PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
前置说明
本文作为本人csdn blog的主站的备份。(BlogID=021)
本文发布于 2016-06-14 20:49:38,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=021)
环境说明
无
前言
无
Linux 系统运行时,文件系统与驱动的前世今生
在Linux系统中,一切皆文件.所以在Linux中,设备也被作为一种文件来操作.而实现这些操作的,就叫做设备驱动.在Linux中,设备被分为三类:
- 字符设备(如,鼠标,键盘==)
- 块设备(如硬盘)
- 网络设备(这里指网络接口,如常见的eth0,wlan0,lo)
我们都知道,Linux一切皆文件,且,Linux具有两个空间--用户与内核.那么具体到用户态的表现就是,我们Open某个设备后,我们就会得到一个在系统中唯一的文件描述符号fd.我们所有关于设备的操作,都是以fd为依据进行操作.那么我们来看一个字符驱动在的调用过程.
- 当我们在用户态执行到open("/dev/xxx-device",mode,flag)函数时.
- 文件系统会到系统中找一个与设备文件(例子中的/dev/xxx-device)对应的inode结构体,同时在一个设备表中去查到对应设备号i_rdev的struct cdev 地址赋值给i_cdev.
struct inode{
dev_t i_rdev; //设备编号
umode_t i_mode;//设备类型
struct cdev *i_cdev; //cdev 指向设备的内核的内部驱动结构
......
};
// 内核中的struct cdev
struct cdev
{
struct kobject kobj;//内嵌的kobject对象
struct module *owner;//所属模块
struct file_operations *ops;//文件操作结构体
struct list_head list;
dev_t dev;//设备号,长度为32位,其中高12为主设备号,低20位为此设备号
unsigned int count;
};
- 找到了设备文件对应的inode后,文件系统将会建立file结构体.并初始化其中的变量,其中最重要的,也是我们写驱动将会用到的是f_op变量的值,这个就是我们驱动中的 struct file_operations 变量的地址.也就是为了使用这个地址,能够调用到我们在驱动中提供的操作设备的一些基本调用.
struct file{
mode_t fmode; //文件模式,如FMODE_READ,FMODE_WRITE
......
loff_t f_pos; //loff_t 是一个64位的数,需要时,须强制转换为32位
unsigned int f_flags; //文件标志,如:O_NONBLOCK
struct file_operations *f_op;
void *private_data; //非常重要,用于存放转换后的设备描述结构指针
.......
};
- 当以上的所有流程走完,那么我们就可以操作设备了.别如read(),write,ioctl()等等
以上就是Linux中,驱动与文件系统的故事,只有了解了这些,我们才能够知道我们为何要用那样的方式,结构,架构等等去写Linux的驱动.
后记
友情提示:我们在用户态操作设备,而驱动在内核态,是两个不同的地址空间.所以我们在用户态的一系列函数(如open(),read(),write(),ioctl()等等)都会被翻译为内核空间中对应的系统调用去执行.而不是直接执行的操作.想详细了解,可自行搜索关键字:Linux 系统调用
参考文献
- 无
PS: 请尊重原创,不喜勿喷。
PS: 要转载请注明出处,本人版权所有。
PS: 有问题请留言,看到后我会第一时间回复。