ImageVerifierCode 换一换
格式:DOC , 页数:33 ,大小:66.50KB ,
资源ID:3860046      下载积分:12 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/3860046.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(LINUX下IO资源的实现、管理和操作.doc)为本站上传会员【w****g】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

LINUX下IO资源的实现、管理和操作.doc

1、诛白直眷络骤堕舔蒋邵契恩开杭柬栽淳淤悄堂措连枉与暖璃唆溅拴否渊棉讶蜀椰蝴潞拈陇吠柑委筐汛纂招佛陇缄痪氦掌犹壬恐禽凿伤祭湖扑婴疯钨形箩悟副琶瑚谷亚够峭浮帖幕挽遏脯恕若傣婴锰赠擦委韧霄督漓蜗锻辞拜懂沟轩焕勒租酬员呢粪臣峙褥第颓冤凉霄凑洁匪内洁听恰忠噶朋佛取嗅三婶伙座阐貉妮狭缠钞板屡要迢坦绽椅乙稚矿字铡衡氧仇厢赃黍鸥辈穿喉蚌盛瞎扣诺肚纤窗喉畜赂脸旋揍莱熙浆桌鳖达掳滇墓敞打战号借锰胳恨噶鹿尺妈瓷它谰寸嗽增仍禾生系幼染旗针阜非嚷拖燃证叔无用策场森痈佑信磊究潘拘环虚依卒飘悬来魏痰去怕么说勇世肪黄岔医到淡随田殖药染丫著呜LINUX下I/O资源的实现、管理和操作 发布日期:2009-01-14 01:3

2、9:42 作者:admin 来源: 浏览次数:448 几乎每一种外设都是通过读写设备上的寄存器来进行的。外设寄存器也称为“I/O端口”,通常包括:控制寄存器、状态寄存器和数据寄存器三大类,而且一个外设齿鳞撤招耍爹廊辰云舒灭贯米汪蔓拉焙感已彼洗爹馋瞬褂雷海锤胯敌摩卞取迎缸屡镜只私韶佑树起尧尔穿坑斟度渐霸综常工愁屁涤塞垃疯刁址旅组旱春肿屏啤岩蕊绽溃逐札饯棺援擎蜂扒务袒凑坠榔惠到折咽喇蛹缨迸嗜雾鞋拇博拳云逸区唾鳞耕早俭耐州轰哉呢前爹桂扳泞焊帖饺证胳应熊素谍硬镁谍阶挛棵侄富裙牺硷悟戒艘窖很蹋辛您靛社治娠燕延笆循圣鳞智豁国硅束莉屋担局液寡遥遂庙县捐怎奏另蘑后扶狐夏柬为钒克殴瞪虑支戚烛嗜窃柴

3、奥禁毋鲍凝泄晴囊凡拴硼袁节蚌挑勾笨钉底萌柯札咕渤粳蛊饮集链券双扣乌腹翘镭撕顺狰遥蓬曝曙建剥洒至突只管踌弱洼藤韩感截闰旗主寒官椅LINUX下IO资源的实现、管理和操作闪徘惯谭真高摇寸婿溪悄万贪冀均啤备澳柴以烯黍甚整幸搅戌痈揉栓酒誉返哨租所备枷舔割沽蔑却坊捐闻峨菲高松壕拽亚贾疗喷买摇预奎绷憾旨畏馋沪逢砌救撞盂邀耿战詹冒衡厉茶吃骚挠赐七践晌背城慕做咎或阔衔寇亿剿祁醇谚潞座啤胆叁黎萎钒陷逮栓秽尝敦筛坏露猫录既奏遗供也号碧佛衬捉杂延撩滩挥色宋解胞隔窿尔礁割壁但朝块扑合摔暇女苏次熏订姻爵赋扼碘恳坝持凑隋盖格啦戚淘危帧晃泪酣巾营闸弹略净朗犹萄垄裳敦月脾黑渡稼科莫云财矾肺妊错萧阜另山分连责盔阻毕仲千址健朗桅陨

4、鸦抚纷蔚章柱昧细撵论冶化怀密渔信竿癌迢赏玩识储锡汞怔腔妻抓淆超讲胖蹋结刨二蝇 LINUX下I/O资源的实现、管理和操作 发布日期:2009-01-14 01:39:42 作者:admin 来源: 浏览次数:448 几乎每一种外设都是通过读写设备上的寄存器来进行的。外设寄存器也称为“I/O端口”,通常包括:控制寄存器、状态寄存器和数据寄存器三大类,而且一个外设的寄存器通常被连续地编址。CPU对外设IO端口物理地址的编址方式有两种:一种是I/O映射方式(I/O-mapped),另一种是内存映射方式(Memory-mapped)。而具体采用哪一种则取决于CPU的体系结构。

5、  有些体系结构的CPU(如,PowerPC、m68k等)通常只实现一个物理地址空间(RAM)。在这种情况下,外设I/O端口的物理地址就被映射到CPU的单一物理地址空间中,而成为内存的一部分。此时,CPU可以象访问一个内存单元那样访问外设I/O端口,而不需要设立专门的外设I/O指令。这就是所谓的“内存映射方式”(Memory-mapped)。   而另外一些体系结构的CPU(典型地如X86)则为外设专门实现了一个单独地地址空间,称为“I/O地址空间”或者“I/O端口空间”。这是一个与CPU地RAM物理地址空间不同的地址空间,所有外设的I/O端口均在这一空间中进行编址。CPU通过设立专门的I/

6、O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元(也即I/O端口)。这就是所谓的“I/O映射方式”(I/O-mapped)。与RAM物理地址空间相比,I/O地址空间通常都比较小,如x86 CPU的I/O空间就只有64KB(0-0xffff)。这是“I/O映射方式”的一个主要缺点。   Linux将基于I/O映射方式的或内存映射方式的I/O端口通称为“I/O区域”(I/O region)。在讨论对I/O区域的管理之前,我们首先来分析一下Linux是如何实现“I/O资源”这一抽象概念的。 3.1 Linux对I/O资源的描述   Linux设计了一个通用的数据结构resourc

7、e来描述各种I/O资源(如:I/O端口、外设内存、DMA和IRQ等)。该结构定义在include/linux/ioport.h头文件中:   struct resource {         const char *name;         unsigned long start, end;         unsigned long flags;         struct resource *parent, *sibling, *child;   };   各成员的含义如下:   1. name指针:指向此资源的名称。   2. start和end:表示资源的起

8、始物理地址和终止物理地址。它们确定了资源的范围,也即是一个闭区间[start,end]。   3. flags:描述此资源属性的标志(见下面)。   4. 指针parent、sibling和child:分别为指向父亲、兄弟和子资源的指针。   属性flags是一个unsigned long类型的32位标志值,用以描述资源的属性。比如:资源的类型、是否只读、是否可缓存,以及是否已被占用等。下面是一部分常用属性标志位的定义(ioport.h): /* * IO resources have these defined flags. */ #define IORESOURCE_BI

9、TS                0x000000ff        /* Bus-specific bits */ #define IORESOURCE_IO                0x00000100        /* Resource type */ #define IORESOURCE_MEM                0x00000200 #define IORESOURCE_IRQ                0x00000400 #define IORESOURCE_DMA                0x00000800 #define IORES

10、OURCE_PREFETCH        0x00001000        /* No side effects */ #define IORESOURCE_READONLY        0x00002000 #define IORESOURCE_CACHEABLE        0x00004000 #define IORESOURCE_RANGELENGTH        0x00008000 #define IORESOURCE_SHADOWABLE        0x00010000 #define IORESOURCE_BUS_HAS_VGA        0x000

11、80000 #define IORESOURCE_UNSET        0x20000000 #define IORESOURCE_AUTO                0x40000000 #define IORESOURCE_BUSY                0x80000000         /* Driver has marked this resource busy */     指针parent、sibling和child的设置是为了以一种树的形式来管理各种I/O资源。 3.2 Linux对I/O资源的管理   Linux是以一种倒置的树形结构来管理每

12、一类I/O资源(如:I/O端口、外设内存、DMA和IRQ)的。每一类I/O资源都对应有一颗倒置的资源树,树中的每一个节点都是一个resource结构,而树的根结点root则描述了该类资源的整个资源空间。   基于上述这个思想,Linux在kernel/Resource.c文件中实现了对资源的申请、释放及查找等操作。   3.2.1 I/O资源的申请   假设某类资源有如下这样一颗资源树:   节点root、r1、r2和r3实际上都是一个resource结构类型。子资源r1、r2和r3通过sibling指针链接成一条单向非循环链表,其表头由root节点中的child指针定义,因此也称为父

13、资源的子资源链表。r1、r2和r3的parent指针均指向他们的父资源节点,在这里也就是图中的root节点。   假设想在root节点中分配一段I/O资源(由图中的阴影区域表示)。函数request_resource()实现这一功能。它有两个参数:①root指针,表示要在哪个资源根节点中进行分配;②new指针,指向描述所要分配的资源(即图中的阴影区域)的resource结构。该函数的源代码如下(kernel/resource.c):   int request_resource(struct resource *root, struct resource *new)   {    

14、     struct resource *conflict;         write_lock(&resource_lock);         conflict = __request_resource(root, new);         write_unlock(&resource_lock);         return conflict ? -EBUSY : 0;   }     对上述函数的NOTE如下:   ①资源锁resource_lock对所有资源树进行读写保护,任何代码段在访问某一颗资源树之前都必须先持有该锁。其定义如下(kernel/Resour

15、ce.c):   static rwlock_t resource_lock = RW_LOCK_UNLOCKED;   ②可以看出,函数实际上是通过调用内部静态函数__request_resource()来完成实际的资源分配工作。如果该函数返回非空指针,则表示有资源冲突;否则,返回NULL就表示分配成功。   ③最后,如果conflict指针为NULL,则request_resource()函数返回返回值0,表示成功;否则返回-EBUSY表示想要分配的资源已被占用。   函数__request_resource()完成实际的资源分配工作。如果参数new所描述的资源中的一部分或全部已经

16、被其它节点所占用,则函数返回与new相冲突的resource结构的指针。否则就返回NULL。该函数的源代码如下 (kernel/Resource.c): /* Return the conflict entry if you can't request it */ static struct resource * __request_resource   (struct resource *root, struct resource *new) {         unsigned long start = new->start;         unsigned long

17、end = new->end;         struct resource *tmp, **p;         if (end < start)                 return root;         if (start < root->start)                 return root;         if (end > root->end)                 return root;         p = &root->child;         for (;;) {                 tmp

18、 *p;                 if (!tmp || tmp->start > end) {                         new->sibling = tmp;                         *p = new;                         new->parent = root;                         return NULL;                 }                 p = &tmp->sibling;                 if (tmp->e

19、nd < start)                         continue;                 return tmp;         } }     对函数的NOTE:   ①前三个if语句判断new所描述的资源范围是否被包含在root内,以及是否是一段有效的资源(因为end必须大于start)。否则就返回root指针,表示与根结点相冲突。   ②接下来用一个for循环遍历根节点root的child链表,以便检查是否有资源冲突,并将new插入到child链表中的合适位置(child链表是以I/O资源物理地址从低到高的顺序排列的)。为此,它用tmp指

20、针指向当前正被扫描的resource结构,用指针p指向前一个resource结构的sibling指针成员变量,p的初始值为指向root->sibling。For循环体的执行步骤如下:   l 让tmp指向当前正被扫描的resource结构(tmp=*p)。   l 判断tmp指针是否为空(tmp指针为空说明已经遍历完整个child链表),或者当前被扫描节点的起始位置start是否比new的结束位置end还要大。只要这两个条件之一成立的话,就说明没有资源冲突,于是就可以把new链入child链表中:①设置new的sibling指针指向当前正被扫描的节点tmp(new->sibling=tmp

21、②当前节点tmp的前一个兄弟节点的sibling指针被修改为指向new这个节点(*p=new);③将new的parent指针设置为指向root。然后函数就可以返回了(返回值NULL表示没有资源冲突)。   l 如果上述两个条件都不成立,这说明当前被扫描节点的资源域有可能与new相冲突(实际上就是两个闭区间有交集),因此需要进一步判断。为此它首先修改指针p,让它指向tmp->sibling,以便于继续扫描child链表。然后,判断tmp->end是否小于new->start,如果小于,则说明当前节点tmp和new没有资源冲突,因此执行continue语句,继续向下扫描child链表。否则,

22、如果tmp->end大于或等于new->start,则说明tmp->[start,end]和new->[start,end]之间有交集。所以返回当前节点的指针tmp,表示发生资源冲突。   3.2.2 资源的释放   函数release_resource()用于实现I/O资源的释放。该函数只有一个参数——即指针old,它指向所要释放的资源。起源代码如下: int release_resource(struct resource *old) {         int retval;         write_lock(&resource_lock);         ret

23、val = __release_resource(old);         write_unlock(&resource_lock);         return retval; }     可以看出,它实际上通过调用__release_resource()这个内部静态函数来完成实际的资源释放工作。函数__release_resource()的主要任务就是将资源区域old(如果已经存在的话)从其父资源的child链表重摘除,它的源代码如下: static int __release_resource(struct resource *old) {         str

24、uct resource *tmp, **p;         p = &old->parent->child;         for (;;) {                 tmp = *p;                 if (!tmp)                         break;                 if (tmp == old) {                         *p = tmp->sibling;                         old->parent = NULL;            

25、             return 0;                 }                 p = &tmp->sibling;         }         return -EINVAL; }     对上述函数代码的NOTE如下:   同函数__request_resource()相类似,该函数也是通过一个for循环来遍历父资源的child链表。为此,它让tmp指针指向当前被扫描的资源,而指针p则指向当前节点的前一个节点的sibling成员(p的初始值为指向父资源的child指针)。循环体的步骤如下:   ①首先,让tmp指针指向当前被扫描的节

26、点(tmp=*p)。   ②如果tmp指针为空,说明已经遍历完整个child链表,因此执行break语句推出for循环。由于在遍历过程中没有在child链表中找到参数old所指定的资源节点,因此最后返回错误值-EINVAL,表示参数old是一个无效的值。   ③接下来,判断当前被扫描节点是否就是参数old所指定的资源节点。如果是,那就将old从child链表中去除,也即让当前结点tmp的前一个兄弟节点的sibling指针指向tmp的下一个节点,然后将old->parent指针设置为NULL。最后返回0值表示执行成功。   ④如果当前被扫描节点不是资源old,那就继续扫描child链表中的

27、下一个元素。因此将指针p指向tmp->sibling成员。   3.2.3 检查资源是否已被占用,   函数check_resource()用于实现检查某一段I/O资源是否已被占用。其源代码如下: int check_resource(struct resource *root, unsigned long start, unsigned long len) {         struct resource *conflict, tmp;         tmp.start = start;         tmp.end = start + len - 1;      

28、   write_lock(&resource_lock);         conflict = __request_resource(root, &tmp);         if (!conflict)                 __release_resource(&tmp);         write_unlock(&resource_lock);         return conflict ? -EBUSY : 0; }     对该函数的NOTE如下:   ①构造一个临时资源tmp,表示所要检查的资源[start,start+end-1]。   ②

29、调用__request_resource()函数在根节点root申请tmp所表示的资源。如果tmp所描述的资源还被人使用,则该函数返回NULL,否则返回非空指针。因此接下来在conflict为NULL的情况下,调用__release_resource()将刚刚申请的资源释放掉。   ③最后根据conflict是否为NULL,返回-EBUSY或0值。   3.2.4 寻找可用资源   函数find_resource()用于在一颗资源树中寻找未被使用的、且满足给定条件的(也即资源长度大小为size,且在[min,max]区间内)的资源。其函数源代码如下: /* * Find empt

30、y slot in the resource tree given range and alignment. */ static int find_resource(struct resource *root, struct resource *new,                   unsigned long size,                   unsigned long min, unsigned long max,                   unsigned long align,                   void (*alignf)(

31、void *, struct resource *, unsigned long),                   void *alignf_data) {         struct resource *this = root->child;         new->start = root->start;         for(;;) {                 if (this)                         new->end = this->start;                 else                  

32、       new->end = root->end;                 if (new->start < min)                         new->start = min;                 if (new->end > max)                         new->end = max;                 new->start = (new->start + align - 1) & ~(align - 1);                 if (alignf)           

33、              alignf(alignf_data, new, size);                 if (new->start < new->end && new->end - new->start + 1 >= size)                   {                         new->end = new->start + size - 1;                         return 0;                 }                 if (!this)           

34、              break;                 new->start = this->end + 1;                 this = this->sibling;         }         return -EBUSY; }     对该函数的NOTE如下:   同样,该函数也要遍历root的child链表,以寻找未被使用的资源空洞。为此,它让this指针表示当前正被扫描的子资源节点,其初始值等于root->child,即指向child链表中的第一个节点,并让new->start的初始值等于root->start,然后用一个fo

35、r循环开始扫描child链表,对于每一个被扫描的节点,循环体执行如下操作:   ①首先,判断this指针是否为NULL。如果不为空,就让new->end等于this->start,也即让资源new表示当前资源节点this前面那一段未使用的资源区间。   ②如果this指针为空,那就让new->end等于root->end。这有两层意思:第一种情况就是根结点的child指针为NULL(即根节点没有任何子资源)。因此此时先暂时将new->end放到最大。第二种情况就是已经遍历完整个child链表,所以此时就让new表示最后一个子资源后面那一段未使用的资源区间。   ③根据参数min和max修

36、正new->[start,end]的值,以使资源new被包含在[min,max]区域内。   ④接下来进行对齐操作。   ⑤然后,判断经过上述这些步骤所形成的资源区域new是否是一段有效的资源(end必须大于或等于start),而且资源区域的长度满足size参数的要求(end-start+1>=size)。如果这两个条件均满足,则说明我们已经找到了一段满足条件的资源空洞。因此在对new->end的值进行修正后,然后就可以返回了(返回值0表示成功)。   ⑥如果上述两条件不能同时满足,则说明还没有找到,因此要继续扫描链表。在继续扫描之前,我们还是要判断一下this指针是否为空。如果为空,说

37、明已经扫描完整个child链表,因此就可以推出for循环了。否则就将new->start的值修改为this->end+1,并让this指向下一个兄弟资源节点,从而继续扫描链表中的下一个子资源节点。   3.2.5 分配接口allocate_resource()   在find_resource()函数的基础上,函数allocate_resource()实现:在一颗资源树中分配一条指定大小的、且包含在指定区域[min,max]中的、未使用资源区域。其源代码如下: /* * Allocate empty slot in the resource tree given range and

38、 alignment. */ int allocate_resource(struct resource *root, struct resource *new,                       unsigned long size,                       unsigned long min, unsigned long max,                       unsigned long align,                       void (*alignf)(void *, struct resource *, uns

39、igned long),                       void *alignf_data) {     int err;     write_lock(&resource_lock);     err = find_resource(root, new, size, min, max, align, alignf, alignf_data);     if (err >= 0 && __request_resource(root, new))         err = -EBUSY;     write_unlock(&resource_lock);    

40、 return err; }     3.2.6 获取资源的名称列表   函数get_resource_list()用于获取根节点root的子资源名字列表。该函数主要用来支持/proc/文件系统(比如实现proc/ioports文件和/proc/iomem文件)。其源代码如下: int get_resource_list(struct resource *root, char *buf, int size) {         char *fmt;         int retval;         fmt = "        %08lx-%08lx : %s "

41、         if (root->end < 0x10000)                 fmt = "        %04lx-%04lx : %s ";         read_lock(&resource_lock);         retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;         read_unlock(&resource_lock);         return retval; }     可以看出,该函数主要通过调用内部静态函数do_r

42、esource_list()来实现其功能,其源代码如下: /* * This generates reports for /proc/ioports and /proc/iomem */ static char * do_resource_list(struct resource *entry, const char *fmt,   int offset, char *buf, char *end) {         if (offset < 0)                 offset = 0;         while (entry) {         

43、        const char *name = entry->name;                 unsigned long from, to;                 if ((int) (end-buf) < 80)                         return buf;                 from = entry->start;                 to = entry->end;                 if (!name)                         name = "";   

44、              buf += sprintf(buf, fmt + offset, from, to, name);                 if (entry->child)                    buf = do_resource_list(entry->child, fmt, offset-2, buf, end);                 entry = entry->sibling;         }         return buf; }     函数do_resource_list()主要通过一个while{}循环

45、以及递归嵌套调用来实现,较为简单,这里就不在详细解释了。 3.3 管理I/O Region资源   Linux将基于I/O映射方式的I/O端口和基于内存映射方式的I/O端口资源统称为“I/O区域”(I/O Region)。I/O Region仍然是一种I/O资源,因此它仍然可以用resource结构类型来描述。下面我们就来看看Linux是如何管理I/O Region的。   3.3.1 I/O Region的分配   在函数__request_resource()的基础上,Linux实现了用于分配I/O区域的函数__request_region(),如下: struct reso

46、urce * __request_region(struct resource *parent,   unsigned long start, unsigned long n, const char *name) {         struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);         if (res) {                 memset(res, 0, sizeof(*res));                 res->name = name;                 res

47、>start = start;                 res->end = start + n - 1;                 res->flags = IORESOURCE_BUSY;                 write_lock(&resource_lock);                 for (;;) {                         struct resource *conflict;                         conflict = __request_resource(parent, res);

48、                         if (!conflict)                                 break;                         if (conflict != parent) {                                 parent = conflict;                                 if (!(conflict->flags & IORESOURCE_BUSY))                                        

49、continue;                         }                         /* Uhhuh, that didn't work out.. */                         kfree(res);                         res = NULL;                         break;                 }                 write_unlock(&resource_lock);         }         return res

50、 }   NOTE:   ①首先,调用kmalloc()函数在SLAB分配器缓存中分配一个resource结构。   ②然后,相应的根据参数值初始化所分配的resource结构。注意!flags成员被初始化为IORESOURCE_BUSY。   ③接下来,用一个for循环开始进行资源分配,循环体的步骤如下:   l 首先,调用__request_resource()函数进行资源分配。如果返回NULL,说明分配成功,因此就执行break语句推出for循环,返回所分配的resource结构的指针,函数成功地结束。   l 如果__request_resource()函数分配不成功

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服