本文共 3350 字,大约阅读时间需要 11 分钟。
linux系统从千千万万设备中提取它们的共性,将这些设备分成3大类:字符设备,块设备,网络设备。
字符设备是前面提到的这三类设备中最常见的设备,比如生活中大家常见的键盘、鼠标、触摸屏等都属于字符设备。所以掌握字符设备驱动框架是每个驱动程序员所必须的。u-boot 启动内核
内核 启动应用程序 应用 读写文件、获取键值用点灯程序为例
应用程序,直接调用open read write 来调用驱动中的led_open、led_read、led_write 字符驱动架构 1.首选上层应用程序调用open函数打开/dev目录下的一个文件 xxx(这个文件就是“设备文件”)2.open()是库里面的函数,所以库里面的一部分代码会被调用
3.这时候库里面会执行异常指令,执行这些异常指令最后导致的结果就是产生“系统调用”进入内核,这个时候从用户空间进入了内核空间
** 4、进入内核后,内核会接受到这个异常并开始处理,处理的结果是找到对应的驱动程序** 5、找到对应的驱动后,驱动程序中的xxx_open()函数就会被调用。因为驱动程序是在内核里面执行的,它的运行权限就比较大,所以在驱动的open()函数就可以对硬件设备进行操作了。根据上面的5个步骤,最终open()函数和xxx_open()函数对应起来。
上述是open()函数调用的过程,open一个文件之后,紧接着就会调用read() write() close()等函数,他们的调用过程和open()函数是一样的。1.C库是怎么进入内核呢?open,read,write实现的实质是什么?
执行swi val
(汇编指令),引发一个异常,相当于中断一样。当发生这个异常的时候,就会进入内核的异常处理函数里面。
设备文件:从文字上看就是设备的文件,这类文件就是专门给硬件设备服务的文件,而且这类文件都存在/dev
目录下,每当我们向内核中加一个设备驱动程序,这时候就会在相应的/dev
目录下生成相应的设备文件。总结起来:设备文件就是跟驱动程序对应起来的,是上层应用访问驱动的接口。下面我们就来看一下这个设备文件的属性:
访问权限之前的字母是b或c,分别表示块设备和字符设备。
设备文件没有文件长度,而增加了另外的两个值,分别是主设备号和从设备号。二者共同形成一个唯一的号码,内核可由此查找对应的设备驱动程序。
之所以给设备文件分配名称,是因为用户更容易记忆符号名而不是数字,但名称无法表示设备文件的实际功能,这主要是通过主从设备号表示一个设备的,设备文件所处的目录也与其功能不相干。
设备文件中非常重要的3个属性:
1.设备类型:c和b,c代表这个设备文件对应的设备驱动程序是一个字符设备驱动程序,b代表这个设备文件对应的设备驱动程序是一个块设备驱动程序。2.—主设备号(范围:1~254):标识一类驱动程序。通过前面这个图我们可以看出主设备号204是标识串口这一类驱动程序;主设备号31标识mtd这一类驱动程序。那这里就有一个问题了,我们知道一台电脑上不止一个串口,这多个串口的驱动程序都是用主设备号204来标识,那我们怎么从中找到某一个具体的串口驱动程序呢,这个时候就需要我们的从设备号了。
3.从设备号(范围:0~255):对应一类驱动程序中某一个具体的驱动程序。当我们通过204这个主设备号找到串口这一类驱动程序后,再通过从设备号找到具体的某一个串口的驱动程序。
3.系统调用接口的作用(system call interface)
在异常处理函数里面,根据发生异常的原因,调用不同的处理函数。
例如:使用open函数,则传进来的值为val1(swi val1);使用read函数,则传进来的值为val2(swi val2);使用write函数,则传进来的值为val3(write val3)。内核里的系统调用接口(system callinterface),会根据传进来不同的值,去调用sys_open、sys_read和sys_write。
总结
Sytem call interface系统调用接口是 决定 使用哪一个函数(read(),write(),open()……)
VFS虚拟文件系统 是 决定 调用哪一个驱动程序的open()函数(led_open()、memdev_open()……)
file_operations
file_operations
:是一个函数指针的集合 file_operations成员
static const struct file_operations XXX_fops ={ .owner = THIS_MODULE, .llseek = XXX_llseek, .open = XXX _open, .read = XXX _read, .write = XXX _write, .ioctl = XXX _ioctl, .release = XXX _release,};
struct module *owner
THIS_MODULE
, 一个在 <linux/module.h
> 中定义的宏. cloff_t (*llseek) (struct file *, loff_t, int);
文件定位函数,合法时返回文件的当前位置,不合法返回-EINVAL
第一个参数为file指针,第二个为请求偏移量,第三个为文件定位的起始地址:一般为0或1,0表示文件开头,1表示当前位置
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
读函数,利用copy_to_user()函数让内核读取用户空间的数据,并返回访问的字节数
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
写函数利用copy_from_user()函数让用户向文件写入数据,并返回写入的字节数
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
执行I/O控制命令
int (*open) (struct inode *, struct file *);
打开文件
(7)int (*release) (struct inode *, struct file *) ;
关闭文件
转载地址:http://ynvzi.baihongyu.com/