typedef structt为什么减少总线

STM32 can总线库函数 uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct);_百度知道
STM32 can总线库函数 uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct);
这个函数不是一个带返回值的函数吗,可我看很多的例程里面使用的时候并没有返回值,是怎么回事?
我有更好的答案
这么定义必须有返回值。
为您推荐:
其他类似问题
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。【图文】linux设备驱动-总线设备和驱动_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
linux设备驱动-总线设备和驱动
&&linux设备驱动-总线设备和驱动
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢博客访问: 32615
博文数量: 18
博客积分: 290
博客等级: 二等列兵
技术积分: 256
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX 20:32:38
设备模型之二&总线设备驱动&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&2012-04-19
一、概要分析&&&&&Linux设备模型中三个很重要的概念就是总线、设备和驱动,即bus,device和driver。它们分别对应的数据结构分别为struct&bus_type,struct&device和struct&device_driver。&&&&总线是处理器与一个或多个设备之间的通道,在设备模型中,所有的设备都通过总线相连。在最底层,Linux系统中的每一个设备都用device结构的一个实例来表示。而驱动则是使总线上的设备能够完成它应该完成的功能。
&&&&在系统中有多种总线,如PCI总线、SCSI总线等。系统中的多个设备和驱动是通过总线让它们联系起来的。在bus_type中两个很重要的成员就是&struct&kset&drivers和struct&kset&devices【&在2.6.32.2中已被&struct&bus_type_private&结构包含&】。它分别代表了连接在这个总线上的两个链,一个是设备链表,另一个则是设备驱动链表。也就是说,通过一个总线描述符,就可以找到挂载到这条总线上的设备,以及支持该总线的不同的设备驱动程序。
1.1&bus_type&相当于一个容器,是device&和device_driver&的管理机构,它&&
包含了一个device&集合(kset)和一个device_driver&集合(kset),分别表&
示挂在这个总线下的所有设备和所有设备驱动程序。
1.2&device_driver&挂在某个bus_type&下面,包含了一个device&集合(kset),
表示这个驱动程序操作(或控制)的所有设备。device_driver&还包含一个&
bus_type&指针,表示驱动程序所在的总线。
1.3&device&挂在某个bus_type&下面,包含了一个device_driver&指针,表示&&&
这个设备对应的设备驱动程序。device&还包含一个bus_type&指针,表示&
设备所在的总线。需要说明的是,一个实际的总线在设备驱动模型中是用两&
个结构表示的:bus_type&和device。bus_type&代表总线类型,出现在
/sys/bus/目录下;device&代表总线设备,出现在/sys/devices/录下,这
表明实际的总线本质上是一种设备。
1.2&总线、设备与驱动的绑定&&&&在系统启动时,它会对每种类型的总线创建一个描述符,并将使用该总线的设备链接到该总线描述符的devices链上来。也即是说在系统初始化时,它会扫描连接了哪些设备,并且为每个设备建立一个struce&device变量,然后将该变量链接到这个设备所连接的总线的描述符上去。另一方面,每当加载了一个设备驱动,则系统也会准备一个struct&device_driver结构的变量,然后再将这个变量也链接到它所在总线的描述符的drivers链上去。&&&&&&&&&&&对于设备来说,在结构体struct&device中有两个重要的成员,一个是struct&bus_type&*bus,另一个是struct&device_driver&*driver。bus成员就表示该设备是链接到哪一个总线上的,而driver成员就表示当前设备是由哪个驱动程序所驱动的。对于驱动程序来说,在结构体struct&device_driver中也有两个成员,struct&bus_type&*bus和struct&list_head&devices,这里的bus成员也是指向这个驱动是链接到哪个总线上的,而devices这个链表则是表示当前这个驱动程序可以去进行驱动的那些设备。一个驱动程序可以支持一个或多个设备,而一个设备则只会绑定给一个驱动程序。&&&&&对于device与device_driver之间建立联系的方式,主要有两种方式。第一种,在计算机启动的时候,总线开始扫描连接在其上的设备,为每个设备建立一个struct&device变量并链接到该总线的devices链上,然后开始初始化不同的驱动程序,驱动程序到它所在的总线的devices链上去遍历每一个还没有被绑定给某个驱动的设备,然后再查看是否能够支持这种设备,如果它能够支持这种设备,则将这个设备与这个驱动联系起来。即,将这个设备的device变量加到驱动的devices链上,同时让struct&device中的device_driver指向当前这个驱动。第二种则是热插拔。也即是在系统运行时插入了设备,此时内核会去查找在该bus链上注册了的device_driver,然后再将设备与驱动联系起来。
1.3&Question:
a)设备与驱动根据什么规则联系起来?
b)驱动程序/设备如何找到总线设备的?
以后内容采用&2.6.32.2&内核,有一些跟以前不一样。以后采用使用方法形式来说明:(例子在device_module文件夹中)总线设备驱动操作方法非常的类似,我主要以bus进行说明而已。设备和驱动主要按照bus方法进行操作即可。
二、总线bus
第一步:定义数据结构
【NOTE】很少&bus_type&成员要求初始化;&大部分由设备模型核心处理.&但是,&我们确实不得不指定总线的名子,&以及任何伴随它的方法。
struct&bus_type&{
& const&char *&&&&&&&&&&&&/*总线名称*/
& struct&bus_attribute *bus_&&&&&&&&&/*总线属性*/
& struct&device_attribute *dev_&&&&&/*设备属性*/
& struct&driver_attribute *drv_&&&&&/*驱动属性*/
&&int&(*match)(struct&device&*dev,&struct&device_driver&*drv);
& int&(*uevent)(struct&device&*dev,&struct&kobj_uevent_env&*env);
& int&(*probe)(struct&device&*dev);
& int&(*remove)(struct&device&*dev);
& void&(*shutdown)(struct&device&*dev);
& int&(*suspend)(struct&device&*dev,&pm_message_t&state);
& int&(*resume)(struct&device&*dev);
& const&struct&dev_pm_ops&*
&&struct&bus_type_private&*p;&&&&&&&&&&&&/*总线类型的私有数据*/&&&&&&&&&
struct&bus_type_private&{
& struct&kset&&&&&&&&&&&&&&&&&&&/*与该总线相关的子系统*/
& struct&kset&*drivers_&&&&&&&&&&&/*总线驱动程序的KSET*/
& struct&kset&*devices_&&&&&&&&&&&/*挂载在总线上的设备KSET*/
& struct&klist&klist_&&&&&&&&&&/*挂载在总线上的设备链表*/&&&
& struct&klist&klist_&&&&&&&&&&&/*驱动程序链表*/
& struct&blocking_notifier_head&bus_
& unsigned&int&drivers_autoprobe:1;
& struct&bus_type&*
Q1:后来注册的设备\驱动如何添加到&struct&kset&*devices_kset&、struct&kset&*drivers_kset?
Q2:后来注册的设备\驱动如何寻找到总线?
第二步:实现总线方法
&& int&(*match)(struct&device&*device,&struct&device_driver&*driver);&&
&& 这个方法被调用,&大概多次,&无论何时一个新设备或者驱动被添加给这个总线.&它应当返回一个非零值如果给定的设备可被给定的驱动处理.&(我们马上进入设备和&device_driver&结构的细节).&这个函数必须在总线级别处理,&因为那是合适的逻辑存在的地方;&核心内核不能知道如何匹配每个可能总线类型的设备和驱动.&
int&(*uevent)&(struct&device&*device,&char&**envp,&int&num_env&p,&char&*buffer,&int&buffer_size);&&
这个模块允许总线添加变量到环境中,&在产生一个热插拔事件在用户空间之前。
第三步:注册总线
int&bus_register(struct&bus_type&*bus);&
注册总线一定要检查其返回值,可能会注册失败。
/*退出时注销总线*/
void&bus_unregister(struct&bus_type&*bus);&&
第四步:创建总线属性文件==>用于与空间进行交互
Q:如何将传送进去的&buf&跟内核交互==>读出的buf&哪里来,写入的&buf&要到哪里去?
struct&bus_attribute&{
& struct&attribute
& ssize_t&(*show)(struct&bus_type&*bus,&char&*buf);
& ssize_t&(*store)(struct&bus_type&*bus,&const&char&*buf,&size_t&count);
#define&BUS_ATTR(_name,&_mode,&_show,&_store) \
& struct&bus_attribute&bus_attr_##_name&=&__ATTR(_name,&_mode,&_show,&_store)
& int&bus_create_file(struct&bus_type&*bus,&struct&bus_attribute&*attr);
&/*删除属性文件*/
& void&bus_remove_file(struct&bus_type&*bus,&struct&bus_attribute&*attr);&&
三、设备device
struct&device&{
& struct&device *&&&&&&&/*父设备*/
& struct&device_private *p;&&&&&&&/*设备结构的私有数据*/
& struct&kobject&&&&&&&&&&&&&&&/*kobject对象*/
& const&char *init_&&&&&/*设备初始化名字替换了&bus_id&*/
& struct&device_type *&&&/*设备方法==>类似于&kobject_ktype*/&
& struct&semaphore
&&&&&&/*信号量*/
& struct&bus_type * &&/*设备所在的总线*/
& struct&device_driver&*/*该设备的驱动,怎样跟驱动匹配呢?*/
& void *platform_ &&&&&&/*平台总线私有数据*/
& struct&dev_pm_info
#ifdef&CONFIG_NUMA
&& int numa_ /*&NUMA&node&this&device&is&close&to&*/
&& u64 *dma_ /*&dma&mask&(if&dma'able&device)&*/
&& u64 coherent_dma_
&& struct&device_dma_parameters&*dma_
&& struct&list_head dma_ /*&dma&pools&(if&dma'ble)&*/
&& struct&dma_coherent_mem *dma_&
&& struct&dev_archdata
/*&dev_t,&creates&the&sysfs&"dev"&*/
&& spinlock_t devres_
&& struct&list_head devres_
&& struct&klist_node knode_
&& struct&class *
&& const&struct&attribute_group&**
&& void (*release)(struct&device&*dev);&/*为何必须有呢?没有行吗*/
struct&device_private&{
&& struct&klist&klist_
&& struct&klist_node&knode_
&& struct&klist_node&knode_
&& struct&klist_node&knode_
&& void&*driver_&&&&&&&&&&&&&&&&&&&/*我们所关心的数据*/
&& struct&device&*
Q1:利用结构中的kobject&跟&kset&进行关联。
Q2:在进行设备注册时,就将设备添加到总线中去,利用bus_add_device(dev)&实现的。
大家可以去&drivers/base/core.c&看源代码int&device_register(struct&device&*dev){&&&&device_initialize(dev);&&&&&&&&&&&&&&&//初始化设备&&&&return&device_add(dev);&&&&&&&&&&&&&&//添加设备}void&device_initialize(struct&device&*dev){
&&&&&*设置设备的kobject所属集合,利用了kobject&挂载到devices_kset其&&
&&&&&*实在第一层,sys/devices/...&而在sys/bus/xxx&目录下是个链接文件&&&&&*/&&&&dev->kobj.kset&=&devices_&&&&&&&&&&&&&
kobject_init(&dev->kobj,&&device_ktype);&&&&//初始化设备的kobject&
INIT_LIST_HEAD(&dev->dma_pools);//初始化设备的DMA池,用于传大数&&&&mutex_init(&dev->mutex);&&&&&&&&&&&&&&&&&//初始化互斥锁&&&&lockdep_set_novalidate_class(&dev->mutex);&&&&spin_lock_init(&dev->devres_lock);&&&&&//初始化自旋锁,用于同步子设备链表&&&&INIT_LIST_HEAD(&dev->devres_head);&&&&&&//初始化子设备链表头&&&&device_pm_init(dev);&&&&set_dev_node(dev,&-1);}int&device_add(struct&device&*dev){&&&&&&&...&&&&&&&&&&&&&&&&&&error&=&device_private_init(dev);&&&&&&&//初始化设备的私有成员&&&&&&...&&&&&parent&=&get_device(dev->parent);&&&&&&&&&//增加父设备kobject的引用&&&&&setup_parent(dev,&parent);&&&&&&&&&&&&&//设置该设备kobject父对象&&&&&&...&&&&&error&=&kobject_add(&dev->kobj,&dev->kobj.parent,&NULL);&//将设备kobject添加进父对象设备模型
&&&&&&...&&&&&&error&=&bus_add_device(dev);&&&&&&&&&&//将设备添加进总线中
...&&&&&&bus_probe_device(dev);&&&&&&&&&&&&//现在该为设备在总线上寻找合适的驱动了&&&&...}&&&&到了这里就将上面的几个问题给解决了,这对于驱动也是类似的在这里就总结一下一个设备添加和删除过程:当在总线上添加(或删除)设备时,会依次遍历总线上的所有驱动程序,调用总线定义的match()方法检查要加入(或删除)的设备是否和驱动程序“匹配”,如果匹配成功,则对设备调用总线或驱动程序中定义的probe(或remove)方法。添加设备时产生KOBJ_ADD&uevent,删除设备时产生KOBJ_REMOVE&uevent。
设备添加流程:
device_register(dev)->device_add(dev)->&kobject_uevent(KOBJ_ADD)
device_add(dev)->bus_attach_device(dev)->device_attach(dev)
->__device_attach(drv,dev)->bus_type():match(dev,drv)
then&->driver_probe_device()->really_probe()
->bus_type:probe()或device_driver:probe()
device_unregister(dev)->device_del(dev)->bus_remove_device(dev)
->device_release_driver(dev)&->__&device_release_driver(dev)
->bus_type:remove()或device_driver:remove()
device_del(dev)->kobject_uevent(KOBJ_REMOVE)&
&四、驱动driver
&(1)添加驱动程序&driver_register(drv)->&bus_add_driver&(drv)->&driver_attach(drv)&->__driver_attach(dev,drv)&->bus_type():match(dev,drv)&then->driver_probe_device()->really_probe()->bus_type:probe()&device_driver:probe()
&driver_register(drv)->&kobject_uevent(KOBJ_ADD)&(2)&驱动程序删除&&driver_unregister(dev)->bus_remove_driver(drv)->&driver_detach(drv)&->__&device_release_driver(dev)&[dev-drv&管理的所有设备]&->bus_type:remove()&或device_driver:remove()&
五、内嵌的设备和驱动&【linux设备驱动程序第三版】&&&&&设备结构包含设备模型核心需要的来模型化系统的信息.&大部分子系统,&但是,&跟踪关于它们驻留的设备的额外信息.&结果,&对设备很少由空设备结构所代表;&相反,&这个结构,&如同&kobject&结构,&常常是嵌入一个更高级的设备表示中.&如果你查看&struct&pci_dev&&的定义或者&struct&usb_device&的定义,&你会发现一个&struct&device&埋在其中.&常常地,&低层驱动甚至不知道&struct&device,&但是有例外.&lddbus&驱动创建它自己的设备类型(&struct&ldd_device&)&并且期望单独的设备驱动来注册它们的设备使用这个类型.&它是一个简单结构:&
struct&ldd_device&{&
&struct&ldd_driver&*&
&struct&device&&&
#define&to_ldd_device(dev)&container_of(dev,&struct&ldd_device,&dev);&&
这个结构允许驱动提供一个实际的名子给设备(&这可以清楚地不同于它的总线&ID,&存储于设备结构)&以及一个这些驱动信息的指针.&给真实设备的结构常常还包含关于供应者信息,&设备型号,&设备配置,&使用的资源,&等等.&可以在&struct&pci_dev&()&或者&struct&usb_device&()&中找到好的例子.&一个方便的宏(&to_ldd_device&)&也为&struct&ldd_device&定义,&使得容易转换指向被嵌入的结构的指针为&ldd_device&指针.&
lddbus&输出的注册接口看来如此:&
int&register_ldd_device(struct&ldd_device&*ldddev)&&
&ldddev->dev.bus&=&&ldd_bus_&
&ldddev->dev.parent&=&&ldd_&
&ldddev->dev.release&=&ldd_dev_&
&strncpy(ldddev->dev.bus_id,&ldddev->name,&BUS_ID_SIZE);&
&return&device_register(&ldddev->dev);&&
EXPORT_SYMBOL(register_ldd_device);&
这里,&我们简单地填充一些嵌入的设备结构成员(&单个驱动不应当需要知道这个&),&并且注册这个设备到驱动核心.&如果我们想添加总线特定的属性到设备,&我们可在这里做。如同大部分驱动核心结构的情形,&device_driver&结构常常被发现嵌到一个更高级的,&总线特定的结构.&lddbus&子系统不会和这样的趋势相反,&因此它已定义了它自己的&ldd_driver&结构:&
struct&ldd_driver&{&
&struct&module&*&
&struct&device_driver&&
&struct&driver_attribute&version_&&
#define&to_ldd_driver(drv)&container_of(drv,&struct&ldd_driver,&driver);&&
这里,&我们要求每个驱动提供特定当前软件版本,&并且&lddbus&输出这个版本字串为它知道的每个驱动.&总线特定的驱动注册函数是:&
int&register_ldd_driver(struct&ldd_driver&*driver)&
&driver->driver.bus&=&&ldd_bus_&
&ret&=&driver_register(&driver->driver);&
&if&(ret)&
&driver->version_attr.attr.name&=&"version";&
&driver->version_attr.attr.owner&=&driver->&
&driver->version_attr.attr.mode&=&S_IRUGO;&
&driver->version_attr.show&=&show_&
&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);&
有些来源于各位大侠博客:
阅读(2708) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
请登录后评论。以下试题来自:
单项选择题设有以下C语言说明语句。
int x,y; s[2]=1,2),3,4),*p=s,*q=s;
则表达式++p->x和表达式(++q)->x的值分别为 (34) 。A.1、1B.1、3C.2、3D.3、3
为您推荐的考试题库
你可能感兴趣的试题
1A.数据总线、串行总线、逻辑总线、物理总线B.逻辑总线、物理总线、并行总线、地址总线C.并行总线、串行总线、全双工总线D.数据总线、地址总线、控制总线2A.根据IP地址对数据包进行过滤B.为系统访问提供更高级别的身份认证C.安装防病毒软件D.使用工具软件检测不正常的高流量3A.确定性B.健壮性C.有穷性D.可靠性4A.172.30.0.1B.172.30.1.13C.0x30002D.00-10-db-92-00-315A.ASPB.HTMLC.HTTPSD.URL
热门相关试卷
最新相关试卷他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 python struct.pack 的文章

 

随机推荐