linux内核之设备驱动那些事(1)

linux内核,作为操作系统的核心部分,管理各种硬件资源。内核对上屏蔽各种底层细节,简化应用程序开发。

内核中有相当比例的代码为驱动代码,因为内核需要支持各种各样的硬件。每次内核正式版本的发布,驱动代码所占比例总是最多。众多硬件厂商将驱动代码提交到内核开源版本中,并遵从内核驱动架构,除开利益因素,必然意味着驱动架构有其合理之处。

接下来,希望能通过对驱动各个部分和细节的了解,逐步加深对其的理解,终极目标是有改造它,优化它的能力。

1、 设备分类

这里写图片描述

Linux内核中有常见的三种典型设备:

  • 网络设备:对应我们通常看到的网络接口,负责数据包的收发,可以通过ifconfig查看网络设备
  • 块设备:用于对应用程序提供存储服务,例如硬盘、U盘、flash等,可以通过/dev目录中的设备文件查看
  • 字符设备:用于对应用程序提供其它类设备的访问服务,例如输入、声音、图像、串口等,同样通过/dev目录中的设备文件查看

所有字符设备和块设备都有主从设备号:

  • 主设备号(major):表示设备的家族类别
  • 从设备号(minor):表示具体设备编号
    大多数主从设备号都是静态分配

一个设备具体属于哪一种设备,关键是看其如何被应用所使用。

2、下有总线上有框架

这里写图片描述

框架:使硬件特性以某种通用的方式供上层使用。应用必然不会直接操作硬件,甚至根本不知道底层有哪些硬件。通过文件系统使用块设备;通过socket利用内核协议栈使用网络接口,这里文件系统、内核协议栈就是框架。
总线:是内核驱动模型的重要组成部分,实现硬件和驱动的匹配,建立起硬件与驱动之间的联系

驱动开发在已经对硬件本身比较了解的基础上,只要知道以什么方式将硬件资源体现给应用(使用什么框架),以什么总线形式注册到内核中,就可以专注在驱动的实现了。

3、内核总线

一台PC,一个嵌入式设备,从硬件组成上看,各种设备、控制器都是由总线连接起来的,总线起到了连接通讯的目的。CPU到DDR的系统总线,PCI控制到PCI设备的PCI总线,USB控制器到USB设备的USB总线,以及SCSI控制器到磁盘设备的SCSI总线等。

内核中的总线,属于软件层面,虽然是软件层面,但基本还是能够和硬件层面对应起来。内核总的总线也是相当丰富,USB、I2C、SPI、PCI,还有特殊的platform总线。内核总线,最关键的作用就是能够进行驱动和硬件设备的匹配。
这里写图片描述
在linux内核中,设备(描述)信息和驱动是分开的,相同类型的设备在不同系统中,资源描述信息是不一样的,例如寄存器地址区间、中断号、管脚信息等。虽然这些信息不一样的,但是对这类设备的使用方式却是相同的,完全可以做到同一套代码(驱动)复用。因此内核中的驱动程序一般被设计成比较通用的形式以便能够适应各种不同。既然设备描述和驱动是分开的,驱动和设备之间的联系则通过总线来完成。

由于匹配的需要,设备信息和驱动都需要注册到相同类型的总线上。假设BUS中已经注册了设备信息,当驱动进行注册时,会查找是否有其支持的硬件,如果找到,则开始对硬件进行进一步的初始化等操作;如果没有找到,则什么也不用做。相反,如果BUS总已经注册了驱动,当设备进行注册时,会查找是否有支持它的驱动,如果找到,则进行下一步动作;如果没有,也是什么也不用做。

总线进行设备和驱动的匹配使用的信息多样,可以是相同名字的字符串,也可以是相同的id号等等

下面,通过一个具体的例子看看驱动与设备的匹配过程:
这里写图片描述
通常内核启动过程中会加载内核支持的驱动代码模块,这时也就将相应驱动注册到了总线上(当然,也有驱动模块是后续通过udev等机制动态加载的,我们后面逐一介绍)。假设上图driverA、driverB和driverC在系统启动过程中已经注册到USB总线上。当一个USB设备接入时,会是一个怎样的过程了?

  • 1、USB设备接入
  • 2、USB控制器发现这个设备,通知内核
  • 3、内核根据上报信息生成USB设备并注册到USB内核总线中
  • 4、USB设备注册过程中完成与驱动的匹配,匹配成功调用驱动的初始化函数(probe)

前两个步骤为硬件层面,后面两个则为内核软件层面。
上面描述的USB总线上设备和驱动的匹配与物理总线关系紧密,或者说物理总线对设备的枚举识别促使该种类型对应内核总线的设备和驱动的匹配呈现出我们现在看到的样子。我们再来看另外一种总线,PCI总线。由于物理上总线对设备的识别与USB存在区别,因此设备与驱动的匹配过程又呈现另一番景象。

  • 1、PCI控制器初始化并扫描PCI总线上的所有设备
  • 2、被扫描到的设备根据硬件信息生成PCI设备注册到内核PCI总线上
  • 3、PCI驱动注册到内核PCI总线上
  • 4、PCI驱动注册时完成与PCI设备的匹配,匹配成功调用初始化函数(probe)。

USB和PCI由于物理总线运行机制的差别,导致软件上设备与驱动的匹配呈现区别。USB看起来是USB设备注册时进行的匹配,而PCI则是在PCI驱动注册时进行的匹配。而实际情况是,USB总线设备与驱动的匹配既可以是USB设备注册时,也可以是USB驱动注册时。但PCI通常只能是在PCI驱动注册时进行匹配。(PCI设备的加载发生在PCI控制器的扫描阶段,PCI控制器的扫描通常在linux内核启动阶段进行,将所有扫描到的PCI设备都先注册到PCI内核总线上,因此PCI驱动通常都是在设备注册到总线后加载的)。

我们描述了能够利用总线物理特性进行枚举的PCI和USB的设备和驱动的匹配过程。那么问题来了,USB控制器了?PCI控制器了?还有嵌入式系统中大量存在的外设控制器?没有物理特性通知内核这些设备的到来,也就无从谈起注册到内核总线中,它们如何匹配自己的驱动了?答案就是platform总线

Platform总线是内核提供的虚拟总线,能够解决上面提到的所有问题。因为没有硬件机制或者说硬件事件能够让内核发现这些外设(串口控制器、I2C控制器、SPI控制器、网口控制器、图形设备、声音设备,包括USB控制器和PCI控制器等),因此内核中设计了platform总线,硬件信息以dtb或者代码描述的方式注册到platform总线上。这些外设的驱动模块在加载时通过platform总线完成驱动与硬件设备的匹配。特别是嵌入式系统中,platform总线是整个驱动过程的基础。

下图为一个硬件系统的总线结构:
这里写图片描述

如果在linux内核中,对应的软件总线结构大概会是这样:

这里写图片描述

Framework(框架),是我们下一节关心的内容。

4、总线数据结构

这里写图片描述

内核中总线相关的数据结构关键的有三个:
1、bus_type:描述一种类型的总线
2、device_driver:表示总线上的驱动
3、device:表示总线上的设备
实际上由于设备与驱动的多样,内核设计上,具体的驱动和设备结构体继承自device_driver和device结构体,达到多样化,定制化。

到此,我们基本了解了linux内核的总线,从驱动代码的角度看,也仅仅是完成了驱动代码中probe函数被调用之前的过程讲解。下一节,继续probe函数后续分析。

参考

【1】http://free-electrons.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值