[内核]Linux UserSpace和Kernel之间如何联系

转自:http://blog.csdn.net/dreaming_my_dreams/article/details/8272586

应用层和驱动的衔接,一直是一个老大难问题,若弄不清楚,总觉得驱动写起来似是而非的。下面就说说我对他们的理解,还有就是如何实现一个驱动支持多个上设备的问题。最主要涉及两个机制:inode和file

1. 在驱动中

  1. 我们先找到一个设备号devno,可以动态申请,也可以静态设定,假设静态设定为major,minor,通过宏MKDEV(major,minor)来生成devno
  2. 构建对设备的操作函数集file_opreation结构体,里面包含了的设备的操作:open、read、write、release、ioctl等
  3. 构建cdev结构体,里面填充两个主要成员dev(设备号)、file_operation(对设备的操作)
  4. 把cdev添加到cdev链表中:cdev_init、cdev_add

举个例子,tty驱动:

-->__init imx_serial_init     //imx.c

  -->uart_register_driver    //serial_core.c

    -->tty_regiser_driver    //tty_io.c

      -->MKDEV(driver->major, driver->minor_start)  //tty_io.c

      -->tty_cdev_add        //tty_io.c

        -->cdev_init(tty_fops)   //tty_io.c, struct file_operations tty_fops={.open;.read;.write}

        -->cdev_add        //tty_io.c

就这样,一步步将file_operation的函数集加入到cdev->ops中,而User层则根据设备号找到cdev链表中对应的设备属性,从而找到函数集。

2. 应用程序中

fd=open("/dev/hello",O_RDWR)来打开设备文件,此设备对应有一个设备号,这是我们识别驱动和设备的桥梁

设备号、设备文件、设备节点概念:设备号由主设备号和从设备号组成,设备号是16bit, 高8bit为主设备号,低8bit为从设备号。/dev下每个设备都有对应的设备文件,即设备节点。

打开 /dev/hello时,根据设备号,在cdev链表中找到cdev这个结构体,cdev里面包含了file_operation结构体,有设备的各种操作,打开时就调用里面的.open 函数。在这里要完成几件事:

  1. inode节点 每一个文件都对应有一个inode节点,inode结构体里.i_fop由cdev的file_operation填充,i_dev由cdev的设备号填充
  2. file结构体中的file_operation也同样由cdev中对应项填充,还有一项fd,对应于打开文件的文件描述符,fd和file一一对应,文件每打开一次,就有一个file结构。所以file里面的.private就很重要,下面会说到。

还有一个问题,那就是多个相同的设备,会公用同一个驱动(一个驱动文件1个主设备号如uart所以要把每一个设备的私有数据封装起来,构成一个私有数据结构体。对设备的每一次读写,都通过操作设备的私有数据结构体中的资源来完成。也就是说,驱动在加载的时候,会申请多个设备私有资源结构体,每个结构体中包含了设备的所有私有资源,虽然公用一个驱动,可是通过设备号找到此设备号对应设备的私有资源,说的有点拗口。这可以通过file结构体的.private来指向。

例如封装私有数据的结构体为:

struct hello_device{

char buf[128]; //设备的私有资源,譬如buf

struct cdev cdev;//设备结构体,里面有devno和file_operation

……

};

前面应经提到inode中的i_cdev会指向cdev结构,所以可以由Container宏来得到hello_device的地址。

所以,在驱动的open函数中有两个参数,inode和file

int open(structc inode *inode,struct file *file){

struct hello_device   *p =container(inode->i_cdev,hello_struct,cdev)

file->private=p;

}

这样file中就包含了设备的私有数据。

驱动read函数中:

ssize_t read(fd,char __user *buf,count)

fd和file一一对应,每打开一次设备,虽然有不同的fd,但他们的file.private是一样的。

每打开一个设备文件,把私有数据和file绑定,这样后面的read/write操作,由于fd和file一一对应,这样,read/write也就通过fd句柄就可以访问到file->private数据了。 

前面主要说了一个驱动如何可以支持多个设备的问题,以及应用层和驱动之间的联系。还有一个问题就是,如何处理过多个进程访问同一个设备的问题

-----------------------------------------------------------------------------------------------------------------------------------------------------------

转自:http://blog.chinaunix.net/uid-20543672-id-3203690.html

最近在看《深入Linux设备驱动程序机制》,这本书条理清晰,我从中获益良多。以前在学习内核驱动的时候就是知道怎么用,对于内部的原理了解的不是这么深入。且当时的能力有限,想了解深入也不容易。这次正好趁复习驱动原理的机会,把这本书认真学习以下。

 
    在第二章讲解字符设备的时候,个人觉得比较有收获的主要是两个方面的知识:
1、字符设备号的管理原理(char_device_struct)
2、字符设备驱动的file_operation中的函数如何与file结构体中的相应结构对应上,并被应用程序调用。
 
    对于以上两个主要的知识点,我觉得书上的条理已经很清楚的,很容易看懂,我在这里复述就多余了。我把学到的两个知识点用图的方式总结出来,供大家参考。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1、字符设备号的管理原理

    重点在于内核在管理时所依赖数据结构char_device_struct以及全局的散列表chrdevs。
    还有就是要知道内核对于设备号的注册与注销和驱动功能的实现是没有必然的联系的。设备号的管理是一个独立的机制,以避免驱动在使用设备号的时候发生冲突,导致驱动中的file_operation对应错误,进而出现应用层操作错误的设备。因为应用层对设备的操作就是通过设备号对应到具体的file_operation的
 
 
 

2、字符设备驱动的file_operation中的函数如何与file结构体中的相应结构对应上,并被应用程序调用

   这部分的内容主要是要熟悉open函数的调用流程,驱动中的file_operation结构体就是在open函数中通过设备号与进程相关的file结构体中相应函数进行对应的。在完成了open操作之后,其他的文件操作就可以直接调用驱动file_operation中的函数了。
   内核对于char_device_struct结构体的管理方式和设备号的cdev_map是类似的,都是通过主设备号作为哈希表的key来索引。
 
原文地址:https://www.cnblogs.com/aaronLinux/p/6661618.html