1.Linux的应用程序是怎么调用驱动程序的?

 

 

2.应用程序的open是怎么与驱动的open对应起来的?(https://blog.csdn.net/dengdun6257/article/details/102283350)

应用层:

当应用程序调用open打开设备文件时会返回一个文件描述符,以供后续的应用程序使用;open原型为:int open(const char *pathname, int flags)

当打开之后调用read读取数据时:read原型为:ssize_t read(int fd, void *buf, size_t count)

 

映射过程:(https://www.linuxidc.com/Linux/2016-12/138520.htm)

注册设备时将实际的fops赋值给cdev的fops,并注册到cdev_map表,并与设备号映射(cdev_map是一个struct kobj_map类型的指针,其中包含着一个struct probe指针类型、大小为255的数组,数组的每个元素指向的一个probe结构封装了一个设备号和相应的设备对象(这里就是cdev),这个cdev_map封装了系统中的所有的cdev结构和对应的设备号;主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型。次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备 )

 

cdev_map对字符设备的管理方式有两种:

(1)一个cdev对象对应这一个/多个设备号的情况

在cdev_map中, 一个probes对象就对应一个主设备号;多个设备号对应一个cdev时,其实只是次设备号在变,主设备号还是一样的,所以是同一个probes对象。

(2)主设备号超过255的情况

当主设备号超过255时,会进行probe复用,此时probe->next就派上了用场,比如probe[200]可以表示设备号200,455...3895等所有对255取余是200的数字。

 

当应用层调用open时,会根据路径得到设备节点文件并找到内核里的inode指针,打开后内核会得到一个flip指针;并返回给应用程序一个文件描述符以供后续的read,write等使用。inode指针中有设备号信息能够告诉操作系统应该使用哪一个设备驱动程序(主要是fops),flip指针中有fops信息(通过inode里的fops传给flip里的fops)

 

 

驱动层:

static int chrdev_open(struct inode *inode, struct file *filp)inode对应内核的设备文件,filp对应当前被打开的文件

 

static ssize_t chrdev_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) ;设备打开后,就使用打开的文件进行后续的操作

 

3.系统调用是怎么运转的?(https://blog.csdn.net/gatieme/article/details/50779184)

一般地,系统调用都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产生,而128号异常处理程序就是系统调用处理程序system_call()

Linux中每个系统调用都有相应的系统调用号作为唯一的标识,内核维护一张系统调用表,sys_call_table,表中的元素是系统调用函数的起始地址,而系统调用号就是系统调用在调用表的偏移量

大部分系统调用都还需要一些外部的参数输人给内核空间和给用户空间返回值,都是通过寄存器传递

 

4.module_init怎么区别驱动是编译进内核还是模块?(https://blog.csdn.net/weixin_37571125/article/details/78665184)

模块代码有两种运行方式,一是静态编译连接进内核,在系统启动过程中进行初始化;一是编译成可动态加载的module,通过insmod动态加载重定位到内核。这两种方式可以在Makefile中通过obj-y或obj-m选项进行选择;

当我们选择将驱动编译成模块时,module_init中的MODULE宏就会被定义; 如果没有定义MODULE宏,那么驱动初始化函数就会带有.initcall6.init属性,那么在其编译时将会被安排到__initcall_start和__initcall_end范围之间。.init 或者 .initcalls 段的特点就是,当内核启动完毕后,这个段中的内存会被释放掉

posted on 2020-02-12 19:55  lzd626  阅读(187)  评论(0编辑  收藏  举报