在前三篇里学习了Linux平台设备和驱动的一些知识后,这篇就说一下驱动程序是怎么自动生成设备文件。
写过Linux驱动的可能都知道,Linux里有一类设备叫做混杂设备,而且还可以发现注册这一类设备后是不用手动去生成设备文件的。好吧,由这类设备的注册函数入手,从而去了解是怎样自动生成设备文件的。看看混杂设备注册函数在/drivers/char/misc.c里的定义:
1 int misc_register(struct miscdevice * misc) 2 { 3 struct miscdevice *c; 4 dev_t dev; 5 int err = 0; 6 7 INIT_LIST_HEAD(&misc->list); 8 9 mutex_lock(&misc_mtx); 10 list_for_each_entry(c, &misc_list, list) { 11 if (c->minor == misc->minor) { 12 mutex_unlock(&misc_mtx); 13 return -EBUSY; 14 } 15 } 16 17 if (misc->minor == MISC_DYNAMIC_MINOR) { 18 int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); 19 if (i >= DYNAMIC_MINORS) { 20 mutex_unlock(&misc_mtx); 21 return -EBUSY; 22 } 23 misc->minor = DYNAMIC_MINORS - i - 1; 24 set_bit(i, misc_minors); 25 } 26 // MISC_MAJOR = 10 27 dev = MKDEV(MISC_MAJOR, misc->minor); 28 29 misc->this_device = device_create(misc_class, misc->parent, dev, 30 misc, "%s", misc->name); 31 if (IS_ERR(misc->this_device)) { 32 int i = DYNAMIC_MINORS - misc->minor - 1; 33 if (i < DYNAMIC_MINORS && i >= 0) 34 clear_bit(i, misc_minors); 35 err = PTR_ERR(misc->this_device); 36 goto out; 37 } 38 39 /* 40 * Add it to the front, so that later devices can "override" 41 * earlier defaults 42 */ 43 list_add(&misc->list, &misc_list); 44 out: 45 mutex_unlock(&misc_mtx); 46 return err; 47 }
第17~25行的作用是分配一个还没用过的次设备号(混杂设备的主设备号都是一样的);第27行,生成一个设备号(由主设备号和次设备号组成)。第29行,自动生成设备文件的“玄机”就在里面,看它在drivers/base/core.c里的定义:
1 struct device *device_create(struct class *class, struct device *parent, 2 dev_t devt, void *drvdata, const char *fmt, ...) 3 { 4 va_list vargs; 5 struct device *dev; 6 7 va_start(vargs, fmt); 8 dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); 9 va_end(vargs); 10 return dev; 11 }
关键看第8行device_create_vargs()的定义:
1 struct device *device_create_vargs(struct class *class, struct device *parent, 2 dev_t devt, void *drvdata, const char *fmt, 3 va_list args) 4 { 5 struct device *dev = NULL; 6 int retval = -ENODEV; 7 8 if (class == NULL || IS_ERR(class)) 9 goto error; 10 11 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 12 if (!dev) { 13 retval = -ENOMEM; 14 goto error; 15 } 16 17 dev->devt = devt; 18 dev->class = class; 19 dev->parent = parent; 20 dev->release = device_create_release; 21 dev_set_drvdata(dev, drvdata); 22 23 retval = kobject_set_name_vargs(&dev->kobj, fmt, args); 24 if (retval) 25 goto error; 26 27 retval = device_register(dev); 28 if (retval) 29 goto error; 30 31 return dev; 32 33 error: 34 put_device(dev); 35 return ERR_PTR(retval); 36 }
第17~21行,很明显,就是设置device变量的一些成员的值;第27行,怎么样,很眼熟是吧,前面已经分析过了,这里就不再累述。
下面总结一下在编写驱动程序时怎么让内核帮我们自动生成设备文件,其实也就是多调用2个函数:
1. class_create()
该函数在include/linux/device.h里定义。
2. 上面所说的device_create()
关键在于把class_create()函数的返回值作为device_create()函数第一个参数的值,其他参数的含义都很好明白。