Chinaunix首页 | 论坛 | 博客
  • 博客访问: 206148
  • 博文数量: 33
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1277
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-03 10:03
个人简介

现于杭州电子科技大学攻读硕士学位

文章分类

全部博文(33)

文章存档

2013年(33)

我的朋友

分类: LINUX

2013-09-07 17:30:05

/*************************************************************************************************************************************/
/* misc.c */

/*
 * linux/drivers/char/misc.c
 *
 * Generic misc open routine by Johan Myreen
 *
 * Based on code from Linus
 *
 * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
 *   changes incorporated into 0.97pl4
 *   by Peter Cervasio () (08SEP92)
 *   See busmouse.c for particulars.
 *
 * Made things a lot mode modular - easy to compile in just one or two
 * of the misc drivers, as they are now completely independent. Linus.
 *
 * Support for loadable modules. 8-Sep-95 Philip Blundell <>
 *
 * Fixed a failing symbol register to free the device registration
 *  Alan Cox <> 21-Jan-96
 *
 * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
 *
 * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
 *
 * Handling of mouse minor numbers for kerneld:
 *  Idea by Jacques Gelinas <>,
 *  adapted by Bjorn Ekwall <>
 *  corrected by Alan Cox <>
 *
 * Changes for kmod (from kerneld):
 * Cyrus Durgin <>
 *
 * Added devfs support. Richard Gooch <>  10-Jan-1998
 */

#include

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

/*
 * Head entry for the doubly linked miscdevice list
 */
static LIST_HEAD(misc_list);
static DEFINE_MUTEX(misc_mtx);

/*
 * Assigned numbers, used for dynamic minors
 */
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static unsigned char misc_minors[DYNAMIC_MINORS / 8];   /* 用于保存已经注册的小于64的次设备号 */

extern int pmu_device_init(void);

#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
{
 mutex_lock(&misc_mtx);
 return seq_list_start(&misc_list, *pos);
}

static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
 return seq_list_next(v, &misc_list, pos);
}

static void misc_seq_stop(struct seq_file *seq, void *v)
{
 mutex_unlock(&misc_mtx);
}

static int misc_seq_show(struct seq_file *seq, void *v)
{
 const struct miscdevice *p = list_entry(v, struct miscdevice, list);

 seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
 return 0;
}


static struct seq_operations misc_seq_ops = {
 .start = misc_seq_start,
 .next  = misc_seq_next,
 .stop  = misc_seq_stop,
 .show  = misc_seq_show,
};

static int misc_seq_open(struct inode *inode, struct file *file)
{
 return seq_open(file, &misc_seq_ops);
}

static const struct file_operations misc_proc_fops = {   /* 混杂设备操作函数,其对应的是/proc目录下的设备文件 */
 .owner  = THIS_MODULE,
 .open    = misc_seq_open,
 .read    = seq_read,
 .llseek  = seq_lseek,
 .release = seq_release,
};
#endif

/* 打开混杂设备函数 */
static int misc_open(struct inode * inode, struct file * file)
{
 int minor = iminor(inode);   /* 获取设备的次设备号 */
 struct miscdevice *c;
 int err = -ENODEV;
 const struct file_operations *old_fops, *new_fops = NULL;
 
 lock_kernel();
 mutex_lock(&misc_mtx);
 
 list_for_each_entry(c, &misc_list, list) {  /* 遍历混杂设备链表,找到次设备相等的那个设备节点 */
  if (c->minor == minor) {
   new_fops = fops_get(c->fops);    /* 获取找到的设备的file_operations结构的操作函数 */
   break;
  }
 }
  
 if (!new_fops) {  /*如果 获取找到的设备的file_operations结构的操作函数没有成功 */
  mutex_unlock(&misc_mtx);
  request_module("char-major-%d-%d", MISC_MAJOR, minor);   /* 以主次设备申请一个模块 */
  mutex_lock(&misc_mtx);

  list_for_each_entry(c, &misc_list, list) {  /* 重新遍历混杂设备链表,找到次设备相等的那个设备节点 */
   if (c->minor == minor) {
    new_fops = fops_get(c->fops);/* 获取找到的设备的file_operations结构的操作函数 */
    break;
   }
  }
  if (!new_fops)  /* 如果还是没有 获取找到的设备的file_operations结构的操作函数,则做出错处理*/
   goto fail;
 }

 err = 0;
 old_fops = file->f_op;  /* 保存设备文件的老的操作函数指针 */
 file->f_op = new_fops;  /* 将找 设备文件的file_operations操作函数集赋值file->f_op ,此后对设备文件进行读写就会操作到对应的设备*/
 if (file->f_op->open) {
  err=file->f_op->open(inode,file);   /* 调用设备驱动程序的open函数 */
  if (err) {
   fops_put(file->f_op);
   file->f_op = fops_get(old_fops);
  }
 }
 fops_put(old_fops);
fail:
 mutex_unlock(&misc_mtx);
 unlock_kernel();
 return err;
}

static struct class *misc_class;

static const struct file_operations misc_fops = {   /* 字符设备操作函数,当用户空间进行系统调用open时,会调用该misc_open函数 */
 .owner  = THIS_MODULE,
 .open  = misc_open,
};


/**
 * misc_register - register a miscellaneous device
 * @misc: device structure
 * 
 * Register a miscellaneous device with the kernel. If the minor
 * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
 * and placed in the minor field of the structure. For other cases
 * the minor number requested is used.
 *
 * The structure passed is linked into the kernel and may not be
 * destroyed until it has been unregistered.
 *
 * A zero is returned on success and a negative errno code for
 * failure.
 */

/* 注册一个混杂设备 */
int misc_register(struct miscdevice * misc)
{
 struct miscdevice *c;
 dev_t dev;
 int err = 0;

 INIT_LIST_HEAD(&misc->list);   /* 初始化设备链表 */

 mutex_lock(&misc_mtx); 
 list_for_each_entry(c, &misc_list, list) {   /* 遍历设备链表,如果发现注册的这个设备的的次设备号在设备链表里已经
                                                                      存在了,则做出错处理(因为在应用程序对设备进行操作的的时候是通过
                                                                      设备的次设备号在设备链表上进行引索的)*/
  if (c->minor == misc->minor) {
   mutex_unlock(&misc_mtx);
   return -EBUSY;
  }
 }

 if (misc->minor == MISC_DYNAMIC_MINOR) {  /* 如果次设备号等于MISC_DYNAMIC_MINOR=255,则说明要为设备动态分配一个此设备号 */
  int i = DYNAMIC_MINORS;  /* i=64 */
  while (--i >= 0)
   if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)    /* 说明有设备号可以分配 */
    break;
  if (i<0) {/* 如果没有找到符合条件misc_minors[i>>3] & (1 << (i&7)))  的i则返回错误*/
   mutex_unlock(&misc_mtx);
   return -EBUSY;
  }
  misc->minor = i;  /* 将找到的这个数(小于64)赋给 misc->minor*/
 }

 if (misc->minor < DYNAMIC_MINORS)   /* 如果次设备号小于64,这说明小于64的次设备号最多可以有8个 */
  misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); /* 则数组 misc_minors以下标为misc->minor >> 3的数组项就等于1 << (misc->minor & 7)*/
 dev = MKDEV(MISC_MAJOR, misc->minor);  /* 获取设备的设备号 */

 misc->this_device = device_create(misc_class, misc->parent, dev, NULL,  /* 创建设备节点,即/dev/ misc->name*/
       "%s", misc->name);
 if (IS_ERR(misc->this_device)) {
  err = PTR_ERR(misc->this_device);
  goto out;
 }

 /*
  * Add it to the front, so that later devices can "override"
  * earlier defaults
  */
 list_add(&misc->list, &misc_list);  /* 将设备加入设备链表 */
 out:
 mutex_unlock(&misc_mtx);
 return err;
}

/**
 * misc_deregister - unregister a miscellaneous device
 * @misc: device to unregister
 *
 * Unregister a miscellaneous device that was previously
 * successfully registered with misc_register(). Success
 * is indicated by a zero return, a negative errno code
 * indicates an error.
 */
/* 注销混杂设备 */
int misc_deregister(struct miscdevice *misc)
{
 int i = misc->minor;   /* 获取设备的次设备号 */

 if (list_empty(&misc->list))  /* 如果设备链表为空,则说明无设备可注销,则做出错处理 */
  return -EINVAL;

 mutex_lock(&misc_mtx);
 list_del(&misc->list);  /* 将设备从设备链表中删除 */
 device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));  /* 销毁设备节点 */
 if (i < DYNAMIC_MINORS && i>0) {
  misc_minors[i>>3] &= ~(1 << (misc->minor & 7));  /* 将数组项中相应的设备号标志位取反 */
 }
 mutex_unlock(&misc_mtx);
 return 0;
}

EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);

/* 混杂设备子系统初始化 */
static int __init misc_init(void)
{
 int err;

#ifdef CONFIG_PROC_FS
 proc_create("misc", 0, NULL, &misc_proc_fops);   /* 在proc文件系统中创建设备文件,文件名为misc即/proc/misc */
#endif
 misc_class = class_create(THIS_MODULE, "misc");   /* 在/sys/class下面创建目录misc即/sys/class/misc*/
 err = PTR_ERR(misc_class);
 if (IS_ERR(misc_class))
  goto fail_remove;

 err = -EIO;
 if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))     /* 注册字符设备 ,主设备号是10,设备文件名为misc*/
  goto fail_printk;
 return 0;

fail_printk:
 printk("unable to get major %d for misc devices\n", MISC_MAJOR);
 class_destroy(misc_class);
fail_remove:
 remove_proc_entry("misc", NULL);
 return err;
}
subsys_initcall(misc_init);   /* 这在系统初始化时被调用 */

阅读(1483) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~