Linux字符设备注册函数 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;

}

 

取消模块就是删除原来注册的东西,不做详细介绍。

  • 9
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值