天天看點

Linux中miscdevice混雜裝置驅動分析

定義:字元裝置的一種,它們共享一個主裝置号(10),但次裝置号不同,所有的混雜裝置形成一個連結清單,對裝置通路時核心根據次裝置号查找到相應的miscdevice裝置。

例如:觸摸屏,LED,按鍵,序列槽。

即:為了節約主裝置号,将某些裝置用連結清單的形式連接配接在一起,最後通過查找次裝置區分。這裡用主裝置無法比對出裝置驅動,隻能找到連結清單,再通過次裝置号,才能找到裝置驅動。而之前所學的,一般字元裝置,通過主裝置号,就能找到裝置驅動了。

混雜裝置驅動内置有自動建立裝置節點的代碼,是以編譯好之後,能自動建立裝置節點。

相關的宏,定義在 kernel/include/linux/miscdevice.h

[cpp] 
    ​​view plain​​​
    ​​​copy​​ 
 
  
1. #ifndef _LINUX_MISCDEVICE_H
2. #define _LINUX_MISCDEVICE_H
3. #include
4. #include
5. 
6. 
7. 
8. #define PSMOUSE_MINOR           1
9. #define MS_BUSMOUSE_MINOR       2
10. #define ATIXL_BUSMOUSE_MINOR    3
11. 
12. #define ATARIMOUSE_MINOR        5
13. #define SUN_MOUSE_MINOR         6
14. #define APOLLO_MOUSE_MINOR      7
15. #define PC110PAD_MINOR          9
16. 
17. #define WATCHDOG_MINOR          130
18. #define TEMP_MINOR              131
19. #define RTC_MINOR               135
20. #define EFI_RTC_MINOR           136
21. #define SUN_OPENPROM_MINOR      139
22. #define DMAPI_MINOR             140
23. #define NVRAM_MINOR             144
24. #define SGI_MMTIMER             153
25. #define STORE_QUEUE_MINOR       155
26. #define I2O_MINOR               166
27. #define MICROCODE_MINOR         184
28. #define TUN_MINOR               200
29. #define MWAVE_MINOR             219
30. #define MPT_MINOR               220
31. #define MPT2SAS_MINOR           221
32. #define HPET_MINOR              228
33. #define FUSE_MINOR              229
34. #define KVM_MINOR               232
35. #define BTRFS_MINOR             234
36. #define AUTOFS_MINOR            235
37. #define MISC_DYNAMIC_MINOR      255
38. 
39. struct device;
40. 
41. struct miscdevice  {
42. int minor;  //次裝置号
43. const char *name;  //裝置名
44. const struct file_operations *fops;//檔案操作
45. struct list_head list;  //形成連結清單
46. struct device *parent;
47. struct device *this_device;
48. const char *nodename;
49. mode_t mode;
50. };
51. 
52. extern int misc_register(struct miscdevice * misc);  //混雜裝置注冊
53. extern int misc_deregister(struct miscdevice *misc);  //混雜裝置登出
54. 
55. #define MODULE_ALIAS_MISCDEV(minor)                             \
56. "char-major-" __stringify(MISC_MAJOR)      \
57. "-" __stringify(minor))
58. #endif      

雜項裝置的核心函數的定義位于:kernel/drivers/char/misc.c

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;
         }
     }   //#define MISC_DYNAMIC_MINOR 255
        int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);    //#define DYNAMIC_MINORS 64
         if (i >= DYNAMIC_MINORS) {
             mutex_unlock(&misc_mtx);
             return -EBUSY;
         }
         misc->minor = DYNAMIC_MINORS - i - 1;
         set_bit(i, misc_minors);
     } //獲得裝置号
//#define MISC_MAJOR  10
     misc->this_device = device_create(misc_class, misc->parent, dev, misc, "%s", misc->name);//說明了混雜裝置驅動内部有自動裝置驅動,可自動
 //建立裝置節點    if (IS_ERR(misc->this_device)) {
         int i = DYNAMIC_MINORS - misc->minor - 1;
         if (i < DYNAMIC_MINORS && i >= 0)
             clear_bit(i, misc_minors);
         err = PTR_ERR(misc->this_device);
         goto out;
     }    
     list_add(&misc->list, &misc_list);
  out:
     mutex_unlock(&misc_mtx);
     return err;
 }      
int misc_deregister(struct miscdevice *misc)
 {
     int i = DYNAMIC_MINORS - misc->minor - 1;     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)
         clear_bit(i, misc_minors); 
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);  
 static char *misc_devnode(struct device *dev, mode_t *mode){
     struct miscdevice *c = dev_get_drvdata(dev);     if (mode && c->mode)
         *mode = c->mode;
     if (c->nodename)
         return kstrdup(c->nodename, GFP_KERNEL);
     return NULL;
 }  
 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");    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\n", MISC_MAJOR);
     class_destroy(misc_class);
 fail_remove:
     remove_proc_entry("misc", NULL);
     return err; }
     subsys_initcall(misc_init);      
"kernel/drivers/base/core.c"
 struct device *device_create(struct class *class, struct device *parent,  dev_t devt, void *drvdata, const char *fmt, ...)
 {
     va_list vargs;
     struct device *dev;     va_start(vargs, fmt);
     dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);    va_end(vargs);
     return dev;
 }
 EXPORT_SYMBOL_GPL(device_create); static int __match_devt(struct device *dev, void *data)
 {
     dev_t *devt = data;     return dev->devt == *devt;
 } 
 void device_destroy(struct class *class, dev_t devt)
 {
     struct device *dev;     dev = class_find_device(class, NULL, &devt, __match_devt);
     if (dev) {
         put_device(dev);
         device_unregister(dev);
     }
 }
 EXPORT_SYMBOL_GPL(device_destroy);