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", 但是这个名子已经被一个真实的, 物理总

线采用.

相关推荐
z千鑫2 小时前
【C/C++】数据库链接入门教程:从零开始的详细指南!MySQL集成与操作
c语言·数据库·c++
脸ル粉嘟嘟2 小时前
linux(redhat8)如何安装mysql8.0之rpm&tar双版本(最新版)(内网)(离线)
linux·运维·adb
Octopus20776 小时前
【Linux】vim的使用
linux·笔记·学习·vim
一个假的前端男6 小时前
VMware安装CentOS 9 及mysql的安装
linux·运维·centos
北京迅为6 小时前
【北京迅为】iTOP-4412全能版使用手册-第七章 Android 4.4系统编译
linux·嵌入式硬件·4412开发板
大风吹PP凉6 小时前
47小型项目的规划与实施
linux·运维·服务器
ccnnlxc7 小时前
shell编程第四天(day036)
linux·运维·服务器
基极向上的三极管8 小时前
【Linux学习】【Ubuntu入门】1-10 ubuntu文件权限
linux·ubuntu
滴水之功8 小时前
VMware ubuntu创建共享文件夹与Windows互传文件
linux·ubuntu
Jolen_xie8 小时前
Ubuntu下用Docker部署群晖系统---Virtual DSM --zerotier实现连接
linux·ubuntu·docker