Linux 驱动模型

为了降低设备多样性带来的Linux驱动开发的复杂度,以及设备热拔插处理、电源管理等,Linux内核提出了设备模型(也称作Driver Model)的概念。设备模型将硬件设备归纳、分类,然后抽象出一套标准的数据结构和接口。驱动的开发,就简化为对内核所规定的数据结构的填充和实现。
http://www.wowotech.net/device_model/13.html

bus device driver class

bus: bus的主要功能是管理device和driver之间的关系. 它维护着一个device列表和一个driver列表, 并且负责匹配device和driver.
device: 对硬件设备的抽象, 主要是描述硬件设备的属性.
driver: 对设备驱动的抽象. 负责管理设备.
class: 是一个device的集合,

kobject sysfs

kobject是内核对象的抽象, 它是一个基类, 在c语言中通过结构体内嵌的方式实现, device就是内核对象他们的数据结构会内嵌一个kobject结构体.
kobject主要有以下功能:

  • 通过parent指针,可以将所有Kobject(内核对象)以层次结构的形式组合起来。
  • 用于管理内核对象的生命周期,使用一个引用计数(reference count),来记录Kobject被引用的次数,并在引用次数变为0时把它释放
  • 和sysfs虚拟文件系统配合,将每一个Kobject及其特性,以文件的形式,开放到用户空间.

sysfs是一个虚拟文件系统, 将kobject(内核对象)的属性以文件的形式展现出来, 供用户空间程序读写.

比如一个device, 它挂在某个bus下同时也属于某个class.
首先sys目录下有给device的目录, 里面会有这个device的目录
也可以通过sys/bus/device/XXX 找到
也可以通过sys/class/XXX 找到
如果这个device有*dev(设备号)属性, 会在device目录下有给dev文件, 里面存放设备号(mdev就读取这个文件自动创建设备节点). 并且在/dev/char/下会有一个以设备号命名的链接, 指向这个设备.

bus

bus 的构成

  • name : 总线的名字, 会在sysfs中以目录的形式存在
  • dev_name : 如果bus下的device没有设置init name, 内核会以"bus->dev_name+device ID"的形式,为这样的设备生成一个名称。
  • bus_attrsdev_attrsdrv_attrs : 一些默认的attribute,可以在bus、device或者device_driver添加到内核时,自动为它们添加相应的attribute
  • match : 匹配device和driver的函数.
  • uevent : 当任何属于该Bus的device,发生添加、移除或者其它动作时,Bus模块的核心逻辑就会调用该接口,以便bus driver能够修改环境变量。
  • probe, remove : bus driver的probe和remove函数

sys/bus里能看到已注册的总线. 在bus目录下使用tree可以看到总线的结构.

bus 的操作

通常我们不会新建一个新的总线, 所以这里不介绍如何创建管理总线.

bus_for_each_dev

bus_for_each_drv

BUS_ATTR(name, mode, show, store);

device

device的构成

  • parent : 该设备的父设备,一般是该设备所从属的bus
  • p : 该指针中会保存子设备链表。
  • kobj : 如上文所说,通过嵌入struct kobject实现类似继承的功能(复用kobject相关的代码)。
  • init_name : 该设备的名称,最终是设置到kobj配合sysfs创建目录, 不设置时内核会根据bus->dev_name + device ID生成一个名称。
  • type :
  • bus : 该设备所从属的bus
  • driver : 该设备所使用的driver, 通常在bus match成功后调用driver的probe函数,在验证设备可用后设置该指针。
  • platform_data : 供driver使用, 放一些私有数据
  • power, pm_domain : 电源管理相关
  • devt : 设备号. 一般什么时候被设置?
  • release : 释放设备时调用的函数, 上文提到kobject会自动释放, 就靠这实现.
  • class : 该设备所从属的class
  • groups : 该设备的attribute 集合, sysfs会根据这个集合创建对应的文件.

device的操作

DEVICE_ATTR(name, mode, show, store); //使用这个宏定义一个attribute. mode是文件权限, show和store是读写函数.

device_register(struct device *dev); //注册一个设备

device_unregister(struct device *dev);

device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...) //创建并注册一个设备

通常device也是基类嵌入到一个结构体中的, 比如platform_device. 所以更常用的是其子类的操作函数, 比如platform_device_register.

driver

driver 的构成

  • name : 驱动的名字
  • bus : 该驱动所从属的bus
  • owner, mod_name : 和module相关
  • probe : 当设备匹配成功后调用的函数
  • remove : 当设备被移除时调用的函数
  • shutdown, suspend, resume, pm : 电源管理相关
  • suppress_bind_attrs : 是否启动sysfs的bind/unbind功能. bind/unbind是从用户空间手动的为driver绑定/解绑定指定的设备的机制.
  • groups : 该driver的attribute 集合, sysfs会根据这个集合创建对应的文件.
  • p : 私有数据指针

DRIVER_ATTR(name, mode, show, store); //和DEVICE_ATTR一样, 用于定义一个attribute

在这个架构下, 驱动开发者基本的工作就是实现probe和remove函数.这两个函数的参数都是device, 这样就能获取到device的数据了.
probe 要做以下事情:

  • 验证设备(device)是否可用
  • 字符设备注册, 包括设备号分配, file_operations设置, cdev注册等
    remove 是probe的逆操作, 释放资源.

probe 触发的时机:

  • 将struct device类型的变量注册到内核中时自动触发
  • 将struct device_driver类型的变量注册到内核中时自动触发
  • 手动查找bus下的设备/驱动时手动触发

class

把一些设备归类, 同一类设备就会有相同的属性/操作, 把他们都放到一个class下, 这样就可以把这些共性的东西放到class下, 而不是每个device都有一份.

class 的构成

  • name : class的名字, 会在/sys/class/下以目录的形式存在
  • class_atrrs : 该class的默认attribute, 在/sys/class/xxx_class”下创建对应的attribute文件。
  • dev_attrs : 共性属性, 该class下每个device的attribute, 在/sys/class/xxx_class/xxx_device”下创建对应的attribute文件。
  • dev_uevent : 当该class下有设备发生变化时,会调用class的uevent回调函数。
  • class_release : 用于release自身的回调函数。
  • dev_release : 用于release class内设备的回调函数。在device_release接口中,会依次检查Device、Device Type以及Device所在的class,是否注册release接口,如果有则调用相应的release接口release设备指针。
posted @ 2025-03-23 18:46  天刚刚破晓  阅读(55)  评论(0)    收藏  举报