Linux字符设备注册函数 register_chrdev详解

 

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;

}

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

相关阅读

Linux下关闭ALSR(地址空间随机化)的方法

##0x00 背景知识ASLR(Address Space Layout Randomization)在2005年被引入到Linux的内核 kernel 2.6.12 中,当然早在2004年就以pat

linux分区方案

菜鸟方案 “/”与swap两个分区就可以应付绝大多数的应用 常用方案 分为3个区 1. 挂载点/;主分区;安装系统和软件;大小为30G;分区格式

如何注册淘宝特价版店铺?如何入驻?

可以看到在淘宝上面注册一个淘宝特价版店铺的时候,很多人觉得很麻烦,不知道怎么去入驻,所以下面小编就来给大家说一下注册的过程,看完

Linux内核配置工具-menuconfig用法

打开:cd进入Linux内核根目录后,控制台输入make menuconfig 移动选择框:上下键、左右键。 搜索功能:”/”键。 选择:回车。 打开/关闭某

Delphi2010及注册码下载地址

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,

发表评论