刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod [OPTION]... NAME TYPE [MAJOR MINOR]命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev(mdev)
内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同,而且里面的参数设置也有一些变化。
struct class和class_create(…) 定义在/include/linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。
在3.2.0内核版本中,struct class定义在头文件include/linux/device.h中:
- struct class {
- const char *name;
- struct module *owner;
- struct class_attribute *class_attrs;
- struct device_attribute *dev_attrs;
- struct bin_attribute *dev_bin_attrs;
- struct kobject *dev_kobj;
- int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
- char *(*devnode)(struct device *dev, mode_t *mode);
- void (*class_release)(struct class *class);
- void (*dev_release)(struct device *dev);
- int (*suspend)(struct device *dev, pm_message_t state);
- int (*resume)(struct device *dev);
- const struct kobj_ns_type_operations *ns_type;
- const void *(*namespace)(struct device *dev);
- const struct dev_pm_ops *pm;
- struct subsys_private *p;
- };
- #define class_create(owner, name) \
- ({ \
- static struct lock_class_key __key; \
- __class_create(owner, name, &__key); \
- })
- 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;
- }
- 626 int scull_init_module(void)
- 627 {
- 628 +-- 7 lines: int result, i;
- ------------------------------------------------------------------------------
- 635 if (scull_major) {
- 636 dev = MKDEV(scull_major, scull_minor);
- 637 result = register_chrdev_region(dev, scull_nr_devs, "scull");
- 638 +-- 8 lines: } else {
- ------------------------------------------------------------------------------
- 646 }
- 647
- 648 +-- 4 lines: allocate the devices -- we can't have them static, as the number
- ------------------------------------------------------------------------------
- 652 scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
- 653 +-- 6 lines: if (!scull_devices) {
- ------------------------------------------------------------------------------
- 659 //create the device class
- 660 my_class = class_create(THIS_MODULE,"scull"); //类名为 scull
- 661 if(IS_ERR(my_class))
- 662 {
- 663 printk("Err: failed in creating class.\n");
- 664 return -1;
- 665 }
- 605 static void scull_setup_cdev(struct scull_dev *dev, int index)
- 606 {
- 607 int err, devno = MKDEV(scull_major, scull_minor + index);
- 608
- 609 cdev_init(&dev->cdev, &scull_fops);
- 610 dev->cdev.owner = THIS_MODULE;
- 611 dev->cdev.ops = &scull_fops;
- 612 err = cdev_add (&dev->cdev, devno, 1);
- 613 /* Fail gracefully if need be */
- 614 if (err)
- 615 printk(KERN_NOTICE "Error %d adding scull%d", err, index);
- 616 //create the device file
- 617 int result = device_create(my_class,NULL,devno,NULL,"scull%d",index); //设备名为scull[0~3]
- 618 if (result<0)
- 619 {
- 620 printk (KERN_WARNING "hello: can't get major number %d\n", scull_major);
- 621 return result;
- 622 }
- 623 }
- 591 void scull_cleanup_module(void)
- 592 {
- 593 int i;
- 594 dev_t devno = MKDEV(scull_major, scull_minor);
- 595
- 596 /* Get rid of our char dev entries */
- 597 if (scull_devices) {
- 598 for (i = 0; i < scull_nr_devs; i++) {
- 599 scull_trim(scull_devices + i);
- 600 cdev_del(&scull_devices[i].cdev);
- 601 device_destroy(my_class,MKDEV(scull_major, scull_minor+i));
- 602 }
- 603 kfree(scull_devices);
- 604 }
- 605
- 606 #ifdef SCULL_DEBUG /* use proc only if debugging */
- 607 scull_remove_proc();
- 608 #endif
- 609
- 610 /* cleanup_module is never called if registering failed */
- 611 unregister_chrdev_region(devno, scull_nr_devs);
- 612 class_destroy(my_class);
- 613
- 614 /* and call the cleanup functions for friend devices */
- 615 scull_p_cleanup();
- 616 scull_access_cleanup();
- 617
- 618 }