杂项设备(misc device)
杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include/linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。
也就是说,misc设备其实也就是特殊的字符设备。
字符设备(char device)
使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已验证)。如果模块使用该方式注册并且 LED_MAJOR为0(自动分配主设备号 ),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如设备leds,如果加载该模块时分配的主设备号和次设备号为253和0,则建立节点:mknod leds c 253 0。使用register_chrdev (LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都要手动建立节点 ,否则在应用程序无法打开该设备。
mise device在linux内核源码中的定义如下:
- 02.#define _LINUX_MISCDEVICE_H
- 03.#include <linux/module.h>
- 04.#include <linux/major.h>
- 05.
- 06.#define PSMOUSE_MINOR 1
- 07.#define MS_BUSMOUSE_MINOR 2
- 08.#define ATIXL_BUSMOUSE_MINOR 3
- 09./*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */
- 10.#define ATARIMOUSE_MINOR 5
- 11.#define SUN_MOUSE_MINOR 6
- 12.#define APOLLO_MOUSE_MINOR 7
- 13.#define PC110PAD_MINOR 9
- 14./*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */
- 15.#define WATCHDOG_MINOR 130 /* Watchdog timer */
- 16.#define TEMP_MINOR 131 /* Temperature Sensor */
- 17.#define RTC_MINOR 135
- 18.#define EFI_RTC_MINOR 136 /* EFI Time services */
- 19.#define SUN_OPENPROM_MINOR 139
- 20.#define DMAPI_MINOR 140 /* DMAPI */
- 21.#define NVRAM_MINOR 144
- 22.#define SGI_MMTIMER 153
- 23.#define STORE_QUEUE_MINOR 155
- 24.#define I2O_MINOR 166
- 25.#define MICROCODE_MINOR 184
- 26.#define TUN_MINOR 200
- 27.#define MWAVE_MINOR 219 /* ACP/Mwave Modem */
- 28.#define MPT_MINOR 220
- 29.#define HPET_MINOR 228
- 30.#define FUSE_MINOR 229
- 31.#define KVM_MINOR 232
- 32.#define MISC_DYNAMIC_MINOR 255
- 33.
- 34.struct device;
- 35.
- 36.struct miscdevice {
- 37. int minor;
- 38. const char *name;
- 39. const struct file_operations *fops;
- 40. struct list_head list;
- 41. struct device *parent;
- 42. struct device *this_device;
- 43.};
- 44.
- 45.extern int misc_register(struct miscdevice * misc);
- 46.extern int misc_deregister(struct miscdevice *misc);
- 47.
- 48.#define MODULE_ALIAS_MISCDEV(minor) /
- 49. MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) /
- 50. "-" __stringify(minor))
- 51.#endif
在Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述)。miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同。 所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。 在内核中用struct miscdevice表示miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。miscdevice的API实现在drivers/char/misc.c中。
下边是描述这个设备的结构体:
1.struct miscdevice {
2. int minor; //次设备号
3. const char *name; //设备的名称
4. const struct file_operations *fops; //文件操作
5. struct list_head list; //misc_list的链表头
6. struct device *parent; //父设备(Linux设备模型中的东东了,哈哈)
7. struct device *this_device; //当前设备,是device_create的返回值,下边会看到
8.};
然后来看看misc子系统的初始化函数:
1.static int __init misc_init(void)
2.{
3. int err;
4.
5.#ifdef CONFIG_PROC_FS
6. /*创建一个proc入口项*/
7. proc_create("misc", 0, NULL, &misc_proc_fops);
8.#endif
9. /*在/sys/class/目录下创建一个名为misc的类*/
10. misc_class = class_create(THIS_MODULE, "misc");
11. err = PTR_ERR(misc_class);
12. if (IS_ERR(misc_class))
13. goto fail_remove;
14.
15. err = -EIO;
16. /*注册设备,其中设备的主设备号为MISC_MAJOR,为10。设备名为misc,misc_fops是操作函数的集合*/
17. if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
18. goto fail_printk;
19. return 0;
20.
21.fail_printk:
22. printk("unable to get major %d for misc devices/n", MISC_MAJOR);
23. class_destroy(misc_class);
24.fail_remove:
25. remove_proc_entry("misc", NULL);
26. return err;
27.}
28./*misc作为一个子系统被注册到linux内核中*/
29.subsys_initcall(misc_init);
下边是register_chrdev函数的实现:
1.int register_chrdev(unsigned int major, const char *name,
2. const struct file_operations *fops)
3.{
4. struct char_device_struct *cd;
5. struct cdev *cdev;
6. char *s;
7. int err = -ENOMEM;
8. /*主设备号是10,次设备号为从0开始,分配256个设备*/
9. cd = __register_chrdev_region(major, 0, 256, name);
10. if (IS_ERR(cd))
11. return PTR_ERR(cd);
12. /*分配字符设备*/
13. cdev = cdev_alloc();
14. if (!cdev)
15. goto out2;
16.
17. cdev->owner = fops->owner;
18. cdev->ops = fops;
19. /*Linux设备模型中的,设置kobject的名字*/
20. kobject_set_name(&cdev->kobj, "%s", name);
21. for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
22. *s = '!';
23. /*把这个字符设备注册到系统中*/
24. err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
25. if (err)
26. goto out;
27.
28. cd->cdev = cdev;
29.
30. return major ? 0 : cd->major;
31.out:
32. kobject_put(&cdev->kobj);
33.out2:
34. kfree(__unregister_chrdev_region(cd->major, 0, 256));
35. return err;
36.}
本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:http://www.linuxidc.com/Linux/2012-05/60856.htm