linux驱动---字符设备的注册register_chrdev说起
首先我们在注册函数里面调用了register_chrdev(MEM_MAJOR,"mem",&memory_fops),向内核注册了一个字符设备。
第一个参数是主设备号,0代表动态分配,这里的MEM_MAJOR是1。第二个参数是设备的名字,第三个参数是文件操作指针。
每个设备文件对应有两个设备号:一个是主设备号,标识该设备的种类,也标识了该设备所使用的驱动程序;另一个是次设备号,标识使用同一设备驱动程序的不同硬件设备。设备文件的主设备号必须与设备驱动程序在登录该设备时申请的主设备号一致,否则用户进程将无法访问到设备驱动程序。
一般说来,PCI卡通常都属于字符设备
完成注册后,在/proc/devices中的第一个字符设备我们就看到了:1 mem。
1.前面提到了注册,那这个字符设备到底注册到哪里去了呢?这是要弄明白的第一个问题。
其实是注册到一个存放字符设备的链表中了:
fs/char_dev.c
- 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];
这里的CHRDEV_MAJOR_HASH_SIZE的大小是255,也就是这里最多能够存放的主设备号最多有255个。
这里还是一点需要注意的是这里分配的是一个指针数组。
- cd->next = *cp;
- *cp = cd;
首先*cp代表的是当前相同的主设备号中最后面的一个,当然这这里的*cp是指向NULL的,然后把*cp更新为cd。
可以注意到这里好像并没有struct cdev什么事情,下面就对其进行初始化。
2.cdev_add第二个任务,add a char device to the system,make it live immediately
先介绍两个遇到的结构体:
include/linux/cdev.h
- struct cdev {
- struct kobject kobj;
- struct module *owner;
- const struct file_operations *ops;
- struct list_head list;
- dev_t dev;
- unsigned int count;
- };
可进行的操作有:
- void cdev_init(struct cdev *, const struct file_operations *);
- struct cdev *cdev_alloc(void);
- void cdev_put(struct cdev *p);
- int cdev_add(struct cdev *, dev_t, unsigned);
- void cdev_del(struct cdev *);
- void cd_forget(struct inode *);
在结构体cdev里出现了另外一个极其重要的结构体struct kobject,include/linux/kobject.h
- struct kobject {
- const char *name;
- struct list_head entry;
- struct kobject *parent;
- struct kset *kset;
- struct kobj_type *ktype;
- struct sysfs_dirent *sd;
- struct kref kref;
- unsigned int state_initialized:1;
- unsigned int state_in_sysfs:1;
- unsigned int state_add_uevent_sent:1;
- unsigned int state_remove_uevent_sent:1;
- unsigned int uevent_suppress:1;
- };
主要的操作有:
- extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
- extern void kobject_del(struct kobject *kobj);
- extern struct kobject *kobject_get(struct kobject *kobj);
- extern void kobject_put(struct kobject *kobj);extern void kobject_put(struct kobject *kobj);
cdev_add里面只调用了一个函数:kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
cdev_map是fs/char_dev.h里定义的一个结构体变量,而kobj_map的作用就是初始化它。
- static struct kobj_map *cdev_map;
- 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;
- };
kobj_map:
内核中所有都字符设备都会记录在一个 kobj_map 结构的 cdev_map 变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。kobj_map() 函数就是用来把字符设备编号和 cdev 结构变量一起保存到 cdev_map 这个散列表里。当后续要打开一个字符设备文件时,通过调用 kobj_lookup() 函数,根据设备编号就可以找到 cdev 结构变量,从而取出其中的 ops 字段。
- 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;
- }
- 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驱动---字符设备的注册register_chrdev说起的更多相关文章
- liunx驱动之字符设备的注册
上一篇文章学习了如何编写linux驱动,通过能否正常加载模块进行验证是否成功,有做过liunx应用开发的小伙伴都知道驱动会在'/dev'目录下以文件的形式展现出来,所以只是能加载驱动模块不能算是完成驱 ...
- linux kernel 字符设备详解
有关Linux kernel 字符设备分析: 参考:http://blog.jobbole.com/86531/ 一.linux kernel 将设备分为3大类,字符设备,块设备,网络设备. 字符设备 ...
- 【驱动】linux设备驱动·字符设备驱动开发
Preface 前面对linux设备驱动的相应知识点进行了总结,现在进入实践阶段! <linux设备驱动入门篇>:http://infohacker.blog.51cto.com/6751 ...
- Linux高级字符设备驱动
转载:http://www.linuxidc.com/Linux/2012-05/60469p4.htm 1.什么是Poll方法,功能是什么? 2.Select系统调用(功能) Select ...
- linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】
转自:http://my.oschina.net/u/274829/blog/285014 1,ioctl介绍 ioctl控制设备读写数据以及关闭等. 用户空间函数原型:int ioctl(int f ...
- Linux高级字符设备驱动 poll方法(select多路监控原理与实现)
1.什么是Poll方法,功能是什么? 2.Select系统调用(功能) Select系统调用用于多路监控,当没有一个文件满足要求时,select将阻塞调用进程. int selec ...
- linux内核cdev_init系列函数(字符设备的注册)
内核中每个字符设备都对应一个 cdev 结构的变量,下面是它的定义: linux-2.6.22/include/linux/cdev.h struct cdev { struct kobject ...
- linux学习--字符设备驱动
目录 1.字符设备驱动抽象结构 2.设备号及设备节点 2.1 设备号分配与管理 2.2 设备节点的生成 3.打开设备文件 linux驱动有基本的接口进行注册和卸载,这里不再做详细说明,本文主要关注li ...
- Linux LED字符设备驱动
// 申请IO资源 int gpio_request(unsigned gpio, const char *label); // 释放IO资源 void gpio_free(unsigned gpio ...
随机推荐
- 深度优化LNMP之MySQL
MySQL数据库优化框架体系 1.硬件层面优化 2.操作系统层面优化 3.MySQL数据库层面优化 4.MySQL安全优化 5.网站集群架构上的优化 6.MySQL流程.制度控制优化 1 硬件层面优化 ...
- 基于JAVA实现的排序算法总结
常用的排序方法有:冒泡排序.快速排序.选择排序.插入排序.归并排序,除此之外,还有基数排序.鸡尾酒排序.桶排序.鸽巢排序.希尔排序等,这里着重介绍下前半段列举的几种常见方法的实现. 1. 冒泡排序法: ...
- python3操作pymsql模块
pymysql是python中操作mysql的模块. 1.pymysql模块的安装 pip3 install pymysql 也可以使用pycharm这个IDE工具来安装pymysql这个模块. 2. ...
- 前端-css
页面css排版不错乱: 1.最外层div中 定义width=980px,当页面缩小以后,就在下面出现滚动条 2.使用 media 技术,bootstrp技术.页面自使用 一.css选择器 选择器 样式 ...
- BZOJ 3771: Triple [快速傅里叶变换 生成函数 容斥原理]
题意:n个物品,可以用1/2/3个不同的物品组成不同的价值,求每种价值有多少种方案(顺序不同算一种) [生成函数]: 构造这么一个多项式函数g(x),使得n次项系数为a[n]. 普通型生成函数用于解决 ...
- Java生产者消费者
简单的生产者.消费者,一个数据缓冲区,一个或者多个生产者把数据放入缓冲区.一个或者多个消费者将数据从缓冲区取走.该缓冲区是一个数据共享,必须进行同步处理,如果缓冲区是满的,生产者将不能放数据,同理如果 ...
- nginx的负载均衡集群测试
分别在3台机子安装nginx和启动nginx服务. dir: 192.168.0.7 另外2台服务器为 192.168.0.5 ,192.168.0.6 在dir 192.168.0.7 上增加配置 ...
- Linux下的压力测试工具:ab、http_load、webbench、siege
一.ab 1.1 介绍 ab是apache自带的一款功能强大的测试工具. 安装了apache一般就自带了. 1.2 下载 同apache. 1.3 安装 同apache. 1.4 安装结果 ...
- WPF&Winform版本地图引擎
最近几年一直从事地图方面的工作,自主研发了WPF和Winform两个版本瓦片地图引擎.轻量级.不依赖第三库.先上一张图片展示一下吧! 产品包括服务端和客户端两部份: 1.服务端主要地图图层配制和空间计 ...
- es6变量声明和解构赋值
/*声明: * 本文内容多为学习借鉴性内容,大部分非原创 * 特别感谢阮一峰的 ECMAScript6 入门,推荐大家学习 */ 一.es5变量声明的不足 1.变量提升和函数声明提升 es5的代码加载 ...