linux 设备模型之设备驱动

设备模型跟踪所有对系统已知的驱动. 这个跟踪的主要原因是使驱动核心能匹配驱动和新

设备. 一旦驱动在系统中是已知的对象, 但是, 许多其他的事情变得有可能. 设备驱动可

输出和任何特定设备无关的信息和配置变量, 例如:

驱动由下列结构定义:

struct device_driver {

char *name;

struct bus_type *bus;

struct kobject kobj;

struct list_head devices;

int (*probe)(struct device *dev);

int (*remove)(struct device *dev);

void (*shutdown) (struct device *dev);

};

再一次, 几个结构成员被忽略( 全部内容见 <linux/device.h> ). 这里, name 是驱动的

名子( 它在 sysfs 中出现 ), bus 是这个驱动使用的总线类型, kobj 是必然的 kobject,

devices 是当前绑定到这个驱动的所有设备的列表, probe 是一个函数被调用来查询一个

特定设备的存在(以及这个驱动是否可以使用它), remove 当设备从系统中去除时被调用,

shutdown 在关闭时被调用来关闭设备.

使用 device_driver 结构的函数的形式, 现在应当看来是类似的(因此我们快速涵盖它

们). 注册函数是:

int driver_register(struct device_driver *drv);

void driver_unregister(struct device_driver *drv);

通常的属性结构在:

struct driver_attribute {

struct attribute attr;

ssize_t (*show)(struct device_driver *drv, char *buf);

ssize_t (*store)(struct device_driver *drv, const char *buf,

size_t count);

};

DRIVER_ATTR(name, mode, show, store);

以及属性文件以通常的方法创建:

int driver_create_file(struct device_driver *drv, struct driver_attribute *attr);

void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr);

bus_type 结构含有一个成员( drv_attrs ) 指向一套缺省属性, 对所有关联到这个总线

的驱动都创建.

驱动结构嵌入

如同大部分驱动核心结构的情形, device_driver 结构常常被发现嵌到一个更高级的, 总

线特定的结构. lddbus 子系统不会和这样的趋势相反, 因此它已定义了它自己的

ldd_driver 结构:

struct ldd_driver {

char *version;

struct module *module;

struct device_driver driver;

struct driver_attribute version_attr;

};

#define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);

这里, 我们要求每个驱动提供特定当前软件版本, 并且 lddbus 输出这个版本字串为它知

道的每个驱动. 总线特定的驱动注册函数是:

int register_ldd_driver(struct ldd_driver *driver)

{

int ret;

driver->driver.bus = &ldd_bus_type;

ret = driver_register(&driver->driver);

if (ret)

return ret;

driver->version_attr.attr.name = "version";

driver->version_attr.attr.owner = driver->module;

driver->version_attr.attr.mode = S_IRUGO;

driver->version_attr.show = show_version;

driver->version_attr.store = NULL;

return driver_create_file(&driver->driver, &driver->version_attr);

}

这个函数的第一部分只注册低级的 device_driver 结构到核心; 剩下的建立版本属性.

因为这个属性在运行时被创建, 我们不能使用 DRIVER_ATTR 宏; 反之,

driver_attribute 结构必须手工填充. 注意我们设定属性的拥有者为驱动模块, 不是

lddbus 模块; 这样做的理由是可以在为这个属性的 show 函数的实现中见到:

static ssize_t show_version(struct device_driver *driver, char *buf)

{

struct ldd_driver *ldriver = to_ldd_driver(driver);

sprintf(buf, "%s\n", ldriver->version);

return strlen(buf);

}

有人可能认为属性拥有者应当是 lddbus 模块, 因为实现这个属性的函数在那里定义. 这

个函数, 但是, 是使用驱动自身所创建的 ldd_driver 结构. 如果那个结构在一个用户空

间进程试图读取版本号时要消失, 事情会变得麻烦. 指定驱动模块作为属性的拥有者阻止

了模块被卸载, 在用户空间保持属性文件打开时. 因为每个驱动模块创建一个对 lddbus

模块的引用, 我们能确信 lddbus 不会在一个不合适的时间被卸载.

为完整起见, sculld 创建它的 ldd_driver 结构如下:

static struct ldd_driver sculld_driver = { .version = "$Revision: 1.1

$", .module = THIS_MODULE, .driver = { .name = "sculld", }, };

一个简单的对 register_ldd_driver 的调用添加它到系统中. 一旦完成初始化, 驱动信

息可在 sysfs 中见到:

$ tree /sys/bus/ldd/drivers

/sys/bus/ldd/drivers

`-- sculld

|-- sculld0 -> ../../../../devices/ldd0/sculld0

|-- sculld1 -> ../../../../devices/ldd0/sculld1

|-- sculld2 -> ../../../../devices/ldd0/sculld2

|-- sculld3 -> ../../../../devices/ldd0/sculld3

`-- version

[46] 这个总线的逻辑名子, 当然, 应当是"sbus", 但是这个名子已经被一个真实的, 物理总

线采用.

相关推荐
ChoSeitaku5 分钟前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__13510 分钟前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
keep__go1 小时前
Linux 批量配置互信
linux·运维·服务器·数据库·shell
矛取矛求1 小时前
Linux中给普通账户一次性提权
linux·运维·服务器
Fanstay9851 小时前
在Linux中使用Nginx和Docker进行项目部署
linux·nginx·docker
大熊程序猿1 小时前
ubuntu 安装kafka-eagle
linux·ubuntu·kafka
ahadee2 小时前
蓝桥杯每日真题 - 第11天
c语言·vscode·算法·蓝桥杯
No0d1es3 小时前
2024年9月青少年软件编程(C语言/C++)等级考试试卷(九级)
c语言·数据结构·c++·算法·青少年编程·电子学会