Linux内核文档翻译汇总.doc_第1页
Linux内核文档翻译汇总.doc_第2页
Linux内核文档翻译汇总.doc_第3页
Linux内核文档翻译汇总.doc_第4页
Linux内核文档翻译汇总.doc_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

我们的内核Linux内核文档翻译汇总-device model如果有任何疑问,请联系:Linux内核文档翻译汇总-device model1前言1Overview2Binding4Bus6Class9Device13Devres17Driver23Interface27Platform30Porting34前言我们翻译的第一批文档已经翻译出来了,我将这些文档整理到一起,方便大家阅读,下面的工作更加艰巨,就是如何校订我们的文档,保证我们的文档的权威性(准确性)。这不仅需要大家的努力,还需要我们制定良好的校订文档规则。下面是我制定的一些校订规则,如果有什么疑问欢迎各位补充:文档校订规则:0. 对进入校订期的文档,请翻译者将文档的最新版本在bbs上发帖公示。 在文档的点击率达到100,或者文档翻译完成一周后,翻译者可以准备,申请答辩,答辩必须在群中交流,根据 文档的大小确定答辩形式,在一致认为答辩通过后,标记为稳定版本。添加到发行版中。1. 答辩规则(一般情况,特殊情况另外说明) -1. 答辩者提前一周,在群中发表声明,说明自己的文章需要答辩,并告知负责人。 -2. chenyongbiao负责安排答辩时间,并发群邮件通知群成员,在群公告中发表公告。 -3. 答辩开始,答辩者做简单陈述(所翻译的文章概要)。 -4. 答辩组成员阅读文章,提出疑问(包括错别字,专用名词等)。 -5. 答辩完成,答辩者综合考虑答辩组成员的意见,整理文档。 -6. 将答辩完的文章公示,并注明已通过答辩,这阶段主要是让大家找文章中的错别字等。 -7. 公示一周后,文章正式添加进发行版。2. 文档提交。如果有任何疑问,请快联系我:,下一步我们将执行校订方案。Overview翻 译者:宙翰 Linux内核设备模型Patrick Mochel 起草于 2002年 8月26日于2006年1月31日更新概述Linux内核设备模型是对所有以前在内核中以前使用过的不同驱动模型的一种统一.它设是通过把一组数据和操作统一到全局可访问的数据结构中来为桥接器和设备增加总线专有驱动.传统的驱动模型给它所控制的设备实现了一系列的树形结构(有些仅仅是一个链表).他们在不同类型的总线设备上区别很大.现在的驱动模型给描述一种总线和会出现在这个总线下的设备提供了一种公共的,统一的数据模型.这种统一的总线模型包括了一组所有总线都有的公共属性和一组公共的回掉函数,例如能在总线枚举,总线关闭和总线电源管理.通用设备和桥接器接口也体现了现代计算机的目标:也就是实现设备的即插即用,电源管理和热插拔功能.特别是由Intel和Microsoft提出的的模型(即ACPI),它确保了几乎所有的设备能在和X86兼容的系统中大多数任意总线上使用.当然并不是每一个总线都能够支持所有这些操作,但几乎所有的总线支持大多数这样的操作.底层访问公共的数据项已经从单个总线中移到了公用数据结构中.当然总线层仍然可以访问这些域,有时也要可被设备专有驱动所访问.其它的总线层被用来做以前给PCI层所做的那些工作.pci_dev结构如下:复制内容到剪贴板代码:struct pci_dev . struct device dev;首先要注意的是这个结构是静态分配的.也就是说在发现设备时只会分配一个.另外要注意的是pci_dev结构末尾的device结构。这是用来防止编程者混淆device和pci_dev。PCI总线层可以自如的访问结构struct device中的各成员.要了解pci_dev这个数据结构,也应该知道devibe这个数据结构.已经被转换成当前驱动模型的单独的PCI设备驱动不要也不应该去动device结构中的成员,除非有强烈的令人信服的理由才去这么做.这种抽象是为了防止在过渡期间产生的不必要的麻烦.如果一个成员的名字变了或是被去除了,那所有底层的驱动将会不可用.另一方面来说,如果只有总线层(并不是设备层)访问device结构,那就只需修改需要修改的那一层即可.用户接口这种对系统中所有设备进行一种完全分层的组织的好处是可以相对容易的给用户空间提供一种完全分层次的设备关系图.通过实现一种称之谓sysfs的特殊的虚拟文件系统内核已经实现了这样的组织视图.因此用户就可以在用户空间的任意点挂载这个完整的sysfs文件系统.也可以把下面的语句添加到/etc/fstab中来实现挂载:复制内容到剪贴板代码:sysfs /sys sysfs defaults 0 0Or by hand on the command line:或者在命令行下敲如下的命令进行挂载:复制内容到剪贴板代码:# mount -t sysfs sysfs /sys无论何时在这个树上插入设备,内核都会为它创建一个目录.这个目录可能在每个层中出现比如全局层,总线层,或设备层.在全局层一般创建两个文件-name和power.只是列出了设备的名称.后一个是描述设备当前的电源状态.它通常被用来设置当前的电源状态.总线层也会为在探测时发现的设备创建文件.例如,PCI层一般会为每一个PCI设备创建irq和resource文件.特定设备的驱动程序也可能会在它的目录下通过创建文件来导出该设备的数据或提供调整的接口?更多关于sysfs目录布局的信息可以查阅当前文件夹中的其它文档和文件Documentation/filesystems/sysfs.txt.Binding原文作者:翻 译者: saltycookie 校 订者:版本状态:还未完成=驱动程序绑定驱动程序绑定是把设备与能够控制该设备的驱动程序关联的过程。典型的情况下,由总线驱动程序来处理绑定,因为每一种总线都有自己特定的结构体来表示设备和设备驱动。有了表示设备和设备驱动程序的通用结构体,大部分的绑定工作使用同样的代码就可以完成。总线表示总线类型的结构体包含了系统里面连接在这种总线上的所有设备的列表。为某个设备调用device_register的时候,该设备就被插到列表的末端。这个结构体里面也包含了总线上所有驱动程序的的列表。当为某个驱动程序调用dirver_register的时候,该驱动程序就被插到列表的末端。这两个事件触发了驱动程序绑定。device_register添加新设备的时候,系统扫描总线的驱动程序列表,试图找到支持该设备的驱动程序。如何确定驱动程序支不支持该设备呢?就看设备标识符(device ID)是不是与驱动程序支持的所有设备标识符的其中一个相匹配。设备标识符的格式和语义因总线而异。与其推导一个复杂的状态自动机和匹配算法,通常是交由总线驱动程序提供一个匹配设备和驱动程序的回调函数。如果匹配成功,回调函数返回1;否则返回0.int match(struct device * dev, struct device_driver * drv);如果匹配成功,系统将设备的driver域置为该驱动程序,并调用驱动程序的probe回调函数,以检测驱动程序是否确实支持这个硬件,同时确定设备是否处于工作状态。设备类型probe成功完成调用后,设备被注册到它所属的设备类型中。设备驱动程序属于唯一一个类型,记录在设备结构体的devclass域中。在设备类型的register_dev回调函数中,会调用devclass_add_device遍历该类型下的所有设备并注册该设备。注意:设备类型结构体以及操作它们的系统调用并不包含在主流的内核中,所以我们这里的讨论多少有点推测的味道。驱动程序当驱动程序关联到设备上时,该设备被插到驱动程序的设备列表中。sysfs驱动程序绑定后:在总线的devices目录下面创建一个指向该设备的物理目录的符号链接。在驱动程序的devices目录下面创建一个指向该设备的物理目录的符号链接。在设备类型的目录下创建一个设备目录,并与该设备在sysfs中的物理位置建立符号链接。也可建立从设备的物理目录到它的设备类型目录或者类型根目录,以及到它的驱动程序目录的符号链接,不过现在还没有这么做。driver_register注册驱动程序的过程与添加新设备几乎是一样的。系统对总线的设备列表进行遍历以发现匹配的设备,并将尽可能多的设备绑定到该驱动程序上。已经有驱动程序的设备会被忽略。删除设备和驱动程序删除设备时,驱动程序的remove回调函数被调用,将设备从它的设备列表中删除,并将设备的引用数减1,直至引用数减到为止。两者之间的所有符号链接也被删除。删除驱动程序时,必须对它所支持的所有设备进行遍历,对每个设备调用驱动程序的remove回调函数。设备从驱动程序的设备列表中删除,两者之间的所有符号链接也被删除。Bus原文作者:翻 译者:校 订者:版本状态:还未完成=总线类型定义struct bus_type char* name;struct subsystemsubsys;struct ksetdrivers;struct ksetdevices;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);声明内核中每一种总线类型(如PCI, USB等)都应该声明一个与之对应的静态对象。必须初始化name域,并可选择性的初始化match回调函数。struct bus_type pci_bus_type = .name= pci, .match= pci_bus_match,;这个结构体应该通过一个头文件向驱动程序开放:extern struct bus_type pci_bus_type;注册通过调用bus_register函数来初始化驱动程序。这个函数初始化总线对象的其余成员变量,并把它插入到一个全局的总线类型链表种。一旦这个总线对象被注册,总线驱动就可以使用总线对象的成员。回调函数match(): 关联驱动程序到设备match回调函数通过比较特定设备的设备标识与驱动程序支持的设备标识为总线提供这个驱动程序是否支持这个特定的设备的判断机会。这种方式没有牺牲总线私有属性或类型安全。当向总线注册一个驱动时,系统遍历总线的设备链表,并为每个无驱动程序关联的设备调用match回调函数。设备与驱动程序链表设备链表和驱动程序链表是用来替代大多总线持有的本地链表。它们分别是struct device和struct device_driver结构的链表。总线驱动可以随心所欲的使用这些链表,但可能需要转换为总线私有的数据类型。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导出属性struct bus_attribute struct attributeattr;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原文作者:翻 译者: 王翔 校 订者:版本状态:Request for comment!=设备类介绍一个设备类描述了一种类型的设备,比如说是声音或者是网络设备。随后的设备类是这样定义的:每一个设备类都定义了一系列的语意和一个与该类对应的设备所要遵循的编程接口。设备的驱动就是这个编程接口的实现,用于驱动在特定总线上工作的特定设备。设备工作在什么总线上,对于设备类是不可知的。 编程接口设备类的结构可能会是这样的:typedef int (*devclass_add)(struct device *);typedef void (*devclass_remove)(struct device *);struct device_class char* name;rwlock_tlock;u32devnum;struct list_headnode;struct list_headdrivers;struct list_headintf_list;struct driver_dir_entrydir;struct driver_dir_entrydevice_dir;struct driver_dir_entrydriver_dir;devclass_addadd_device;devclass_removeremove_device;一个典型的设备类的定义可能会是这样的:struct device_class input_devclass = .name= input, .add_device= input_add_device,.remove_device= input_remove_device,;每一个设备类的结构应该被导出在一个头文件里面,以便被驱动程序,扩展程序和接口使用。使用以下的语句,实现设备类的注册和撤销:int devclass_register(struct device_class * cls);void devclass_unregister(struct device_class * cls);Devices设备当设备与驱动程序绑定了后,它们就被添加到了驱动程序所属的设备类里面去。在驱动模型内核(这里不知道怎么翻译比较好)问世之前,当设备被初始化了后,这一个添加的操作一般都是在驱动程序在回调probe()的时候发生的。但是现在,添加操作是在内核中回调了probe()后发生的。在类中,设备会被枚举出来。每一次设备被加入到类中,类的devnum数据项的值就会就增加,并且将会被指定给设备。但是这个数据项的值永远不会减少,也就是说,如果设备从类中移除出去,又重新添加,它将会接受到一个不同的枚举值。类被允许用来为设备创建一个明确的数据结构,并且使用使用一个设备的class_data指针来指向这个数据结构。在设备类中,不存在设备的列表。每一个驱动程序都有它支持的设备的列表。设备类拥有都有一个驱动程序的列表。要访问类中的全部驱动程序,遍历类中每个驱动程序的设备列表即可。设备驱动程序当设备被内核注册的时候,设备的驱动程序就添加到了设备的类中去。驱动程序通过设置结构device driver:devclass字段来指明这是什么类。文件系统目录结构存在一个顶级的文件系统目录,名称为:class每一个类都在class文件夹里面拥有一个目录,下面还有两个默认的子文件夹: class/ - input |- devices - drivers通过类来注册的驱动程序,在drivers/目录下有一个符号连接,指向了驱动程序的文件夹(在它的bus目录下): class/ - input |- devices - drivers - usb:usb_mouse - ./././bus/drivers/usb_mouse/每一个设备都在devices/目录下面有一个符号连接,指向了设备的物理层次的文件夹: class/ - input |- devices | - 1 - ./././root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/ - drivers导出属性struct devclass_attribute struct attribute attr; ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off); ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);类驱动程序可以使用DEVCLASS_ATTR宏来导出属性,工作方式和DEVICE_ATTR相似。例如,一个定义可以是这样的:static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);与如下声明的效果是一样的:static devclass_attribute devclass_attr_debug;总线的驱动可以从类的文件系统目录中添加或者或者删除属性,方法如下:int devclass_create_file(struct device_class *, struct devclass_attribute *);void devclass_remove_file(struct device_class *, struct devclass_attribute *);在上面的例子中,在文件系统的类的文件夹中,文件将会被命名为debug。接口存在着多种用于访问特定设备类类型的同种设备的机制。设备的接口描述了这些机制。当一个设备被添加到了设备类中后,内核尝试将设备添加到每一个接口中去。Device原文作者:翻 译者: Solarapex 校 订者:版本状态:还未完成=基本设备结构体代码:struct device struct list_head g_list; struct list_head node; struct list_head bus_list; struct list_head driver_list; struct list_head intf_list; struct list_head children; struct device *parent; char nameDEVICE_NAME_SIZE; char bus_idBUS_ID_SIZE; spinlock_t lock; atomic_t refcount; struct bus_type * bus; struct driver_dir_entry dir; u32 class_num; struct device_driver *driver; void *driver_data; void *platform_data; u32 current_state; unsigned char *saved_state; void (*release)(struct device * dev);域g_list: 全局设备列表中的节点.node: 父设备的孩子列表中的节点.bus_list: 设备从属的总线所属的设备列表中的节点.driver_list: 设备对应的驱动所属的设备列表中的节点.intf_list: intf_data列表. 对每个该设备所支持的接口, 程序会分配一个结构体.children: 子设备列表.parent: * 待修正 *name: 设备描述(用ASCII码).例: 3Com Corporation 3c905 100BaseTX Boomerangbus_id: 设备总线的位置描述(用ASCII码). 此设备从属的总线下的所有设备应对应唯一的描述符.例: PCI总线bus_id的格式为:系统中所有PCI设备的bus_id都对应上述同一个名字.lock: 设备的自旋锁(spinlock). (译注: 在自旋锁中, 线程简单地循环等待并检查, 直到锁可用.)(xlp补注: 在UP(uni processor)情况下,spinlock就是简单的清中断(CLI)和设中断(SEI).在SMP情况下,spinlock_lock是循环检测锁,可用后获取锁,spinlock_unlock是直接释放锁).refcount: 设备引用的数量.bus: 指向设备所属总线的bus_type结构体的指针.dir: 设备的sysfs目录.(译注: sysfs是Linux 2.6提供的虚拟文件系统. sysfs从内核设备模型中向用户空间导出设备及驱动的信息. 它也被用来进行配置.)class_num: 设备的Class-enumerated值.driver: 指向设备驱动程序结构体device_driver的指针.driver_data: 驱动相关的数据.platform_data: 设备所在平台的数据.例: 对嵌入式或片上系统(SOC)这类用户自定义板上的设备, Linux常使用platform_data指向一个针对板的结构体, 来描述设备以及设备间的连线.这样一个结构体中可能包含可用的端口, 芯片参数, GPIO针扮演的额外角色等等. 它可以缩小板支持包(Board Support Packages, BSP)的体积并减少驱动中针对板的#ifdef的数量.current_state: 设备当前电源状态.saved_state: 指向设备已保存的状态的指针. 驱动可以利用它来控制设备,release: 当所有设备引用都撤销后用来释放设备的回调函数. 它应由为设备分配空间的程序(也就是发现这个设备的总线驱动)来设置.编程接口发现设备的总线驱动程序用下列接口来向核心注册该设备:代码:int device_register(struct device * dev);总线负责初始化下列域: - parent - name - bus_id - bus当设备引用减为零时, 设备就被从核心删除. 设备引用数可由下列接口调整:代码:struct device * get_device(struct device * dev);void put_device(struct device * dev);如果设备引用数不为零(即便是在设备正在被卸载的过程中), get_device将返回一个指针, 该指针指向设备传回的一个结构体.驱动程序可以通过下列接口访问设备结构体中的锁:代码:void lock_device(struct device * dev);void unlock_device(struct device * dev);属性代码:struct device_attribute struct attribute attr; ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off); ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);使用一个简单的类似procfs的接口,便可以通过驱动程序导出设备属性(译注: procfs是process file system的缩写, 它是一个启动时建立的伪文件系统, 用来访问内核中的进程信息. 该文件系统通常被挂载到/proc下. 它因为不是真实的文件系统, 所以只消耗少量内存, 而不占存储空间)关于sysfs如何工作的信息, 请参阅Documentation/filesystems/sysfs.txt属性用宏DEVICE_ATTR来声明:代码:#define DEVICE_ATTR(name,mode,show,store)例:代码:DEVICE_ATTR(power,0644,show_power,store_power);上句声明了一个叫做dev_attr_power的设备属性结构体. 此结构体可以用下列接口添加到设备或同设备删除:代码:int device_create_file(struct device *device, struct device_attribute * entry);void device_remove_file(struct device * dev, struct device_attribute * attr);例:代码:device_create_file(dev,&dev_attr_power);device_remove_file(dev,&dev_attr_power);文件名和模式将分别是power和0644(-rw-r-r-).Devres原文作者:Tejun Heo翻 译者:Henry 校 订者:版本状态:已完成=Devres - 设备资源管理=Tejun Heo于2007年1月10号第一次起草1.简介 : 嘿? Devres(设备资源)?2.Devres(设备资源) : 果壳里的Devres(设备资源)3.Devres(设备资源)组 : 聚集Devres(设备资源)和释放Devres(设备资源)4.详细内容 : 生命周期规则,调用上下文, .5.费用 : 我们必须为此付出多大的代价?6.管理级别的接口列表: 现有的已被实现的管理级别的接口1.简介-当你正试着用IO映射来转化libata, devres(设备资源)就产生了。每个被IO映射的地址都应该被保存起来,而当驱动被卸载时都应该变成未映射的。举个例子来说,一个简单的SFF ATA控制器(就是那种很经典的PCI IDE)在本地模式需要使用五个PCI BARS,并且所有的PCI BARS都需要被维护。就和大多数其他的设备驱动一样,在-remove和-probe失败路径里libata底层驱动也有很多的漏洞。是的,那也许是因为libata底层驱动开发者们都是一群懒家伙,但是是不是所有的底层开发者都是这样呢?在没有任何关于Braindamaged的文档的情况下,我花了一天的时间来折腾Braindamaged硬件,最后它成功的工作了。出于某种原因,我们并没有像测试核心代码一样来测试底层驱动,并且一些在驱动卸载时发生的漏洞以及一些初始化失败也没能引起我们的注意。而关于初始化失败的路径则是更加糟糕,因为它需要应付多个入口点,更不用说完全遍历了。所以,许多底层驱动都会在卸载时产生资源泄露,一半的失败原因都是在实现probe()时导致的,当它执行失败后就会产生泄露,也许还会产生更加意想不到的错误。IO映射添加了更多与probe()的结合,当然也包括msi和msix。2. Devres(设备资源)-设备资源从根本上说就是一个占着内存的由设备结构体连接而成的链表。每个设备资源入口都与一个释放资源的函数相关联。一个设备资源能通过多种方式来释放。不管是那一种方式,所有的设备资源入口都应该在驱动被卸载时而释放掉。释放资源时,相关联的释放函数就会被应用,并且设备资源入口也会被释放掉。设备驱动使用资源时,管理级别接口就会被创建用来使用设备资源。举例来说,使用dma_alloc_coherent()来获得连续的DMA内存。这个管理级别的版本被称作dmam_alloc_coherent()。它和dma_alloc_coherent()功能大致一样,除了DMA内存分配时使用它来管理,并且在卸载时自动释放所分配的内存。实现看起来和下面相似:struct dma_devres size_t size; void *vaddr; dma_addr_t dma_handle; static void dmam_coherent_release(struct device *dev, void *res) struct dma_devres *this = res; dma_free_coherent(dev, this-size, this-vaddr, this-dma_handle);dmam_alloc_coherent(dev, size, dma_handle, gfp) struct dma_devres *dr;void *vaddr;dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp);./* alloc DMA memory as usual */vaddr = dma_alloc_coherent(.);. /* record size, vaddr, dma_handle in dr */dr-vaddr = vaddr;.devres_add(dev, dr);return vaddr; 如果一个驱动使用dmam_alloc_coherent(), 那么被分配的区域都会保证被释放不管是否是中途初始化失败还是驱动被卸载。如果大多数的资源都是用管理级别的接口来获得,那么一个驱动在编写初始化和退出代码时就会显得更加简单。初始化路径看起来大概和下面很像:my_init_one() struct mydev *d;d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);if (!d)return -ENOMEM;d-ring = dmam_alloc_coherent(.);if (!d-ring)return -ENOMEM;if (check something)return -EINVAL;.return register_to_upper_layer(d); 退出时:my_remove_one() unregister_from_upper_layer(d);shutdown_my_hardware(); 就像上面写的那样,底层驱动在使用设备资源的时候更加简单化。在维护底层驱动时也会更加容易。当然,当初始化失败路径被退出路径所共享时,两者都需要更多的测试。3. 设备资源组-设备资源入口可以用设备资源组来集中起来。当一个组被释放时,所有被包含的设备资源入口以及被嵌套的组都会被释放。一个习惯是当获取资源失败时就回滚到之前的状态。举例如下: if (!devres_open_group(dev, NULL, GFP_KERNEL)return -ENOMEM; acquire A; if (failed)goto err; acquire B; if (failed)goto err; . devres_remove_group(dev, NULL); return 0; err: devres_release_group(dev, NULL); return err_code;通常当资源获取失败时就意味着probe失败,像上面的架构通常在中间层驱动(就像libata核心层)上是十分有用的,这样也不会在失败时引起所谓的边际效应。对于LLDs,在大多数例子中仅仅是返回错误代码就已经足够了。每一个组被一个void*id所标识。它既可以显式的通过devres_open_group()中的参数id来指定,也可以像上面的例子一样通过传递一个NULL给void *id来自动创建。这两种方式,devres_open_group()都会返回一个组id。这个被返回的ID可以被传递给其他的设备资源函数用来选择目标组。如果NULL参数指定给那些函数,那么最近打开的组将会被选择。举例来说,你可以

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论