linux MISC駆動モデル解析


linux MISC        

ledドライバのコードを読むとldd 3に記載されている各種文字デバイス登録関数ではなくmisc_が見つかりましたregister関数、これはledデバイスがヘテロデバイスとしてカーネルに現れていることを示しています.カーネルではmiscヘテロデバイス駆動インタフェースはいくつかの文字デバイスの簡単なパッケージであり、彼らは1つのプライマリデバイス番号を共有し、異なるセカンダリデバイス番号を共有し、open呼び出しを共有し、その彼の操作関数は開いた後にlinuxドライバの方法で再ロードされてマウントされます.
1.主なデータ構造
          misc_list  ,misc   misc_register            , misc_deregister     。         miscdevice。    :
struct miscdevice  {
	int minor;
	const char *name;
	const struct file_operations *fops;
	struct list_head list;
	struct device *parent;
	struct device *this_device;
	const char *nodename;
	mode_t mode;
};
          misc        ,   misc                      ,         name minor fops      。    led        miscdevice   :
static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};
          fops    open  ,       misc_ops   open  。  minor    MISC_DYNAMIC_MINOR,        ,     misc_register     。

2. misc_init関数
    misc               ,        。     misc             。
static int __init misc_init(void)
{
	int err;


#ifdef CONFIG_PROC_FS
	proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
	misc_class = class_create(THIS_MODULE, "misc");
        //udev        
	err = PTR_ERR(misc_class);
	if (IS_ERR(misc_class))
		goto fail_remove;


	err = -EIO;
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) //        
		goto fail_printk;
	misc_class->devnode = misc_devnode;
	return 0;


fail_printk:
	printk("unable to get major %d for misc devices
", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; }
        ,       ,               ,        2.4   register_chrdev。         MISC_MAJOR,     0-255 256   。       misc 。

3. misc_register()関数
    misc_register()   misc.c ,         misc_class      , miscdevice     misc_list   ,     linux         ,     miscdevice   。
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) {  //      
		int i = DYNAMIC_MINORS;
		while (--i >= 0)
			if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
				break;
		if (i<0) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
		misc->minor = i;
	}


	if (misc->minor < DYNAMIC_MINORS)
		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,
					  misc, "%s", misc->name);
        //udev        ,linux      
	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); //   misc_list  
 out:
	mutex_unlock(&misc_mtx);
	return err;
}
        ,        misc_list  ,                ,    。              ,    MKDEV     ,          misc          MISC_MAJOR,    device_create,      。     misc_list   。
      device_create,class_create   :  class_create   misc.c           ,       。           ,   ldd3    ,         class_create       __class_regsiter()          。 device_create       ,              device_register  。      linux      , linux  2.6       ,devfs    ,udev  devfs   。  devfs,udev     。
   struct class *myclass = class_create(THIS_MODULE, “my_device_driver”);
   class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”);
               ,      ,udev daemon     /dev   my_device      。                 。             。

4.まとめ
                 ,               ,          ,            ,    ,        miscdevice   ,  misc_register    。     255     ,                   。    ,mini2440                   , mini2440_buttons,mini2440_adc,mini2440_pwm 。