[ZLG-ARM] Linux设备模型(总线、设备、驱动程序和类)

[复制链接]
1909|1
 楼主| reeper 发表于 2009-4-9 14:27 | 显示全部楼层 |阅读模式
总线是处理器和一个或多个设备之间的通道,在设备模型中,&nbsp;所有的设备都通过总线相连,&nbsp;甚至是内部的虚拟'platform'总线。总线可以相互插入。设备模型展示了总线和它们所控制的设备之间的实际连接。<br />在&nbsp;Linux&nbsp;设备模型中,&nbsp;总线由&nbsp;bus_type&nbsp;结构表示,&nbsp;定义在&nbsp;:&nbsp;struct&nbsp;bus_type&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;name;/*总线类型名称*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;owner;/*指向模块的指针(如果有),&nbsp;此模块负责操作这个总线*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subsys;/*与该总线相关的子系统*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drivers;/*总线驱动程序的kset*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devices;/*&nbsp;挂在该总线的所有设备的kset*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klist_devices;/*与该总线相关的驱动程序链表*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klist_drivers;/*挂接在该总线的设备链表*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;blocking_notifier_head&nbsp;bus_notifier;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;bus_attribute&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;bus_attrs;&nbsp;/*总线属性*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_attribute&nbsp;*&nbsp;dev_attrs;&nbsp;/*设备属性,指向为每个加入总线的设备建立的默认属性链表*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;driver_attribute&nbsp;*&nbsp;drv_attrs;&nbsp;/*驱动程序属性*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;bus_attribute&nbsp;drivers_autoprobe_attr;/*驱动自动探测属性*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;bus_attribute&nbsp;drivers_probe_attr;/*驱动探测属性*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*match)(struct&nbsp;device&nbsp;*&nbsp;dev,&nbsp;struct&nbsp;device_driver&nbsp;*&nbsp;drv);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*uevent)(struct&nbsp;device&nbsp;*dev,&nbsp;char&nbsp;**envp,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;num_envp,&nbsp;char&nbsp;*buffer,&nbsp;int&nbsp;buffer_size);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*probe)(struct&nbsp;device&nbsp;*&nbsp;dev);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*remove)(struct&nbsp;device&nbsp;*&nbsp;dev);<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*shutdown)(struct&nbsp;device&nbsp;*&nbsp;dev);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;(*suspend)(struct&nbsp;device&nbsp;*&nbsp;dev,&nbsp;pm_message_t&nbsp;state);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;(*suspend_late)(struct&nbsp;device&nbsp;*&nbsp;dev,&nbsp;pm_message_t&nbsp;state);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;(*resume_early)(struct&nbsp;device&nbsp;*&nbsp;dev);<br />&nbsp;&nbsp;&nbsp;&nbsp;nt&nbsp;(*resume)(struct&nbsp;device&nbsp;*&nbsp;dev);<br />/*处理热插拔、电源管理、探测和移除等事件的方法*/<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;int&nbsp;drivers_autoprobe:1;<br />};<br /><br /><br /><br />总线的注册和删除<br /><br />总线的主要注册步骤:<br /><br />(1)申明和初始化&nbsp;bus_type&nbsp;结构体。只有很少的&nbsp;bus_type&nbsp;成员需要初始化,大部分都由设备模型核心控制。但必须为总线指定名字及一些必要的方法。例如:&nbsp;struct&nbsp;bus_type&nbsp;ldd_bus_type&nbsp;=&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;.name&nbsp;=&nbsp;'ldd',<br />&nbsp;&nbsp;&nbsp;&nbsp;.match&nbsp;=&nbsp;ldd_match,<br />&nbsp;&nbsp;&nbsp;&nbsp;.uevent&nbsp;=&nbsp;ldd_uevent,<br />};<br /><br /><br /><br />(2)调用bus_register函数注册总线。&nbsp;int&nbsp;bus_register(struct&nbsp;bus_type&nbsp;*&nbsp;bus)<br /><br /><br /><br />调用可能失败,&nbsp;所以必须始终检查返回值。若成功,新的总线子系统将被添加进系统,并可在&nbsp;sysfs&nbsp;的&nbsp;/sys/bus&nbsp;下看到。之后可以向总线添加设备。<br />例如:&nbsp;ret&nbsp;=&nbsp;bus_register(&ldd_bus_type);<br />if&nbsp;(ret)<br />return&nbsp;ret;&nbsp;<br /><br /><br /><br />当必须从系统中删除一个总线时,&nbsp;调用:<br />void&nbsp;bus_unregister(struct&nbsp;bus_type&nbsp;*bus);<br /><br /><br />总线方法<br /><br />在&nbsp;bus_type&nbsp;结构中定义了许多方法,它们允许总线核心作为设备核心和单独的驱动程序之间提供服务的中介,主要介绍以下两个方法:&nbsp;int&nbsp;(*match)(struct&nbsp;device&nbsp;*&nbsp;dev,&nbsp;struct&nbsp;device_driver&nbsp;*&nbsp;drv);<br />/*当一个新设备或者驱动被添加到这个总线时,这个方**被调用一次或多次,若指定的驱动程序能够处理指定的设备,则返回非零值。必须在总线层使用这个函数,&nbsp;因为那里存在正确的逻辑,核心内核不知道如何为每个总线类型匹配设备和驱动程序*/<br /><br />int&nbsp;(*uevent)(struct&nbsp;device&nbsp;*dev,&nbsp;char&nbsp;**envp,&nbsp;int&nbsp;num_envp,&nbsp;char&nbsp;*buffer,&nbsp;int&nbsp;buffer_size);<br />/*在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量(参数和&nbsp;kset&nbsp;的uevent方法相同)*/<br /><br /><br /><br />lddbus的match和uevent方法:&nbsp;static&nbsp;int&nbsp;ldd_match(struct&nbsp;device&nbsp;*dev,&nbsp;struct&nbsp;device_driver&nbsp;*driver)<br />{<br />return&nbsp;!strncmp(dev-&gtbus_id,&nbsp;driver-&gtname,&nbsp;strlen(driver-&gtname));<br />}/*仅简单比较驱动和设备的名字*/<br />/*当涉及实际硬件时,&nbsp;match&nbsp;函数常常对设备提供的硬件&nbsp;ID&nbsp;和驱动所支持的&nbsp;ID&nbsp;做比较*/<br /><br />static&nbsp;int&nbsp;ldd_uevent(struct&nbsp;device&nbsp;*dev,&nbsp;char&nbsp;**envp,&nbsp;int&nbsp;num_envp,&nbsp;char&nbsp;*buffer,&nbsp;int&nbsp;buffer_size)<br />{<br />envp[0]&nbsp;=&nbsp;buffer;<br />if&nbsp;(snprintf(buffer,&nbsp;buffer_size,&nbsp;'LDDBUS_VERSION=%s',<br />Version)&nbsp;&gt=&nbsp;buffer_size)<br />return&nbsp;-ENOMEM;<br />envp[1]&nbsp;=&nbsp;NULL;<br />return&nbsp;0;<br />}/*在环境变量中加入&nbsp;lddbus&nbsp;源码的当前版本号*/<br /><br /><br /><br />对设备和驱动的迭代<br /><br />若要编写总线层代码,&nbsp;可能不得不对所有已经注册到总线的设备或驱动进行一些操作,这可能需要仔细研究嵌入到&nbsp;bus_type&nbsp;结构中的其他数据结构,&nbsp;但最好使用内核提供的辅助函数:&nbsp;int&nbsp;bus_for_each_dev(struct&nbsp;bus_type&nbsp;*bus,&nbsp;struct&nbsp;device&nbsp;*start,&nbsp;void&nbsp;*data,&nbsp;int&nbsp;(*fn)(struct&nbsp;device&nbsp;*,&nbsp;void&nbsp;*));<br />int&nbsp;bus_for_each_drv(struct&nbsp;bus_type&nbsp;*bus,&nbsp;struct&nbsp;device_driver&nbsp;*start,&nbsp;void&nbsp;*data,&nbsp;int&nbsp;(*fn)(struct&nbsp;device_driver&nbsp;*,&nbsp;void&nbsp;*));<br /><br />/*这两个函数迭代总线上的每个设备或驱动程序,&nbsp;将关联的&nbsp;device&nbsp;或&nbsp;device_driver&nbsp;传递给&nbsp;fn,&nbsp;同时传递&nbsp;data&nbsp;值。若&nbsp;start&nbsp;为&nbsp;NULL,&nbsp;则从第一个设备开始;&nbsp;否则从&nbsp;start&nbsp;之后的第一个设备开始。若&nbsp;fn&nbsp;返回非零值,&nbsp;迭代停止并且那个值从&nbsp;bus_for_each_dev&nbsp;或bus_for_each_drv&nbsp;返回。*/<br /><br /><br /><br />总线属性<br /><br />几乎&nbsp;Linux&nbsp;设备模型中的每一层都提供添加属性的函数,&nbsp;总线层也不例外。bus_attribute&nbsp;类型定义在&nbsp;如下:&nbsp;struct&nbsp;bus_attribute&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;attribute&nbsp;&nbsp;&nbsp;&nbsp;attr;<br />&nbsp;&nbsp;&nbsp;&nbsp;ssize_t&nbsp;(*show)(struct&nbsp;bus_type&nbsp;*,&nbsp;char&nbsp;*&nbsp;buf);<br />&nbsp;&nbsp;&nbsp;&nbsp;ssize_t&nbsp;(*store)(struct&nbsp;bus_type&nbsp;*,&nbsp;const&nbsp;char&nbsp;*&nbsp;buf,&nbsp;size_t&nbsp;count);<br />};<br /><br /><br /><br /><br />可以看出struct&nbsp;bus_attribute&nbsp;和struct&nbsp;attribute&nbsp;很相似,其实大部分在&nbsp;kobject&nbsp;级上的设备模型层都是以这种方式工作。<br /><br />内核提供了一个宏在编译时创建和初始化&nbsp;bus_attribute&nbsp;结构:&nbsp;BUS_ATTR(_name,_mode,_show,_store)/*这个宏声明一个结构,&nbsp;将&nbsp;bus_attr_&nbsp;作为给定&nbsp;_name&nbsp;的前缀来创建总线的真正名称*/<br /><br />/*总线的属性必须显式调用&nbsp;bus_create_file&nbsp;来创建:*/<br />int&nbsp;bus_create_file(struct&nbsp;bus_type&nbsp;*bus,&nbsp;struct&nbsp;bus_attribute&nbsp;*attr);&nbsp;<br /><br />/*删除总线的属性调用:*/<br />void&nbsp;bus_remove_file(struct&nbsp;bus_type&nbsp;*bus,&nbsp;struct&nbsp;bus_attribute&nbsp;*attr);&nbsp;<br /><br /><br /><br />例如创建一个包含源码版本号简单属性文件方法如下:&nbsp;static&nbsp;ssize_t&nbsp;show_bus_version(struct&nbsp;bus_type&nbsp;*bus,&nbsp;char&nbsp;*buf)<br />{<br />return&nbsp;snprintf(buf,&nbsp;PAGE_SIZE,&nbsp;'%s<br />',&nbsp;Version);<br />}<br /><br />static&nbsp;BUS_ATTR(version,&nbsp;S_IRUGO,&nbsp;show_bus_version,&nbsp;NULL);&nbsp;<br /><br />/*在模块加载时创建属性文件:*/<br />if&nbsp;(bus_create_file(&ldd_bus_type,&nbsp;&bus_attr_version))<br />printk(KERN_NOTICE&nbsp;'Unable&nbsp;to&nbsp;create&nbsp;version&nbsp;attribute<br />');<br /><br />/*这个调用创建一个包含&nbsp;lddbus&nbsp;代码的版本号的属性文件(/sys/bus/ldd/version)*/<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />设备&nbsp;<br />在最底层,&nbsp;Linux&nbsp;系统中的每个设备由一个&nbsp;struct&nbsp;device&nbsp;代表:&nbsp;struct&nbsp;device&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klist_children;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist_node&nbsp;&nbsp;&nbsp;&nbsp;knode_parent;&nbsp;&nbsp;&nbsp;/*&nbsp;node&nbsp;in&nbsp;sibling&nbsp;list&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist_node&nbsp;&nbsp;&nbsp;&nbsp;knode_driver;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist_node&nbsp;&nbsp;&nbsp;&nbsp;knode_bus;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*parent;/*&nbsp;设备的&nbsp;'父'&nbsp;设备,该设备所属的设备,通常一个父设备是某种总线或者主控制器.&nbsp;如果&nbsp;parent&nbsp;是&nbsp;NULL,&nbsp;则该设备是顶层设备,较少见&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kobject&nbsp;kobj;/*代表该设备并将其连接到结构体系中的&nbsp;kobject;&nbsp;注意:作为通用的规则,&nbsp;device-&gtkobj-&gtparent&nbsp;应等于&nbsp;device-&gtparent-&gtkobj*/<br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;bus_id[BUS_ID_SIZE];/*在总线上唯一标识该设备的字符串;例如:&nbsp;PCI&nbsp;设备使用标准的&nbsp;PCI&nbsp;ID&nbsp;格式,&nbsp;包含:域,&nbsp;总线,&nbsp;设备,&nbsp;和功能号.*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_type&nbsp;&nbsp;&nbsp;&nbsp;*type;<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is_registered:1;<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uevent_suppress:1;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_attribute&nbsp;uevent_attr;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_attribute&nbsp;*devt_attr;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;semaphore&nbsp;&nbsp;&nbsp;&nbsp;sem;&nbsp;&nbsp;/*&nbsp;semaphore&nbsp;to&nbsp;synchronize&nbsp;calls&nbsp;to&nbsp;its&nbsp;driver.&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;bus_type&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;bus;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*标识该设备连接在何种类型的总线上*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_driver&nbsp;*driver;&nbsp;&nbsp;&nbsp;&nbsp;/*管理该设备的驱动程序*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*driver_data;&nbsp;&nbsp;&nbsp;&nbsp;/*该设备驱动使用的私有数据成员*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*platform_data;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Platform&nbsp;specific&nbsp;data,&nbsp;device&nbsp;core&nbsp;doesn't&nbsp;touch&nbsp;it&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;dev_pm_info&nbsp;&nbsp;&nbsp;&nbsp;power;<br /><br />#ifdef&nbsp;CONFIG_NUMA<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numa_node;&nbsp;&nbsp;&nbsp;/*&nbsp;NUMA&nbsp;node&nbsp;this&nbsp;device&nbsp;is&nbsp;close&nbsp;to&nbsp;*/<br />#endif<br />&nbsp;&nbsp;&nbsp;&nbsp;u64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*dma_mask;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;dma&nbsp;mask&nbsp;(if&nbsp;dma'able&nbsp;device)&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;u64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;coherent_dma_mask;/*&nbsp;Like&nbsp;dma_mask,&nbsp;but&nbsp;for<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alloc_coherent&nbsp;mappings&nbsp;as<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;not&nbsp;all&nbsp;hardware&nbsp;supports<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;64&nbsp;bit&nbsp;addresses&nbsp;for&nbsp;consistent<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allocations&nbsp;such&nbsp;descriptors.&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;dma_pools;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;dma&nbsp;pools&nbsp;(if&nbsp;dma'ble)&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;dma_coherent_mem&nbsp;&nbsp;&nbsp;&nbsp;*dma_mem;&nbsp;/*&nbsp;internal&nbsp;for&nbsp;coherent&nbsp;mem&nbsp;override&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;arch&nbsp;specific&nbsp;additions&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;dev_archdata&nbsp;&nbsp;&nbsp;&nbsp;archdata;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;spinlock_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devres_lock;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;devres_head;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;class_device&nbsp;migration&nbsp;path&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;node;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*class;<br />&nbsp;&nbsp;&nbsp;&nbsp;dev_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;dev_t,&nbsp;creates&nbsp;the&nbsp;sysfs&nbsp;'dev'&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;attribute_group&nbsp;&nbsp;&nbsp;&nbsp;**groups;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;optional&nbsp;groups&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;(*release)(struct&nbsp;device&nbsp;*&nbsp;dev);/*当这个设备的最后引用被删除时,内核调用该方法;&nbsp;它从被嵌入的&nbsp;kobject&nbsp;的&nbsp;release&nbsp;方法中调用。所有注册到核心的设备结构必须有一个&nbsp;release&nbsp;方法,&nbsp;否则内核将打印错误信息*/<br />};<br />/*在注册&nbsp;struct&nbsp;device&nbsp;前,最少要设置parent,&nbsp;bus_id,&nbsp;bus,&nbsp;和&nbsp;release&nbsp;成员*/<br /><br /><br /><br />设备注册<br /><br />设备的注册和注销函数为:<br />int&nbsp;device_register(struct&nbsp;device&nbsp;*dev);<br />void&nbsp;device_unregister(struct&nbsp;device&nbsp;*dev);<br /><br /><br />一个实际的总线也是一个设备,所以必须单独注册,以下为&nbsp;lddbus&nbsp;在编译时注册它的虚拟总线设备源码:<br /><br />static&nbsp;void&nbsp;ldd_bus_release(struct&nbsp;device&nbsp;*dev)<br />{<br />printk(KERN_DEBUG&nbsp;'lddbus&nbsp;release<br />');<br />}<br /><br />struct&nbsp;device&nbsp;ldd_bus&nbsp;=&nbsp;{<br />.bus_id&nbsp;=&nbsp;'ldd0',<br />.release&nbsp;=&nbsp;ldd_bus_release<br /><br />};&nbsp;/*这是顶层总线,parent&nbsp;和&nbsp;bus&nbsp;成员为&nbsp;NULL*/<br /><br />/*作为第一个(并且唯一)总线,&nbsp;它的名字为&nbsp;ldd0,这个总线设备的注册代码如下:*/<br />ret&nbsp;=&nbsp;device_register(&ldd_bus);<br />if&nbsp;(ret)<br />printk(KERN_NOTICE&nbsp;'Unable&nbsp;to&nbsp;register&nbsp;ldd0<br />');<br />/*一旦调用完成,&nbsp;新总线会在&nbsp;sysfs&nbsp;中&nbsp;/sys/devices&nbsp;下显示,任何挂到这个总线的设备会在&nbsp;/sys/devices/ldd0&nbsp;下显示*/<br /><br /><br />设备属性<br /><br />sysfs&nbsp;中的设备入口可有属性,相关的结构是:&nbsp;/*&nbsp;interface&nbsp;for&nbsp;exporting&nbsp;device&nbsp;attributes&nbsp;这个结构体和《LDD3》中的不同,已经被更新过了,请特别注意!*/<br />struct&nbsp;device_attribute&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;attribute&nbsp;attr;<br />&nbsp;&nbsp;&nbsp;&nbsp;ssize_t&nbsp;(*show)(struct&nbsp;device&nbsp;*dev,&nbsp;struct&nbsp;device_attribute&nbsp;*attr,char&nbsp;*buf);<br />&nbsp;&nbsp;&nbsp;&nbsp;ssize_t&nbsp;(*store)(struct&nbsp;device&nbsp;*dev,&nbsp;struct&nbsp;device_attribute&nbsp;*attr,&nbsp;const&nbsp;char&nbsp;*buf,&nbsp;size_t&nbsp;count);<br />};<br /><br />/*设备属性结构可在编译时建立,&nbsp;使用以下宏:*/<br />DEVICE_ATTR(_name,_mode,_show,_store);<br />/*这个宏声明一个结构,&nbsp;将&nbsp;dev_attr_&nbsp;作为给定&nbsp;_name&nbsp;的前缀来命名设备属性<br /><br />/*属性文件的实际处理使用以下函数:*/<br />int&nbsp;device_create_file(struct&nbsp;device&nbsp;*device,&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_attribute&nbsp;*&nbsp;entry);<br />void&nbsp;device_remove_file(struct&nbsp;device&nbsp;*&nbsp;dev,&nbsp;struct&nbsp;device_attribute&nbsp;*&nbsp;attr);<br /><br /><br /><br />设备结构的嵌入<br /><br />device&nbsp;结构包含设备模型核心用来模拟系统的信息。但大部分子系统记录了关于它们又拥有的设备的额外信息,所以很少单纯用&nbsp;device&nbsp;结构代表设备,而是,通常将其嵌入一个设备的高层表示中。底层驱动几乎不知道&nbsp;struct&nbsp;device。<br /><br />lddbus&nbsp;驱动创建了它自己的&nbsp;device&nbsp;类型,并期望每个设备驱动使用这个类型来注册它们的设备:&nbsp;struct&nbsp;ldd_device&nbsp;{<br />char&nbsp;*name;<br />struct&nbsp;ldd_driver&nbsp;*driver;<br />struct&nbsp;device&nbsp;dev;&nbsp;<br />};&nbsp;<br />#define&nbsp;to_ldd_device(dev)&nbsp;container_of(dev,&nbsp;struct&nbsp;ldd_device,&nbsp;dev);&nbsp;<br /><br /><br /><br />lddbus&nbsp;导出的注册和注销接口如下:&nbsp;/*<br />*&nbsp;LDD&nbsp;devices.<br />*/<br /><br />/*<br />*&nbsp;For&nbsp;now,&nbsp;no&nbsp;references&nbsp;to&nbsp;LDDbus&nbsp;devices&nbsp;go&nbsp;out&nbsp;which&nbsp;are&nbsp;not<br />*&nbsp;tracked&nbsp;via&nbsp;the&nbsp;module&nbsp;reference&nbsp;count,&nbsp;so&nbsp;we&nbsp;use&nbsp;a&nbsp;no-op<br />*&nbsp;release&nbsp;function.<br />*/<br />static&nbsp;void&nbsp;ldd_dev_release(struct&nbsp;device&nbsp;*dev)<br />{&nbsp;}<br /><br />int&nbsp;register_ldd_device(struct&nbsp;ldd_device&nbsp;*ldddev)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;ldddev-&gtdev.bus&nbsp;=&nbsp;&ldd_bus_type;<br />&nbsp;&nbsp;&nbsp;&nbsp;ldddev-&gtdev.parent&nbsp;=&nbsp;&ldd_bus;<br />&nbsp;&nbsp;&nbsp;&nbsp;ldddev-&gtdev.release&nbsp;=&nbsp;ldd_dev_release;<br />&nbsp;&nbsp;&nbsp;&nbsp;strncpy(ldddev-&gtdev.bus_id,&nbsp;ldddev-&gtname,&nbsp;BUS_ID_SIZE);<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;device_register(&ldddev-&gtdev);<br />}<br />EXPORT_SYMBOL(register_ldd_device);<br /><br />void&nbsp;unregister_ldd_device(struct&nbsp;ldd_device&nbsp;*ldddev)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;device_unregister(&ldddev-&gtdev);<br />}<br />EXPORT_SYMBOL(unregister_ldd_device);<br /><br /><br /><br /><br />sculld&nbsp;驱动添加一个自己的属性到它的设备入口,称为&nbsp;dev,&nbsp;仅包含关联的设备号,源码如下:&nbsp;static&nbsp;ssize_t&nbsp;sculld_show_dev(struct&nbsp;device&nbsp;*ddev,struct&nbsp;device_attribute&nbsp;*attr,&nbsp;char&nbsp;*buf)<br />{<br />struct&nbsp;sculld_dev&nbsp;*dev&nbsp;=&nbsp;ddev-&gtdriver_data;<br />return&nbsp;print_dev_t(buf,&nbsp;dev-&gtcdev.dev);<br />}<br /><br />static&nbsp;DEVICE_ATTR(dev,&nbsp;S_IRUGO,&nbsp;sculld_show_dev,&nbsp;NULL);<br /><br />/*接着,&nbsp;在初始化时间,&nbsp;设备被注册,&nbsp;并且&nbsp;dev&nbsp;属性通过下面的函数被创建:*/<br />static&nbsp;void&nbsp;sculld_register_dev(struct&nbsp;sculld_dev&nbsp;*dev,&nbsp;int&nbsp;index)&nbsp;<br />{<br />sprintf(dev-&gtdevname,&nbsp;'sculld%d',&nbsp;index);<br />dev-&gtldev.name&nbsp;=&nbsp;dev-&gtdevname;<br />dev-&gtldev.driver&nbsp;=&nbsp;&sculld_driver;<br />dev-&gtldev.dev.driver_data&nbsp;=&nbsp;dev;<br />register_ldd_device(&dev-&gtldev);<br />if&nbsp;(device_create_file(&dev-&gtldev.dev,&nbsp;&dev_attr_dev))&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;printk(&nbsp;'Unable&nbsp;to&nbsp;create&nbsp;dev&nbsp;attribute&nbsp;!&nbsp;<br />');<br />}&nbsp;/*注意:程序使用&nbsp;driver_data&nbsp;成员来存储指向我们自己的内部的设备结构的指针。请检查device_create_file的返回值,否则编译时会有警告。*/<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />设备驱动程序&nbsp;<br />设备模型跟踪所有系统已知的驱动,主要目的是使驱动程序核心能协调驱动和新设备之间的关系。一旦驱动在系统中是已知的对象就可能完成大量的工作。驱动程序的结构体&nbsp;device_driver&nbsp;定义如下:&nbsp;/*定义在*/<br />struct&nbsp;device_driver&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;name;/*驱动程序的名字(&nbsp;在&nbsp;sysfs&nbsp;中出现&nbsp;)*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;bus_type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;bus;/*驱动程序所操作的总线类型*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kobject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kobj;/*内嵌的kobject对象*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;klist_devices;/*当前驱动程序能操作的设备链表*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;klist_node&nbsp;&nbsp;&nbsp;&nbsp;knode_bus;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;owner;<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;mod_name;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;used&nbsp;for&nbsp;built-in&nbsp;modules&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;module_kobject&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;mkobj;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*probe)&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;device&nbsp;*&nbsp;dev);/*查询一个特定设备是否存在及驱动是否可以使用它的函数*/<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*remove)&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;device&nbsp;*&nbsp;dev);/*将设备从系统中删除*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;(*shutdown)&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;device&nbsp;*&nbsp;dev);/*关闭设备*/<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*suspend)&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;device&nbsp;*&nbsp;dev,&nbsp;pm_message_t&nbsp;state);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*resume)&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;device&nbsp;*&nbsp;dev);<br />};<br /><br />/*注册device_driver&nbsp;结构的函数是:*/<br />int&nbsp;driver_register(struct&nbsp;device_driver&nbsp;*drv);<br />void&nbsp;driver_unregister(struct&nbsp;device_driver&nbsp;*drv);<br /><br />/*driver的属性结构在:*/<br />struct&nbsp;driver_attribute&nbsp;{<br />struct&nbsp;attribute&nbsp;attr;<br />ssize_t&nbsp;(*show)(struct&nbsp;device_driver&nbsp;*drv,&nbsp;char&nbsp;*buf);<br />ssize_t&nbsp;(*store)(struct&nbsp;device_driver&nbsp;*drv,&nbsp;const&nbsp;char&nbsp;*buf,&nbsp;size_t&nbsp;count);<br />};<br />DRIVER_ATTR(_name,_mode,_show,_store)<br /><br />/*属性文件创建的方法:*/<br />int&nbsp;driver_create_file(struct&nbsp;device_driver&nbsp;*&nbsp;drv,&nbsp;struct&nbsp;driver_attribute&nbsp;*&nbsp;attr);<br />void&nbsp;driver_remove_file(struct&nbsp;device_driver&nbsp;*&nbsp;drv,&nbsp;struct&nbsp;driver_attribute&nbsp;*&nbsp;attr);<br /><br />/*bus_type&nbsp;结构含有一个成员(&nbsp;drv_attrs&nbsp;)&nbsp;指向一组为属于该总线的所有设备创建的默认属性*/<br /><br /><br /><br />驱动程序结构的嵌入<br /><br />对大多数驱动程序核心结构,&nbsp;device_driver&nbsp;结构通常被嵌入到一个更高层的、总线相关的结构中。<br /><br />以lddbus&nbsp;子系统为例,它定义了ldd_driver&nbsp;结构:&nbsp;struct&nbsp;ldd_driver&nbsp;{<br />char&nbsp;*version;<br />struct&nbsp;module&nbsp;*module;<br />struct&nbsp;device_driver&nbsp;driver;<br />struct&nbsp;driver_attribute&nbsp;version_attr;&nbsp;<br />};&nbsp;<br />#define&nbsp;to_ldd_driver(drv)&nbsp;container_of(drv,&nbsp;struct&nbsp;ldd_driver,&nbsp;driver);&nbsp;<br /><br /><br /><br />lddbus总线中相关的驱动注册和注销函数是:&nbsp;/*<br />*&nbsp;Crude&nbsp;driver&nbsp;interface.<br />*/<br />static&nbsp;ssize_t&nbsp;show_version(struct&nbsp;device_driver&nbsp;*driver,&nbsp;char&nbsp;*buf)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;ldd_driver&nbsp;*ldriver&nbsp;=&nbsp;to_ldd_driver(driver);<br />&nbsp;&nbsp;&nbsp;&nbsp;sprintf(buf,&nbsp;'%s<br />',&nbsp;ldriver-&gtversion);<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;strlen(buf);<br />}<br /><br />int&nbsp;register_ldd_driver(struct&nbsp;ldd_driver&nbsp;*driver)<br />{<br />int&nbsp;ret;<br />driver-&gtdriver.bus&nbsp;=&nbsp;&ldd_bus_type;<br />ret&nbsp;=&nbsp;driver_register(&driver-&gtdriver);/*注册底层的&nbsp;device_driver&nbsp;结构到核心*/<br />if&nbsp;(ret)<br />return&nbsp;ret;<br />driver-&gtversion_attr.attr.name&nbsp;=&nbsp;'version';/*&nbsp;driver_attribute&nbsp;结构必须手工填充*/<br />driver-&gtversion_attr.attr.owner&nbsp;=&nbsp;driver-&gtmodule;/*注意:设定&nbsp;version&nbsp;属性的拥有者为驱动模块,&nbsp;不是&nbsp;lddbus&nbsp;模块!因为&nbsp;show_version&nbsp;函数是使用驱动模块所创建的&nbsp;ldd_driver&nbsp;结构,若&nbsp;ldd_driver&nbsp;结构在一个用户空间进程试图读取版本号时已经注销,就会出错*/<br />driver-&gtversion_attr.attr.mode&nbsp;=&nbsp;S_IRUGO;<br />driver-&gtversion_attr.show&nbsp;=&nbsp;show_version;<br />driver-&gtversion_attr.store&nbsp;=&nbsp;NULL;<br />return&nbsp;driver_create_file(&driver-&gtdriver,&nbsp;&driver-&gtversion_attr);/*建立版本属性,因为这个属性在运行时被创建,所以不能使用&nbsp;DRIVER_ATTR&nbsp;宏*/<br />}<br /><br />void&nbsp;unregister_ldd_driver(struct&nbsp;ldd_driver&nbsp;*driver)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;driver_unregister(&driver-&gtdriver);<br />}<br />EXPORT_SYMBOL(register_ldd_driver);<br />EXPORT_SYMBOL(unregister_ldd_driver);<br /><br /><br /><br />在sculld&nbsp;中创建的&nbsp;ldd_driver&nbsp;结构如下:&nbsp;/*&nbsp;Device&nbsp;model&nbsp;stuff&nbsp;*/<br />static&nbsp;struct&nbsp;ldd_driver&nbsp;sculld_driver&nbsp;=&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;.version&nbsp;=&nbsp;'$Revision:&nbsp;1.21&nbsp;$',<br />&nbsp;&nbsp;&nbsp;&nbsp;.module&nbsp;=&nbsp;THIS_MODULE,<br />&nbsp;&nbsp;&nbsp;&nbsp;.driver&nbsp;=&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.name&nbsp;=&nbsp;'sculld',<br />&nbsp;&nbsp;&nbsp;&nbsp;},<br />};/*只要一个简单的&nbsp;register_ldd_driver&nbsp;调用就可添加它到系统中。一旦完成初始化,&nbsp;驱动信息可在&nbsp;sysfs&nbsp;中显示*/<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />类&nbsp;子系统<br /><br />类是一个设备的高层视图,&nbsp;它抽象出了底层的实现细节,从而允许用户空间使用设备所提供的功能,&nbsp;而不用关心设备是如何连接和工作的。类成员通常由上层代码所控制,&nbsp;而无需驱动的明确支持。但有些情况下驱动也需要直接处理类。<br /><br />几乎所有的类都显示在&nbsp;/sys/class&nbsp;目录中。出于历史的原因,有一个例外:块设备显示在&nbsp;/sys/block目录中。在许多情况,&nbsp;类子系统是向用户空间导出信息的最好方法。当类子系统创建一个类时,&nbsp;它将完全拥有这个类,根本不用担心哪个模块拥有那些属性,而且信息的表示也比较友好。<br /><br />为了管理类,驱动程序核心导出了一些接口,其目的之一是提供包含设备号的属性以便自动创建设备节点,所以udev的使用离不开类。&nbsp;类函数和结构与设备模型的其他部分遵循相同的模式,所以真正崭新的概念是很少的。<br /><br />注意:class_simple&nbsp;是老接口,在2.6.13中已被删除,这里不再研究。<br /><br />管理类的接口<br /><br />类由&nbsp;struct&nbsp;class&nbsp;的结构体来定义:<br /><br />/*<br />*&nbsp;device&nbsp;classes<br />*/<br />struct&nbsp;class&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;name;/*每个类需要一个唯一的名字,&nbsp;它将显示在&nbsp;/sys/class&nbsp;中*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;owner;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subsys;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;children;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;devices;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;interfaces;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class_dirs;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;semaphore&nbsp;&nbsp;&nbsp;&nbsp;sem;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;locks&nbsp;both&nbsp;the&nbsp;children&nbsp;and&nbsp;interfaces&nbsp;lists&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class_attribute&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;class_attrs;/*&nbsp;指向类属性的指针(以NULL结尾)&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class_device_attribute&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;class_dev_attrs;/*&nbsp;指向类中每个设备的一组默认属性的指针&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device_attribute&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;dev_attrs;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*uevent)(struct&nbsp;class_device&nbsp;*dev,&nbsp;char&nbsp;**envp,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;num_envp,&nbsp;char&nbsp;*buffer,&nbsp;int&nbsp;buffer_size);/*&nbsp;类热插拔产生时添加环境变量的函数&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*dev_uevent)(struct&nbsp;device&nbsp;*dev,&nbsp;char&nbsp;**envp,&nbsp;int&nbsp;num_envp,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;*buffer,&nbsp;int&nbsp;buffer_size);/*&nbsp;类中的设备热插拔时添加环境变量的函数&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;(*release)(struct&nbsp;class_device&nbsp;*dev);/*&nbsp;把设备从类中删除的函数&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;(*class_release)(struct&nbsp;class&nbsp;*class);/*&nbsp;删除类本身的函数&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;(*dev_release)(struct&nbsp;device&nbsp;*dev);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*suspend)(struct&nbsp;device&nbsp;*,&nbsp;pm_message_t&nbsp;state);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*resume)(struct&nbsp;device&nbsp;*);<br />};<br /><br /><br />/*类注册函数:*/<br />int&nbsp;class_register(struct&nbsp;class&nbsp;*cls);<br />void&nbsp;class_unregister(struct&nbsp;class&nbsp;*cls);<br /><br />/*类属性的接口:*/<br />struct&nbsp;class_attribute&nbsp;{<br />struct&nbsp;attribute&nbsp;attr;<br />ssize_t&nbsp;(*show)(struct&nbsp;class&nbsp;*cls,&nbsp;char&nbsp;*buf);<br />ssize_t&nbsp;(*store)(struct&nbsp;class&nbsp;*cls,&nbsp;const&nbsp;char&nbsp;*buf,&nbsp;size_t&nbsp;count);&nbsp;<br />};&nbsp;<br />CLASS_ATTR(_name,_mode,_show,_store);&nbsp;<br />int&nbsp;class_create_file(struct&nbsp;class&nbsp;*cls,&nbsp;const&nbsp;struct&nbsp;class_attribute&nbsp;*attr);<br />void&nbsp;class_remove_file(struct&nbsp;class&nbsp;*cls,&nbsp;const&nbsp;struct&nbsp;class_attribute&nbsp;*attr);<br /><br /><br />类设备<br /><br />类存在的真正目的是给作为类成员的各个设备提供一个容器,成员由&nbsp;struct&nbsp;class_device&nbsp;来表示:<br /><br />struct&nbsp;class_device&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;node;/*for&nbsp;internal&nbsp;use&nbsp;by&nbsp;the&nbsp;driver&nbsp;core&nbsp;only*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kobject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kobj;/*for&nbsp;internal&nbsp;use&nbsp;by&nbsp;the&nbsp;driver&nbsp;core&nbsp;only*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;class;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;指向该设备所属的类,必须*/<br />&nbsp;&nbsp;&nbsp;&nbsp;dev_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;devt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;dev_t,&nbsp;creates&nbsp;the&nbsp;sysfs&nbsp;'dev'&nbsp;,for&nbsp;internal&nbsp;use&nbsp;by&nbsp;the&nbsp;driver&nbsp;core&nbsp;only*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class_device_attribute&nbsp;*devt_attr;/*for&nbsp;internal&nbsp;use&nbsp;by&nbsp;the&nbsp;driver&nbsp;core&nbsp;only*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class_device_attribute&nbsp;uevent_attr;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;device&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;dev;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;指向此设备相关的&nbsp;device&nbsp;结构体,可选。若不为NULL,应是一个从类入口到/sys/devices&nbsp;下相应入口的符号连接,以便用户空间查找设备入口*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;class_data;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;私有数据指针&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class_device&nbsp;&nbsp;&nbsp;&nbsp;*parent;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;parent&nbsp;of&nbsp;this&nbsp;child&nbsp;device,&nbsp;if&nbsp;there&nbsp;is&nbsp;one&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;attribute_group&nbsp;**&nbsp;groups;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;optional&nbsp;groups&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;&nbsp;&nbsp;&nbsp;(*release)(struct&nbsp;class_device&nbsp;*dev);<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;(*uevent)(struct&nbsp;class_device&nbsp;*dev,&nbsp;char&nbsp;**envp,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;num_envp,&nbsp;char&nbsp;*buffer,&nbsp;int&nbsp;buffer_size);<br />&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;&nbsp;&nbsp;&nbsp;class_id[BUS_ID_SIZE];&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;此类中的唯一的名字&nbsp;*/<br />};<br /><br />/*类设备注册函数:*/<br />int&nbsp;class_device_register(struct&nbsp;class_device&nbsp;*cd);<br />void&nbsp;class_device_unregister(struct&nbsp;class_device&nbsp;*cd);<br /><br />/*重命名一个已经注册的类设备入口:*/<br />int&nbsp;class_device_rename(struct&nbsp;class_device&nbsp;*cd,&nbsp;char&nbsp;*new_name);&nbsp;<br /><br />/*类设备入口属性:*/<br />struct&nbsp;class_device_attribute&nbsp;{<br />struct&nbsp;attribute&nbsp;attr;<br />ssize_t&nbsp;(*show)(struct&nbsp;class_device&nbsp;*cls,&nbsp;char&nbsp;*buf);<br />ssize_t&nbsp;(*store)(struct&nbsp;class_device&nbsp;*cls,&nbsp;const&nbsp;char&nbsp;*buf,<br />size_t&nbsp;count);<br />};<br /><br />CLASS_DEVICE_ATTR(_name,&nbsp;_mode,&nbsp;_show,&nbsp;_store);&nbsp;<br /><br />/*创建和删除除struct&nbsp;class中设备默认属性外的属性*/<br />int&nbsp;class_device_create_file(struct&nbsp;class_device&nbsp;*cls,&nbsp;const&nbsp;struct&nbsp;class_device_attribute&nbsp;*attr);<br />void&nbsp;class_device_remove_file(struct&nbsp;class_device&nbsp;*cls,&nbsp;const&nbsp;struct&nbsp;class_device_attribute&nbsp;*attr);<br /><br /><br />类接口<br /><br />类子系统有一个&nbsp;Linux&nbsp;设备模型的其他部分找不到的附加概念,称为“接口”,&nbsp;可将它理解为一种设备加入或离开类时获得信息的触发机制,结构体如下:&nbsp;struct&nbsp;class_interface&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;list_head&nbsp;&nbsp;&nbsp;&nbsp;node;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*class;/*&nbsp;指向该接口所属的类*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;(*add)&nbsp;(struct&nbsp;class_device&nbsp;*,&nbsp;struct&nbsp;class_interface&nbsp;*);<br /><br />/*当一个类设备被加入到在&nbsp;class_interface&nbsp;结构中指定的类时,&nbsp;将调用接口的&nbsp;add&nbsp;函数,进行一些设备需要的额外设置,通常是添加更多属性或其他的一些工作*/<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*remove)&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;class_device&nbsp;*,&nbsp;struct&nbsp;class_interface&nbsp;*);/*一个接口的功能是简单明了的.&nbsp;当设备从类中删除,&nbsp;将调用remove&nbsp;方法来进行必要的清理*/<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;(*add_dev)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(struct&nbsp;device&nbsp;*,&nbsp;struct&nbsp;class_interface&nbsp;*);<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;(*remove_dev)&nbsp;(struct&nbsp;device&nbsp;*,&nbsp;struct&nbsp;class_interface&nbsp;*);<br />};<br /><br />/*注册或注销接口的函数:*/<br />int&nbsp;class_interface_register(struct&nbsp;class_interface&nbsp;*class_intf);<br />void&nbsp;class_interface_unregister(struct&nbsp;class_interface&nbsp;*class_intf);<br />/*一个类可注册多个接口*/
zcying 发表于 2009-4-9 14:59 | 显示全部楼层

Linux要学 的东西太多

  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

139

主题

185

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部