static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
///
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;
}
/
register_chrdev函数把以前分开的做的申请设备号,cdev_init, cdev_add等操作封装起来,一个函数来完成.
用起来方便 ,但有局限性。它的次设备号固定是从0开始, 设备的个数固定为256个.
如都用这函数来实现设备驱动,那主设备就无法重用,尽管次设备号可用范围还有很大的空间.
如用于实现只有一个同类设备的驱动,只用一个设备号就可以,用这个函数就会多浪费设备号.
如用于实现多于256个同类设备的驱动时,设备号不够用.
这个函数其实常用于内核里的中间层(把某类设备驱动必用功能封装成一种简化的可共用的接口).
测试代码, test.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#define MYMA 4095
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");
//编译加载驱动后,只要创建主设备号为4095, 次设备号为(0--255之间)的设备文件都可以调用驱动