register_chrdev
linux字符设备注册函数 register_chrdev详解
当我们需要注册字符设备的时候,需要module_init()中调用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();
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);
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;
}
1:参数分析
* @major: major device number or 0 for dynamic allocation
主设备号,当用户设置为0时,内核会动态分配一个设备号。
* @baseminor: first of the requested range of minor numbers
次设备号,要在一定范围内从0开始
* @count: the number of minor numbers required
次设备号的范围
* @name: name of this range of devices
设备名称
* @fops: file operations associated with this devices
2:接口代码分析
struct char_device_struct *cd; //字符设备结构体指针,用于检测存储使用。
static struct char_device_struct {
struct char_device_struct *next;
unsigned int major;
unsigned int baseminor;
int minorct;
char name[64];
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
__register_chrdev_region():
检查设备号是否有效,注册设备到全局变量chrdevs[i]中。
内核中有字符设备和块设备表,根据设备类型和主设备号既能找到对应的结构跳转函数。
struct cdev *cdev; 字符型设备,这个是真正的实用的。
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
cdev = cdev_alloc();
分配一个字符设备结构内存大小,返回这个结构,失败返回空。
cdev->owner = fops->owner;
cdev->ops = fops;
kobject_set_name(&cdev->kobj, "%s", name);
设置设备用户,文件操作指针,设备名称。
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
添加设备到系统中 module结构体链表中,使之模块立即生效。此后文件操作,可以正常使用
如果注册失败的话,释放以上的配置。
重点是 cdev_add的理解源代码如下:
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
p->count = count;
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,
struct module *module, kobj_probe_t *probe,
int (*lock)(dev_t, void *), void *data)
{
unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;
unsigned index = MAJOR(dev);
unsigned i;
struct probe *p;
if (n > 255)
n = 255; //检测设备号是否在范围内
p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);
if (p == NULL)
return -ENOMEM;
for (i = 0; i < n; i++, p++) { //设置字符module结构的配置
p->owner = module;
p->get = probe;
p->lock = lock;
p->dev = dev;
p->range = range;
p->data = data;
}
mutex_lock(domain->lock);
for (i = 0, p -= n; i < n; i++, p++, index++) {
struct probe **s = &domain->probes[index % 255];//添加到全局模块中
while (*s && (*s)->range < range)
s = &(*s)->next;
p->next = *s;
*s = p;
}
mutex_unlock(domain->lock);
return 0;
}
取消模块就是删除原来注册的东西,不做详细介绍。
相关阅读
##0x00 背景知识ASLR(Address Space Layout Randomization)在2005年被引入到Linux的内核 kernel 2.6.12 中,当然早在2004年就以pat
菜鸟方案 “/”与swap两个分区就可以应付绝大多数的应用 常用方案 分为3个区 1. 挂载点/;主分区;安装系统和软件;大小为30G;分区格式
可以看到在淘宝上面注册一个淘宝特价版店铺的时候,很多人觉得很麻烦,不知道怎么去入驻,所以下面小编就来给大家说一下注册的过程,看完
打开:cd进入Linux内核根目录后,控制台输入make menuconfig 移动选择框:上下键、左右键。 搜索功能:”/”键。 选择:回车。 打开/关闭某
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,