register_chrdev函数把以前分开的做的申请设备号,cdev_init,cdev_add等操作封装起来,一个函数来完成。
用起来方便,但有局限性,它的次设备号固定是从0开始,设备的个数固定为256个。
如都用这函数来实现设备驱动,那主设备就无法重用,尽管次设备号可用范围还有很大的空间。
如用于实现只有一个同类设备的驱动,只用一个设备号就可以,用这个函数就会多浪费设备号。
如用于实现多于256个同类设备的驱动时,设备号不够用。
register_chrdev函数内部实现过程:
int __register_chrdev(unsigned int major, unsigned int baseminor,
unsigned int count, const char *name,
const struct file_operations *fops)
{
struct char_device_struct *cd;
struct cdev *cdev;
int err = -ENOMEM;
cd = __register_chrdev_region(major, baseminor, count, name); //申请设备号
if (IS_ERR(cd))
return PTR_ERR(cd);
cdev = cdev_alloc(); //动态创建cdev对象并初始化list和kobj成员
if (!cdev)
goto out2;
cdev->owner = fops->owner;
cdev->ops = fops;
kobject_set_name(&cdev->kobj, "%s", name);
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); //增加cdev对象到内核里
if (err)
goto out;
cd->cdev = cdev;
return major ? 0 : cd->major;
out:
kobject_put(&cdev->kobj);
out2:
kfree(__unregister_chrdev_region(cd->major, baseminor, count));
return err;
}
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
测试代码(test.c):
#include
#include
#include
#define MYMA 1234
ssize_t myread(struct file *fl, char __user *buf, size_t len, loff_t *off)
{
printk("in myread ...\n");
return 0;
}
struct file_operations fops = {
.read = myread,
};
static int __init test_init(void)
{
int ret;
ret = register_chrdev(MYMA, "mydev", &fops);
return ret;
}
static void __exit test_exit(void)
{
unregister_chrdev(MYMA, "mydev");
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
编译加载驱动后,只要创建主设备号为1234,次设备号为(0到255之间)的设备文件都可以调用驱动。
如:mknod /dev/mydev c 1234 111