转自: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来索引。
 

[内核]Linux UserSpace和Kernel之间如何联系的更多相关文章

  1. shell、bash、terminal和kernel之间的关系

    shell.bash.terminal和kernel之间的关系 本文是<鸟哥的Linux私房菜>的学习笔记 什么是kernel kernel的中文是"操作系统核心",主 ...

  2. ZMQ 在linux进程 和分布式之间的通信

    ZMQ 在linux进程 和分布式之间的通信 待补全

  3. Linux/Unix shell sql 之间传递变量

    灵活结合Linux/Unix Shell 与SQL 之间的变量传输,极大程度的提高了DBA的工作效率,本文针对Linux/Unix shell sql 之间传递变量给出几个简单的示例以供参考. Lin ...

  4. 远程调用内核接口(remote call kernel)

    -------------------------------------------------------------------------------- 标题: 远程调用内核接口(remote ...

  5. Level-IP(Linux userspace TCP/IP stack)

    转自:github.com/saminiir/level-ip Level-IP is a Linux userspace TCP/IP stack, implemented with TUN/TAP ...

  6. lower_case_table_names和数据库在Linux和windows平台之间的相互迁移问题

    MySQL关于 lower_case_table_names 的文档 https://dev.mysql.com/doc/refman/5.7/en/identifier-case-sensitivi ...

  7. Memory Allocation API In Linux Kernel && Linux Userspace、kmalloc vmalloc Difference、Kernel Large Section Memory Allocation

    目录 . 内核态(ring0)内存申请和用户态(ring3)内存申请 . 内核态(ring0)内存申请:kmalloc/kfree.vmalloc/vfree . 用户态(ring3)内存申请:mal ...

  8. archlinux 传统方法编译内核linux kernel 3.3.7

    From: http://hi.baidu.com/flashgive/item/eaef6326b5eb73d3a417b662 archlinux中传统方法编译内核 1)下载内核以及补丁并解压: ...

  9. Linux 内核源码(kernel source)

    查看内核的发行版:uname -r(--kernel-release) $ uname -r 4.4.0-78-generic 内核源码所在的位置:/usr/src $ cd /usr/src $ l ...

随机推荐

  1. 【云计算】Docker容器不能修改hosts文件怎么解决?

    参考资料: http://bbs.csdn.net/topics/390871429 http://tieba.baidu.com/p/4295556808 http://stackoverflow. ...

  2. Ubuntu 16.04 LTS软件包管理基本操作

    前文 Ubuntu 16.04 新特性中我们已经介绍过,随着 Ubuntu 16.04 LTS 的发布,Ubuntu 的软件包管理命令也发生了变化,新系统采用了 Debian 项目中所使用的 APT( ...

  3. 初始小R-安装启动与测试

    非常感谢<深入浅出数据分析>这本书让我有幸认识了R,多多少少的弥补了我心里对R语言.R分析.R工具的模糊认知,下面我们就来体验一下R语言的魅力吧!GO! 一:下载R R官方地址:http: ...

  4. js 能实现监听F5页面刷新子iframe 而父页面不刷新

    重点是阻止默认的刷新,这样外部页面就不刷新了,然后指定刷新iframe,我下面给出了思路 document.onkeypress = function(e){ if(e.keyCode == 116) ...

  5. mvc:annotation-driven注解的作用

    <mvc:annotation-driven>会自动注册RequestMappingHandlerMapping与RequestMappingHandlerAdapter两个Bean,这是 ...

  6. The application is in break mode

    在安装使用Visual Studio 2017后,当代码出现异常的时候,它没有调到代码出错的地方,显示了下图.. 解决办法:打开 Debug——>Options——>,勾上 Use Man ...

  7. webpack 引入jquery和第三方jquery插件

    1.引入jquery jQuery 直接在 html 中引入,然后在 webpack 中把它配置为全局即可. index.html: <!DOCTYPE html> <html> ...

  8. Hibernate持久化对象的状态

    1. 站在持久化的角度 , Hibernate 把对象分为 4 种状态 : 持久化状态, 暂时状态, 游离状态(脱管状态) , 删除状态.Session 的特定方法能使对象从一个状态转换到还有一个状态 ...

  9. P2P原理

    简单介绍 前面文章在分布式计算泛型中介绍过P2P泛型.他是一种是一种无中心server的对等网络泛型. P2P即Peer-to-Peer的缩写.翻译为点对点或者端对端.就是我们常说的对等计算. P2P ...

  10. Android OpenGL 开发

    2013-06-30 Android OpenGL 开发 Android提供OpenGL包,专门用于3D的加速和渲染等. OpenGL, Open Graphics Library, 是一个专业的图形 ...