Linux设备模型(一) 概览

参考文章:http://www.wowotech.net/linux_kenrel/13.html

目录

1. 简介

为了降低设备多样性带来的Linux驱动开发的复杂度,以及设备热拔插处理、电源管理等,Linux内核提出了设备模型的概念。设备模型将硬件设备归纳、分类,然后抽象出一套标准的数据结构和接口。

2. Linux设备模型概览

Linux设备模型是一个复杂的数据结构,图2.1是Linux设备模型示意图。
Linux设备模型使用一系列抽象,提供统一的设备管理视图,这些抽象包括:Bus,Class,Device,Device Driver
Linux设备模型(一)  概览

基于上述4个抽象数据结构,驱动的开发,就简化为对内核所规定的数据结构的填充和实现。
图2.2 列出了Linux设备模型相关技术点。对于Linux驱动工程师来说,想要理解Linux设备模型,这些技术点是需要深刻学习理解的。
实际上,对于上层用户,只需要关心Bus,Class,Device,Device Driver。而对于Kobject,sysfs,uevent,上层用户是不需要关心的。
Linux设备模型(一)  概览
先简单说一下Kobject,sysfs,uevent:
Kobject是Linux设备模型的基础数据结构,Bus,Class,Device,Device Driver 这4个数据结构都包含有Kobject相关数据结构。
sysfs是一个基于RAM的文件系统,它和Kobject一起,可以将Kernel的数据结构导出到用户空间,以文件目录结构的形式,提供对这些数据结构(以及数据结构的属性)的访问支持。正是通过sysfs文件系统,将Bus,Class,Device,Device Driver的信息展示给了用户,通过修改/sys目录下设备的文件容,即可以直接修改设备对应的参数。
uevent用于在Kobject状态发生改变时,例如增加、移除等,通知用户空间程序。用户空间程序收到这样的事件后,会做相应的处理。

3. Bus, Class, Device和Device Driver的概念

Linux设备模型是抽象出来的模型,那么我们来看看它是对什么做了抽象。
先来看一个嵌入式系统常见的硬件拓扑图。
Linux设备模型(一)  概览

Bus(总线):Linux认为(可以参考include/linux/device.h中struct bus_type的注释),总线是CPU和一个或多个设备之间信息交互的通道。而为了方便设备模型的抽象,所有的设备都应连接到总线上(无论是CPU内部总线、虚拟的总线还是“Platform Bus”)。

注1:什么是Platform Bus?
在计算机中有这样一类设备,它们通过各自的设备控制器,直接和CPU连接,CPU可以通过常规的寻址操作访问它们(或者说访问它们的控制器)。这种连接方式,并不属于传统意义上的总线连接。但设备模型应该具备普适性,因此Linux就虚构了一条Platform Bus,供这些设备挂靠。

注2:区分I2C控制器、I2C设备。(SPI也是类似的,要区分SPI控制器和SPI设备)
对于ARM Core而言,I2C控制器、I2C设备都是设备。如图3.1所示, I2C控制器是连接到Platform Bus的。而 I2C Bus Device是连接到I2C Bus的。而我们通常写的设备驱动,是连接到 I2C Bus 上的 I2C Bus Device 驱动

思考:
几乎所有的文章都说Platform Bus是不存在的,是虚构的。
但是,对于了解嵌入式硬件架构(以ARM架构为例)的人而言,在图3.1 嵌入式硬件拓扑图中,Platform Bus就是AMBA总线(可能是AXI、AHB、APB、相关Bridge)的抽象。如果这样说,Platform Bus就不是虚构的,是对硬件的Bus抽象。
当然,这是我自己的一个思考,也不知道是否正确。Linux设备模型设计精巧,作为菜鸟,我可能没有理解到大师们的设计理念。

Class(分类):在Linux设备模型中,Class的概念非常类似面向对象程序设计中的Class(类),它主要是集合具有相似功能或属性的设备,这样就可以抽象出一套可以在多个设备之间共用的数据结构和接口函数。因而从属于相同Class的设备的驱动程序,就不再需要重复定义这些公共资源,直接从Class中“继承”即可。

注:此处的“继承”仅仅是数据结构的嵌套,不是C++语言里的继承概念。
Linux设备模型仅仅是借鉴了面向对象的程序设计思想,并不是真的面向对象。当然也就不存在什么构造函数、析构函数、封装、多态等相关技术点,切记生搬硬套。

Device(设备):抽象系统中所有的硬件设备,描述它的名字、属性、从属的Bus、从属的Class等信息。

Device Driver(驱动):Linux设备模型用Driver抽象硬件设备的驱动程序,它包含设备初始化、电源管理相关的接口实现。而Linux内核中的驱动开发,基本都围绕该抽象进行(实现所规定的接口函数)。

4. Linux设备模型的核心思想

Linux设备模型的核心思想是(通过xxx手段,实现xxx目的):

  1. 用Device(struct device)和Device Driver(struct device_driver)两个数据结构,分别从“有什么用”和“怎么用”两个角度描述硬件设备。这样就统一了编写设备驱动的格式,使驱动开发从论述题变为填空体,从而简化了设备驱动的开发。

  2. 同样使用Device和Device Driver两个数据结构,实现硬件设备的即插即用(热拔插)。
    在Linux内核中,只要任何Device和Device Driver具有相同的名字,内核就会执行Device Driver结构中的初始化函数(probe),该函数会初始化设备,使其为可用状态。
    而对大多数热拔插设备而言,它们的Device Driver一直存在内核中。当设备没有插入时,其Device结构不存在,因而其Driver也就不执行初始化操作。当设备插入时,内核会创建一个Device结构(名称和Driver相同),此时就会触发Driver的执行。这就是即插即用的概念。

  3. 通过"Bus–>Device”类型的树状结构(见2.1章节的图例)解决设备之间的依赖,而这种依赖在开关机、电源管理等过程中尤为重要。
    试想,一个设备挂载在一条总线上,要启动这个设备,必须先启动它所挂载的总线。很显然,如果系统中设备非常多、依赖关系非常复杂的时候,无论是内核还是驱动的开发人员,都无力维护这种关系。
    而设备模型中的这种树状结构,可以自动处理这种依赖关系。启动某一个设备前,内核会检查该设备是否依赖其它设备或者总线,如果依赖,则检查所依赖的对象是否已经启动,如果没有,则会先启动它们,直到启动该设备的条件具备为止。而驱动开发人员需要做的,就是在编写设备驱动时,告知内核该设备的依赖关系即可。

  4. 使用Class结构,在设备模型中引入面向对象的概念,这样可以最大限度地抽象共性,减少驱动开发过程中的重复劳动,降低工作量。

5. 小结

将在后面的文章里,逐一介绍图2.2列出的技术点 Bus,Class,Device,Device Driver,Kobject,sysfs,uevent。

6. 说明

图3.1中,Camera通过两条线连接到ARM Core:
一条是直接连接到Camera控制器,可以理解为MIPI CSI接口,Camera数据直接吐到CSI接口。
一条是通过I2C Bus连接到ARM Core,可以理解为Camera的控制信号。

上一篇:聊聊读源码这件事


下一篇:Application全局应用