【第22期】观点:IT 行业加班,到底有没有价值?

【Linux设备驱动】字符设备驱动

原创 2016年05月31日 16:53:10

★关于设备号

◇什么是设备号?它有什么作用?

设备号是一个整形数字,它起到连接设备文件与设备驱动的作用。

它具体是怎样进行连接的

在内核中,字符设备被保存在一个kobj_map结构的cdev_map变量中。通过kobj_map函数将设备号(主次设备号)与字符设备结构体cdev保存到cdev_map中。这个过程实现在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);
}
在cdev_add()函数中最后一行调用的kobj_map()函数实现了上述过程,现在来看一看这个函数代码:

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++) {
		p->owner = module;
		p->get = probe;
		p->lock = lock;
		p->dev = dev;//设备号存放位置
		p->range = range;
		p->data = data;//cdev结构体存放位置
	}
	mutex_lock(domain->lock);
	for (i = 0, p -= n; i < n; i++, p++, index++) {//s是存放cdev_map结构体中probes[index%255]的地址
		struct probe **s = &domain->probes[index % 255];//主设备号为index的驱动程序
		while (*s && (*s)->range < range)//将主设备号相同的设备放到一个链表中
			s = &(*s)->next;
		p->next = *s;
		*s = p;
	}
	mutex_unlock(domain->lock);
	return 0;
}
其中有一些代码已经加了注释。这里最难理解的地方就是将主设备号相同的字符设备放到同一个链表的这几行代码。

mutex_lock(domain->lock);
	for (i = 0, p -= n; i < n; i++, p++, index++) {//s是存放cdev_map结构体中probes[index%255]的地址
		struct probe **s = &domain->probes[index % 255];//主设备号为index的驱动程序
		while (*s && (*s)->range < range)//将主设备号相同的设备放到一个链表中
			s = &(*s)->next;
		p->next = *s;
		*s = p;
	}
	mutex_unlock(domain->lock);
其中domain在程序中便是cdev_map,这里将cdev_map锁住,防止多进程对cdev_map操作。
struct probe **s = &domain->probes[index % 255]
就是确定主设备号为index的驱动程序。

struct kobj_map {
	struct probe {
		struct probe *next;
		dev_t dev;
		unsigned long range;
		struct module *owner;
		kobj_probe_t *get;
		int (*lock)(dev_t, void *);
		void *data;
	} *probes[255];
	struct mutex *lock;
};
在这个结构体中struct probe *probes[255];这个结构体指针数组就是用来存放主设备号字符驱动的地址的,其中主设备号为0~254
其中这255个数组成员都会指向一个struct probe的结构体,而这个结构体代表的就是主设备号不同的字符设备驱动。
while (*s && (*s)->range < range)//将主设备号相同的设备放到一个链表中
			s = &(*s)->next;
		p->next = *s;
		*s = p;
这段代码就是将之前申请的p指针指向的struct probe结构体加载到主设备号相同的链表中去。

kobj_map()这个函数主要的作用将加载到内核的字符设备cdev与设备号dev存入申请的struct probe结构体p中;然后将p指针指向的struct probe结构体加载到同为主设备号下的一个链表中。这样当打开一个字符设备文件时,就可以通过设备号找到相应的字符设备,并且调用它的file_operations结构体中的函数。

◇申请设备号的方式有两种:静态申请和动态申请。

 所谓静态申请就是直接指定主设备号,然后使用函数

int register_chrdev_region(dev_t from, unsigned count, const char *name)

申请。动态申请则不指定设备号,

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)

让系统自动分配设备号使用。设备号可以分为主设备号与次设备号。可以通过下面的宏实现:

MAJOR(dev_t dev)
MINJOR(dev_t dev)

★申请注册设备

linux系统中使用cdev结构来表示一个字符设备,注册一个字符设备步骤:
◇申请设备号
◇分配并初始化一个cdev结构体
分配并初始化一个cdev结构体有两种方式:cdev_alloc()、cdev_init()
cdev_alloc()用于动态申请一个cdev结构体
cdev_init()用于初始化cdev成员,建立cdev与file_operations之间的联系
◇将此结构体加入内核中
cdev_add(struct cdev*p,int count)将此结构体加入到内核中

★注销设备

首先注销设备号,
unregister_chrdev_region(xxx_dev_no,1)
然后注销设备
cdev_del(&xxx_dev.cdev)

★Linux字符设备驱动的组成

◇字符设备驱动模块加载与卸载函数
◇字符设备驱动的file_operations结构体中成员函数
版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

Linux字符设备驱动详解

刚开始看Linux字符设备驱动,感觉这篇文章写的真不错!!http://blog.jobbole.com/86531/ 一、linux系统将设备分为3类:字符设备、块设备...

Linux字符设备驱动程序编写基本流程

Linux字符设备驱动程序编写基本流程 Linux device driver 的概念   系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文...

程序员升职加薪指南!还缺一个“证”!

CSDN出品,立即查看!

Linux 字符设备驱动

字符设备驱动的结构在Linux内核中使用cdev结构体描述一个字符设备:// include/linux/cdev.h struct cdev { struct kobject kobj; ...

深入浅出 Linux字符设备驱动程序解析

深入浅出 Linux字符设备驱动程序解析 Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得linux的设备操作犹如文件一般。在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open、close、read、write ...

学习linux字符设备驱动心得

一、主设备号和此设备号 主设备号表示设备对应的驱动程序;次设备号由内核使用,用于正确确定设备文件所指的设备。 内核用dev_t类型()来保存设备编号,dev_t是一个32位的数,12位表示主设备号...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)