很多学习Linux编程的新人都会被字符设备注册搞糊涂了,我刚开始也一样糊里糊涂的,看到网上例程有各种版本,就是调用module_init时传递的实参,先记为xxx_init()。大家可能还会看到杂项设备驱动misc_register、平台设备驱动platform_device_register。但是作为Linux编程的初级者,建议先不着急去学习复杂的注册方式。现在我先贴出一份比较标准的设备注册程序
1.定义全局变量
#define DEVICE_NAME "Tounie-fasync"
int major = 0; //定义主设备号
static struct class * fasync_cls; //定义一个类指针
struct cdev fasync_cdev; //定义一个设备结构体
设备注册函数
static int xxx_init(void)
{
int result,err;
dev_t fasyncn = MKDEV(major, 0); //根据主设备号获取设备号
if(major) //判断是静态注册还是动态注册
result = register_chrdev_region(fasyncn, 1, DEVICE_NAME); //静态注册设备号,即自己定义主设备号
esle
{
result = alloc_chrdev_region(&fasyncn, 0, 1, DEVICE_NAME); //动态注册设备号,即开始将主设备号初始化为0
major = MAJOR(fasyncn); //通过设备号获取主设备号
}
if(result) //注册设备号失败,如果注册设备号成功result为0
{
printk("fasync register failure!\n");
unregister_chrdev_region(fasyncn, 1);
return result;
}
/* 初始化cdev */
cdev_init(&fasync_cdev, &fasync_fops); //将设备结构体与字符设备操作函数关联,实际上就是将fasync_fops赋给fasync_cdev的成员
/* 注册cdev */
err = cdev_add(&fasync_cdev, fasyncn, 1); //向内核添加一个字符设备结构体
if(err) //向内核添加字符设备结构体失败
{
printk("Error %d adding fasync!\n",err);
unregister_chrdev_region(fasyncn, 1);
return err;
}
printk("adding cdev successed!\n");
/* 以下程序可以不要,如果不要需要在我们加载模块之后手动创建设备节点,所以最好将这些工作全部在驱动程序中实现 */
/* 自动创建设别节点 */
/* 创建设备类 */
fasync_cls = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(fasync_cls))
{
printk("Err: failed in Tounie-fasync.\n");
return -1;
}
/* 创建设备节点 */
device_create(fasync_cls, NULL, fasyncn, NULL, DEVICE_NAME);
printk(DEVICE_NAME" initialized!\n");
return 0;
}
/* 字符设备驱动注册程序到此完毕 */
你们可能会发现有些论坛贴出的程序没那么麻烦,人家一般就三个步骤:
1.register_chrdev(LED_MAJOR, DEVICE_NAME, &Tounie_leds_fops); //注册字符设备
2.led_class = class_create(THIS_MODULE,DEVICE_NAME); //注册字符设备类
3.device_create(led_class,NULL,MKDEV(LED_MAJOR, 0),NULL,DEVICE_NAME); //创建设备类
以上方法也可以实现字符设备驱动的注册,register_chrdev函数是2.6的内核以前的注册方法,虽然现在一些版本还兼容这些方法,但是在将来这些方法即将被淘汰,所以我们还是学习新内核的注册方法比较好。
2.6版本以前的register_chrdev相当于register_chrdev_region、cdev_init和cdev_add三个函数的功能