www.ourkernel.com 我们的内核
删除设备时,驱动程序的remove回调函数被调用,
将设备从它的设备列表中删除,并将设备的引用数减1,直至引用数减到0为止。 两者之间的所有符号链接也被删除。
删除驱动程序时,必须对它所支持的所有设备进行遍历, 对每个设备调用驱动程序的remove回调函数。 设备从驱动程序的设备列表中删除, 两者之间的所有符号链接也被删除。
Bus
原文作者:
翻 译者:xiaochuan-xu 511221198209167478@qq.com 校 订者:
版本状态:还未完成
======================================
总线类型
定义
~~~~~
struct bus_type { char * name;
struct subsystem subsys; struct kset drivers; struct kset
devices;
struct bus_attribute * bus_attrs; struct device_attribute * dev_attrs; struct driver_attribute * drv_attrs; int (*match)(struct device * dev, struct device_driver * drv); int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); int (*suspend)(struct device * dev, pm_message_t state); int
(*resume)(struct device * dev);
};
int bus_register(struct bus_type * bus);
声明
6
www.ourkernel.com 我们的内核
~~~~~
内核中每一种总线类型(如PCI, USB等)都应该声明一个与之对应的静态对象。必须初始化
name域,并可选择性的初始化match回调函数。
struct bus_type pci_bus_type = { .name = \ .match };
= pci_bus_match,
这个结构体应该通过一个头文件向驱动程序开放:
extern struct bus_type pci_bus_type;
注册 ~~~~~
通过调用bus_register函数来初始化驱动程序。这个函数初始化总线对象的其余成员变量, 并把它插入到一个全局的总线类型链表种。一旦这个总线对象被注册,总线驱动就可以使用 总线对象的成员。
回调函数
~~~~~~~~~
match(): 关联驱动程序到设备 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
match回调函数通过比较特定设备的设备标识与驱动程序支持的设备标识为总线提供这个驱
动程序是否支持这个特定的设备的判断机会。这种方式没有牺牲总线私有属性或类型安全。
当向总线注册一个驱动时,系统遍历总线的设备链表,并为每个无驱动程序关联的设备调用 match回调函数。
设备与驱动程序链表 ~~~~~~~~~~~~~~~~~~~
设备链表和驱动程序链表是用来替代大多总线持有的本地链表。它们分别是struct device 和struct device_driver结构的链表。总线驱动可以随心所欲的使用这些链表,但可能需要 转换为总线私有的数据类型。
7
www.ourkernel.com 我们的内核
LDM核提供了一些遍历这些链表的辅助函数。
int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *));
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *));
这些辅助函数遍历各自的链表,并为链表上的每一个设备或驱动程序调用回调函数。所以链 表的访问通过持有总线锁同步。链表上的每一个对象的引用计数在调用回调函数之前被增加 在获取下一个对象后被减小。调用回调函数时锁被释放。
sysfs文件系统
~~~~~~~~~~~~~~
这是一个名叫‘bus’的顶层目录。
每一种总线在这个‘bus’目录下获取一个子目录,同时还有两个默认目录:
/sys/bus/pci/ |-- devices
`-- drivers
注册到总线上的驱动程序在该总线驱动程序目录下获取一个目录:
/sys/bus/pci/ |-- devices
`-- drivers
|-- Intel ICH
|-- Intel ICH Joystick |-- agpgart `-- e100
在总线上发现的每一个给总线类型的设备获取一个该总线设备目录下的指向设备物理层次 目录的符号链接。
/sys/bus/pci/
|-- devices
| |-- 00:00.0 -> ../../../root/pci0/00:00.0 | |-- 00:01.0 -> ../../../root/pci0/00:01.0 | `-- 00:02.0 -> ../../../root/pci0/00:02.0
`-- drivers
导出属性
8
www.ourkernel.com 我们的内核
~~~~~~~~~
struct bus_attribute { struct attribute attr; ssize_t (*show)(struct bus_type *, char * buf); ssize_t (*store)(struct bus_type *, const char * buf, size_t count); };
总线驱动能够通过BUS_ATTR宏导出属性,BUS_ATTR宏工作方式与设备DEVICE_ATTR宏相似。
比如,类似这样定义:
static BUS_ATTR(debug,0644,show_debug,store_debug);
等价于声明:
static bus_attribute bus_attr_debug;
这可以用来对sysfs文件系统上的总线目录添加和删除属性,使用:
int bus_create_file(struct bus_type *, struct bus_attribute *); void bus_remove_file(struct bus_type *, struct bus_attribute *);
Class
原文作者:
翻 译者: 王翔 dimensionwang@gmail.com 校 订者:
版本状态:Request for comment!
======================================
设备类
介绍
~~~~~~~~~~~~
一个设备类描述了一种类型的设备,比如说是声音或者是网络设备。随后的设备类是这样定义的:
<在这里插入设备类的列表>
每一个设备类都定义了一系列的语意和一个与该类对应的设备所要遵循的编程接口。设备的驱动就是这个编程接口的实现,用于驱动在特定总线上工作的特定设备。
9
www.ourkernel.com 我们的内核
设备工作在什么总线上,对于设备类是不可知的。
编程接口
~~~~~~~~~~~~~~~~~~~~~
设备类的结构可能会是这样的:
typedef int (*devclass_add)(struct device *); typedef void (*devclass_remove)(struct device *);
struct device_class {
struct driver_dir_entry dir; struct driver_dir_entry device_dir; struct driver_dir_entry driver_dir; devclass_add
add_device;
remove_device;
char rwlock_t
* name; lock;
u32 devnum; struct list_head node; struct list_head struct list_head
drivers; intf_list;
devclass_remove };
一个典型的设备类的定义可能会是这样的:
struct device_class input_devclass = { .name = \
.add_device = input_add_device, .remove_device = input_remove_device,
};
每一个设备类的结构应该被导出在一个头文件里面,以便被驱动程序,扩展程序和接口使用。
使用以下的语句,实现设备类的注册和撤销:
int devclass_register(struct device_class * cls); void devclass_unregister(struct device_class * cls);
10