之前【Linux设备驱动】最简单的 字符设备驱动编写一文已经对最简单的字符设备驱动编写做了一个简答的叙述,但手动创建设备节点,还是差那么点意思.
Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev
目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev
。
疑问:什么是udev?
创建或删除类
class_create()和class_destroy()
1.class_create
是类创建函数,它本身是一个宏,一共有两个参数:
- 参数
owner
一般为THIS_MODULE
- 参数
name
是类名字
返回值:指向结构体class
的指针,也就是创建的类。
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define class_create(owner, name) \
({ \
static struct lock_class_key __key; \
__class_create(owner, name, &__key); \
})
//__class_create函数原型是
/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
* @name: pointer to a string for the name of this class.
* @key: the lock_class_key for this class; used by mutex lock debugging
*
* This is used to create a struct class pointer that can then be used
* in calls to device_create().
*
* Returns &struct class pointer on success, or ERR_PTR() on error.
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
*/
struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key);
2.class_destroy()是卸载驱动程序的时候要删除类
void class_destroy(struct class *class);
创建删除设备
device_create()和device_destroy()
在创建好类之后还不能实现自动创建设备节点,还需要在类下创建设备
struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
//class:给哪个类创建设备
//parent:父设备,一般为NULL
//devt:设备号
//drvdata:设备可能会使用到的数据
//fmt:设备名字
同样的,卸载驱动的时候需要删除掉创建的设备,设备删除函数为device_destroy
,函数原型如下:
void device_destroy(struct class *class, dev_t devt)
参照【Linux设备驱动】最简单的 字符设备驱动编写代码,优化结果如下:
/*以上代码略*/
/*******************************************/
struct class *char_class;
struct device *char_device;
static __init int char_init(void)
{
int ret = 0;
ret = alloc_chrdev_region(&ndev, 0, 1, "chr_dev");//动态分配设备号
if(ret < 0){
printk("alloc_chrdev_region failed!\n");
return ret;
}
printk("init():major = %d, minor = %d\n", MAJOR(ndev), MINOR(ndev));//打印主设备号和次设备号
chr_dev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
if(NULL == chr_dev){
printk("kzalloc cdev failed!\n");
goto err_alloc_cdev;
}
cdev_init(chr_dev, &chr_ops);//初始化字符设备对象,[加入系统前必须初始化]
ret = cdev_add(chr_dev, ndev, 1);//将字符设备对象插入chr_dev注册进系统
if(ret < 0){
printk("cdev_add error!\n");
goto err_cdev_add;//注册失败记得要销毁刚才分配的设备号
}
char_class = class_create(THIS_MODULE,"chr_dev")//创建类
if(NULL == char_class){
printk("char class create failed!\n");
goto err_class_create;
}
char_device = device_create(char_class, NULL, ndev, NULL, "chr_dev");
if(NULL == char_device){
printk("char device create failed!\n");
goto err_device_create;
}
printk("create char driver success!\n");
return 0;
err_device_create:
class_destroy(char_class);
err_class_create:
cdev_del(chr_dev);
err_cdev_add:
kfree(chr_dev);
err_alloc_cdev:
unregister_chrdev_region(ndev, 1);
printk("create char driver failed!\n");
return -1;
}
static __exit void char_exit(void)
{
device_destroy(char_class, ndev);//删除设备
class_destroy(char_class);//删除类
unregister_chrdev_region(ndev, 1);//释放分配的设备号
cdev_del(chr_dev);//将字符设备对象chr_dev从系统中注销
kfree(chr_dev);
printk("exit char driver success!\n");
}
module_init(char_init);
module_exit(char_exit);
MODULE_AUTHOR("zywang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("char driver new demo");