使用udev在/dev/下动态生成设备文件
create_chrdev.c
---------------------------------------------
#include <linux/types.h> //dev_t
#include <linux/cdev.h> //struct cdev
#include <linux/fs.h> //alloc_chrdev_region()
#include <linux/device.h> //class_create()
dev_t devid;
static struct cdev *led_cdev;
static int led_Major = 0;
static int led_Minor = 0;
static struct class *led_class;
static struct file_operations led_fops = {
.owner = THIS_MODULE,
};
static int __init hello_init(void)
{
int err;
//初始化cdev
led_cdev = cdev_alloc();
cdev_init(led_cdev, &led_fops);
led_cdev->owner = THIS_MODULE;
//动态获取主设备号(dev_t devid中包含"主设备号"和"次设备号"信息)
alloc_chrdev_region(&devid, 66, 1, "led");
led_Major = MAJOR(devid);
led_Minor = MINOR(devid);
printk(KERN_INFO "I was assigned major number %d.\n", led_Major);
printk(KERN_INFO "I was assigned minor number %d.\n", led_Minor);
//注册字符设备 (1)
err = cdev_add(led_cdev, devid, 1);
if (err) {
printk(KERN_NOTICE "Error %d adding device\n", err);
return -1;
}
led_class = class_create(THIS_MODULE, "led_class1");
if (IS_ERR(led_class)) {
printk(KERN_INFO "create class error\n");
return -1;
}
class_device_create(led_class, NULL, devid, NULL, "led" "%d", MINOR(devid));
return 0;
}
static void __exit hello_exit(void)
{
unregister_chrdev_region(devid, 1);
cdev_del(led_cdev);
class_device_destroy(led_class, devid);
class_destroy(led_class);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zengxiaolong ");
MODULE_DESCRIPTION("A sample driver");
MODULE_SUPPORTED_DEVICE("testdevice");
(1)cdev_add()执行后将会在/proc/devices文件中看到"252 led",但是在/dev/目录下没有生成相应的设备文件。直到class_device_create()执行后才会在/dev/目录下生成设备文件led66。而class_create()执行后会在/sys/class/目录下生成led_class1目录
Makefile
---------------------------------------------
all: default
obj-m += create_chrdev.o
default:
make -C /home/zxl/soft/kernel/linux-2.6.22 M=`pwd` modules
clean:
make -C /home/zxl/soft/kernel/linux-2.6.22 M=`pwd` clean
Sysfs文件系统与Linux设备模型 sysfs把连接在系统上的设备和总线组织成为一个分级的目录及文件,它们可以由用户空间存取,向用户空间导出内核数据结构以及它们的属性,这其中就包括设备的主次设备号。新的设备文件系统udev的工作过程就依赖于sysfs文件系统的这些功能特点。udev文件系统在用户空间工作,它可以根据sysfs文件系统导出的信息(设备号等),动态建立和删除设备文件,而不再需要使用mknod来手动建立设备文件,也不必为查找设备号(尤其是驱动中动态申请产生的设备号)而头疼。 kobject内核对象提供了基本的对象管理能力,是linux 2.6设备模型的核心结构,每个在内核中注册的kobject对象都对应于sysfs文件系统的一个目录,这可以通过以下函数调用体现: kobject_add()-> kobject_add_varg()->kobject_add_internal()->create_dir()->sysfs_create_dir() (好像已经不存在kobject_register函数了) sysfs文件系统下的所有目录,其最终的建立过程都是通过注册添加kobject到linux设备层次来实现的,举两个例子: 1、class class_register-> __class_register-> kset_register-> kobject_add_internal 2、device device_register-> device_add-> kobject_add 因此,对应于一个设备,在sysfs文件系统下不是一个文件,而是一个目录,目录名字的来源是kobject对象的name域。目录中会有两个文件和若干目录,这两个文件是设备的属性文件。我们可以看看device_add函数的实现,其中有: 912 error = device_create_file(dev, &uevent_attr); 913 if (error) 914 goto attrError; 915 916 if (MAJOR(dev->devt)) { 917 error = device_create_file(dev, &devt_attr); 918 if (error) 919 goto ueventattrError; 其中会在sysfs文件系统对应设备目录下创建两个属性文件(可以看看device_create_file函数的实现,是调用sysfs_create_file),其中有两个参数是两个结构体指针,两个结构体的定义如下: 311 static struct device_attribute uevent_attr = 312 __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
428 static struct device_attribute devt_attr = 429 __ATTR(dev, S_IRUGO, show_dev, NULL); 再看看_ATTR: 48 #define __ATTR(_name,_mode,_show,_store) { \ 49 .attr = {.name = __stringify(_name), .mode = _mode }, \ 50 .show = _show, \ 51 .store = _store, \ 52 } 再看看__stringify: 19 #define __stringify_1(x) #x 20 #define __stringify(x) __stringify_1(x) (真是无底洞呀,到这为止吧!)这两个宏看起来很怪异,有人说这个定义很奇妙,具体奇妙在哪目前我还没体会到,等有机会再补充(留个脚印吧)。简单来说,它们的功能就是x转化为字符串,所以uevent和dev就转化为“uevent”和”dev“了,把它们赋给name,这就是sysfs具体设备目录下的两个文件uevent和dev名字的来源了! 这两个属性文件的内容是怎么等到的呢?sysfs是虚拟文件系统,大家应该知道proc文件系统吧,类似地它们都是在内存中,内容都是动态生成的而不是存储在非易失存储器中。大家应该注意到属性结构体中有两个函数指针show和store,在这里被赋值了 422 static ssize_t show_dev(struct device *dev, struct device_attribute *attr, 423 char *buf) 424 { 425 return print_dev_t(buf, dev->devt); 426 }
|