Linux设备模型–总线、驱动、设备、设备类 (相关结构介绍)

前面的文章分析设备模型中的最基础部分,下面就要更跨入现实,看看如何在这些基础之上构建整个设备驱动子系统。谈到设备驱动,总会涉及到三个概念:总线、驱动、设备。而在Linux中,为了便于用户管理一些功能不同但是使用方式却很接近的设备,开发者们定义了一个设备类的概念。

总线

?

structbus_type {

constchar*name;

structbus_attribute *bus_attrs;

structdevice_attribute *dev_attrs;

structdriver_attribute *drv_attrs;

int(*match)(structdevice *dev,structdevice_driver *drv);

int(*uevent)(structdevice *dev,structkobj_uevent_env *env);

int(*probe)(structdevice *dev);

int(*remove)(structdevice *dev);

void(*shutdown)(structdevice *dev);

int(*suspend)(structdevice *dev, pm_message_t state);

int(*resume)(structdevice *dev);

conststructdev_pm_ops *pm;

structsubsys_private *p;

};

@name:总线名称

@bus_attrs:总线默认属性

?

structbus_attribute {

structattribute attr;<br> ssize_t (*show)(structbus_type *bus, char*buf);

ssize_t (*store)(structbus_type *bus,constchar*buf, size_tcount);

};

@dev_attrs:所有挂载设备默认属性

?

structdevice_attribute {

structattribute attr;

ssize_t (*show)(structdevice *dev,structdevice_attribute *attr,

char*buf);

ssize_t (*store)(structdevice *dev,structdevice_attribute *attr,

constchar*buf, size_tcount);

};

@drv_attrs:所有挂载驱动默认属性

?

structdriver_attribute {

structattribute attr;

ssize_t (*show)(structdevice_driver *driver,char*buf);

ssize_t (*store)(structdevice_driver *driver,constchar*buf,

size_tcount);

};

以上的属性是该总线所有设备或者驱动通用的,

@match:在有新设备或者新驱动挂载到本总线上时,该函数会被调用多次以匹配设备以及相应的驱动。一般这种匹配很简单,都是比较一下设备和驱动的名字,因此保证设备和相应的驱动具有相同的名字是很重要的。

@uevent:总线通过这个函数向uevent事件中添加环境变量。

@probe:检测总线上的驱动是否支持这个设备,如果支持则将使用match函数进行匹配。

@remove:移除设备

@shutdown:关闭设备,内部调用device_driver中的shutdown函数

@suspend:挂起设备

@resume:重新启动设备

@pm:电源管理相关函数。

@p:总线私有数据。

?

structsubsys_private {

structkset subsys;

structkset *devices_kset;

structkset *drivers_kset;

structklist klist_devices;

structklist klist_drivers;

structblocking_notifier_head bus_notifier;

unsignedintdrivers_autoprobe:1;

structbus_type *bus;

structlist_head class_interfaces;

structkset glue_dirs;

structmutex class_mutex;

structclass*class;

};

@@subsys:内嵌的kset用于定义本子系统,在/sys/bus目录下可以看到很多目录如pci、i2c、spi等,这些目录就对应此处kset内嵌的kobject结构体。在后面分析相关函数时

@@devices_kset、@@drivers_kset:如果你进入目录/sys/bus/pci,就会发现其中包含两个目录:devices和drivers。这里的两个kset就与之对应。在驱动模型中,总线上所有设备对应的kobject结构体都属于devices_kset指向的kset,同理,所有驱动对应的kobject结构体都属于drivers_kset指向的结构体。这里之所以没有使用内嵌kset结构体的方式,我才原因大体有两个,一是上述两个kset都会作为subsys的字节点,如果内嵌的话对于理解有困难。第二个原因我认为才是最根本的,因为后面的驱动也是采用这种相关信息和核心设备模型分开管理的方式,这样既增强了模块之间的独立性,又便于理解。

@@klist_devices、@@klist_drivers:这是两个klist链表的头节点,链表中的元素分别代表driver_private和device。以上四个成员变量构成了两个连个层次,一个是按照设备模型构建的层次,一个是私有数据所构建的层次。

@@bus_notifier:用于实现内核通知机制。有的子系统可能对总线状态变化感兴趣,这个成员变量就是用于通知内核中的其他子系统总线状态发生了变化。

@@drivers_autoprobe:

@@bus: 指向相关联的struct bus_type。

和设备类相关:

@@class_interfaces:所提供的设备类接口,包括两个指针,分别指向添加设备和删除设备的函数。

@@glue_dirs:和sysfs文件系统相关。

@@class_mutex:锁,用于实现访问相对应设备类时的互斥性。

@@class:所对应的设备类

设备类

?

structclass{

constchar*name;

structmodule *owner;

structclass_attribute *class_attrs;

structdevice_attribute *dev_attrs;

structbin_attribute *dev_bin_attrs;

structkobject *dev_kobj;

int(*dev_uevent)(structdevice *dev,structkobj_uevent_env *env);

char*(*devnode)(structdevice *dev, mode_t *mode);

void(*class_release)(structclass*class);

void(*dev_release)(structdevice *dev);

int(*suspend)(structdevice *dev, pm_message_t state);

int(*resume)(structdevice *dev);

conststructkobj_ns_type_operations *ns_type;

constvoid*(*namespace)(structdevice *dev);

conststructdev_pm_ops *pm;

structsubsys_private *p;

};

@name: 设备类的名称

@owner:所属模块

@class_attrs:本设备类的默认属性

@dev_attrs:本设备类下所有设备的默认属性

@dev_bin_attrs:本设备类下所有设备的默认二进制属性

@dev_kobj:本设备类对应的kobject结构体

@dev_uevent:用于向用户空间发送uevent事件时添加环境变量。

@devnode:和devtmpfs相关。

@class_release:释放本设备类对象时的回调函数

@dev_release:释放本设备类下设备对象时的回调函数

@suspend:挂起设备

@resume:重新运行设备

@ns_type:

@pm:电源管理相关函数指针

@p:私有数据,只有设备驱动核心部分可以使用这些数据。

驱动

?

structdevice_driver {

constchar*name;

structbus_type *bus;

structmodule *owner;

constchar*mod_name;/* used for built-in modules */

boolsuppress_bind_attrs;/* disables bind/unbind via sysfs */

conststructof_device_id *of_match_table;

int(*probe) (structdevice *dev);

int(*remove) (structdevice *dev);

void(*shutdown) (structdevice *dev);

int(*suspend) (structdevice *dev, pm_message_t state);

int(*resume) (structdevice *dev);

conststructattribute_group **groups;

conststructdev_pm_ops *pm;

structdriver_private *p;

};

@name:驱动名称@bus:所挂载的总线@owner:所属模块@mod_name:模块名称@suppress_bind_attrs:@of_device_id:指向一个静态数组,数组元素为所支持的设备ID,@probe:检测本驱动是否支持某个设备@remove:设备移除时调用@shutdown:关闭某个设备@suspend:挂起某个设备@resume:继续运行某个设备@groups:属性组,这些属性是驱动可以导出的,并且与任何特定设备都无关的。@pm:电源管理操作指针@p:驱动私有数据,这些数据仅能被驱动模型核心部分访问。

?

structdriver_private {

structkobject kobj;

structklist klist_devices;

structklist_node knode_bus;

structmodule_kobject *mkobj;

structdevice_driver *driver;

};

@@kobj:内嵌的kobject结构体 @@klist_devices:驱动管理的所有设备组成一个klist,此为头节点。 @@knode_bus:所有的总线组成klist双向链表,这是本驱动对应的链表节点。 @@mkobj:所属模块对应的内核对象结构,用于驱动模型(内嵌kobject)。 @@driver:所关联的设备驱动

设备

?

structdevice {

structdevice *parent;

structdevice_private *p;

structkobject kobj;

constchar*init_name;/* initial name of the device */

conststructdevice_type *type;

structmutex mutex;/* mutex to synchronize calls to

* its driver.

*/

structbus_type *bus;/* type of bus device is on */

structdevice_driver *driver;/* which driver has allocated this

device */

void*platform_data;/* Platform specific data, device

core doesn't touch it */

structdev_pm_info power;

structdev_power_domain *pwr_domain;

#ifdef CONFIG_NUMA

intnuma_node;/* NUMA node this device is close to */

#endif

u64 *dma_mask;/* dma mask (if dma'able device) */

u64 coherent_dma_mask;/* Like dma_mask, but for

alloc_coherent mappings as

not all hardware supports

64 bit addresses for consistent

allocations such descriptors. */

structdevice_dma_parameters *dma_parms;

structlist_head dma_pools;/* dma pools (if dma'ble) */

structdma_coherent_mem *dma_mem;/* internal for coherent mem

override */

/* arch specific additions */

structdev_archdata archdata;

structdevice_node *of_node;/* associated device tree node */

dev_t devt;/* dev_t, creates the sysfs "dev" */

spinlock_t devres_lock;

structlist_head devres_head;

structklist_node knode_class;

structclass*class;

conststructattribute_group **groups;/* optional groups */

void(*release)(structdevice *dev);

};

@parent:父设备节点,通常为总线控制器。

@kobj:内嵌的kobject节点

@init_name:设备初始名称

@type:设备类行,类似kobj_type

?

structdevice_type {

constchar*name;

conststructattribute_group **groups;

int(*uevent)(structdevice *dev,structkobj_uevent_env *env);

char*(*devnode)(structdevice *dev, mode_t *mode);

void(*release)(structdevice *dev);

conststructdev_pm_ops *pm;

};

@@name:类型名称

@@attribute_group:属性组

@@uevent:发送uevent事件时添加环境变量

@@devnode:

@@release:释放设备

@@pm:电源管理操作

@mutex:用于串行化对设备驱动的访问。

@bus:所挂载的总线

@driver:所对应的设备驱动

@platform_data:平台相关数据

@power:和电源管理相关的信息

@pwr_domain:电源管理相关的操作

@numa_node:NUMA节点,与机器内存模型相关。

DMA相关

@dma_mask:

@coherent_dma_mask:

@dma_pools:

@archdata:

@of_node:设备数节点,of代表Open Firmware.

@devres_lock:用于保护设备资源列表

@devres_head:设备资源列表

@knode_class:设备类所组成链表的对应节点

@class:所属设备类

@groups:属性组

@release:设备释放函数

@p:私有数据

?

structdevice_private {

structklist klist_children;

structklist_node knode_parent;

structklist_node knode_driver;

structklist_node knode_bus;

void*driver_data;

structdevice *device;

};

@@klist_children:所有的子设备节点组成的链表的头节点

@@knode_parent:与父节点中klist_children构成链表

@@knode_dirver:与设备驱动中的klist_devices构成链表

@@knode_bus:与总线的klist_devices构成链表

@@driver_data:驱动相关的数据

@@device:相关联的设备

参考:http://www.cnblogs.com/jimmychange/archive/2011/09/29/2194831.html

不论你在什么时候结束,重要的是结束之後就不要悔恨

Linux设备模型–总线、驱动、设备、设备类 (相关结构介绍)

相关文章:

你感兴趣的文章:

标签云: