申请字符设备
第一种方法:查看系统中哪个设备号属于空闲
cat /proc/dev
我们可以查看字符设备,块设备
int register_chrdev_region(dev_t from,unsigned count, const char *name);
from: 待申请的设备号
count: 待申请的设备号数目(次设备号)
name: 设备名称(出现在/proc/devices)
返回: 成功返回0,失败返回负值
优点:在申请设备号之前,可以提前创建设备节点
缺点:不利于驱动的推广。如果现在驱动使用的主设备号为250,放在别的开发板时,有可能这个主设备已经被别人使用,造成申请设备失败!,我们查看看哪个没有使用,对他进行注册,所以这种方法我们一般不使用
第二张方法:
内核知道我们那些没有使用,所以我们让内核来帮助我们来分配
dev_t dev;
int alloc_chrdev_region(dev_t* dev,unsigned baseminor, unsigned count, constchar *name);
dev: 保存分配到的设备号,如果内核帮你分配好,将分配的设备号保存在dev中。
baseminor: 希望分配的起始次设备号,一般这个参数指定为0
count: 需要分配的设备号数目(主设备号不变,次设备号依次+1)
name:设备名称(出现在/proc/devices)
请求内核动态分配count个设备号,且次设备号baseminor开始
优点:便于驱动的推广。
缺点:在申请设备号之前,无法提前创建设备文件,只有申请完设备号以后才能创建。
同样的,当我们不再使用这些的时候,我们将他归还给操作系统
unregister_chrdev_region(dev_t dev, int count);
dev:设备号
count:设备的个数
open函数的调用
- 应用程序调用open,首先调用C库的open实现,C库的open函数会保存open对应的系统调用号到R7中,然后调用swi/svc触发一个软中断异常
- CPU跳转到内核创建好的异常向量表的入口地址vetor_swi,根据open的系统调用号,在系统调用表中找到自己对应的系统内核实现sys_open
- 调用sys_open内核函数(fs/open.c),内核会在sys_open函数中创建file对象,根据已经找到的cdev对象,从这个对象中的ops中取出硬件操作集合(led_fops,beep_fops),把这个集合赋值给file对象的f_op字段
- sys_open最终执行:
file->f_op->open(inode,file); //如果底层驱动的操作集合有open函数(led_open,beep_open)那么就调用此函数,如果没有,直接返回用户空间。 - 至此open的调用就完毕!
- 如果要对设备进行read,或者write操作:
app:read->软中断->sys_read执行:
file->f_op->read(file, buf, size, &f_pos); //直接调用底层驱动的操作集合的函数led_read,beep_read
字符设备驱动种四个重要的结构体是什么
.3 struct cdev
描述:这个数据结构就是内核用来描述字符设备,类似你用struct people来描述一个人一样!
跟驱动开发相关的重要字段
struct cdev {
const struct file_operations *ops; //给用户提供的操作硬件的方法
dev_t dev; //存放已经申请的设备号
unsigned int count;//设备的个数
};
struct file_operations
描述:提供了操作硬件的方法(一堆的函数指针,这些函数指针最终指向驱动的某些函数),并且这些方法最终会提供给用户去使用。
struct file_operations myfops = {
.open = drv_open,
.read = drv_read,
.write = drv_write
... //需要几个,填充几个
}; //一旦完成这些初始化,最终内核就会使用这个结构
体,供用户去使用。