欢迎来到三一文库! | 帮助中心 三一文库31doc.com 一个上传文档投稿赚钱的网站
三一文库
全部分类
  • 研究报告>
  • 工作总结>
  • 合同范本>
  • 心得体会>
  • 工作报告>
  • 党团相关>
  • 幼儿/小学教育>
  • 高等教育>
  • 经济/贸易/财会>
  • 建筑/环境>
  • 金融/证券>
  • 医学/心理学>
  • ImageVerifierCode 换一换
    首页 三一文库 > 资源分类 > DOC文档下载
     

    Linux设备管理从dev_add说起.doc

    • 资源ID:3255496       资源大小:21KB        全文页数:3页
    • 资源格式: DOC        下载积分:2
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录   微博登录  
    二维码
    微信扫一扫登录
    下载资源需要2
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    Linux设备管理从dev_add说起.doc

    Linux设备管理从dev_add说起这里我们来探讨一下Linux内核(以4.8.5内核为例)是怎么管理字符设备的,即当我们获得了设备号,分配了cdev结构,注册了驱动的操作方法集,最后进行cdev_add()的时候,究竟是将哪些内容告诉了内核,内核又是怎么管理我的cdev结构的,这就是本文要讨论的内容。我们知道,Linux内核对设备的管理是基于kobject,这点从我们的cdev结构中就可以看出,所以,接下来,你将看到"fs/char_dev.c"中实现的操作字符设备的函数都是基于"lib/kobject.c"以及"drivers/base/map.c"中对kobject操作的函数。好,现在我们从cdev_add()开始一层层的扒。cdev_map对象/fs/char_dev.c 27 static struct kobj_map *cdev_map;内核中关于字符设备的操作函数的实现放在"fs/char_dev.c"中,打开这个文件,首先注意到就是这个在内核中不常见的静态全局变量cdev_map(27),我们知道,为了提高软件的内聚性,Linux内核在设计的时候尽量避免使用全局变量作为函数间数据传递的方式,而建议多使用形参列表,而这个结构体变量在这个文件中到处被使用,所以它应该是描述了系统中所有字符设备的某种信息,带着这样的想法,我们可以在"drivers/base/map.c"中找到kobj_map结构的定义:/drivers/base/map.c 19 struct kobj_map 20 struct probe 21 struct probe *next; 22 dev_t dev; 23 unsigned long range; 24 struct module *owner; 25 kobj_probe_t *get; 26 int (*lock)(dev_t, void *); 27 void *data; 28 *probes255; 29 struct mutex *lock; 30 ;从中可以看出,kobj_map的核心就是一个struct probe指针类型、大小为255的数组,而在这个probe结构中,第一个成员next(21)显然是将这些probe结构通过链表的形式连接起来,dev_t类型的成员dev显然是设备号,get(25)和lock(26)分别是两个函数接口,最后的重点来了,void*作为C语言中的万金油类型,在这里就是我们cdev结构(通过后面的分析可以看出),所以,这个cdev_map是一个struct kobj_map类型的指针,其中包含着一个struct probe指针类型、大小为255的数组,数组的每个元素指向的一个probe结构封装了一个设备号和相应的设备对象(这里就是cdev),可见,这个cdev_map封装了系统中的所有的cdev结构和对应的设备号,最多为255个字符设备。cdev_add了解了cdev_map的功能,我们就可以一探cdev_add()/fs/char_dev.c456 int cdev_add(struct cdev *p, dev_t dev, unsigned count) 457 458 int error;459 460 p->dev = dev;461 p->count = count;462 463 error = kobj_map(cdev_map, dev, count, NULL,464 exact_match, exact_lock, p);465 if (error)466 return error;467 468 kobject_get(p->kobj.parent);469 470 return 0;471 函数很短,(460-461)就是将我们之前获得设备号和设备号长度填充到cdev结构中,kobject_get()(468)也没做什么事:/lib/kobject.c 591 struct kobject *kobject_get(struct kobject *kobj) 592 593 if (kobj) . 598 kref_get( 599 600 return kobj; 601 所以,核心工作显然是交给了kobj_map()kobj_map()这个函数在内核的设备管理中占有重要的地位,这里我们只从字符设备的角度分析它的功能,先上实现/drivers/base/map.c 32 int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, 33 struct module *module, kobj_probe_t *probe, 34 int (*lock)(dev_t, void *), void *data) 35 36 unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; 37 unsigned index = MAJOR(dev); 38 unsigned i; 39 struct probe *p; . 44 p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL); . 48 for (i = 0; i owner = module; 50 p->get = probe; 51 p->lock = lock; 52 p->dev = dev; 53 p->range = range; 54 p->data = data; 55 56 mutex_lock(domain->lock); 57 for (i = 0, p -= n; i next = *s; 62 *s = p; 63 64 mutex_unlock(domain->lock); 65 return 0; 66 这个函数的设计也很单纯,就是封装好一个probe结构并将它的地址放入probes数组进而封装进cdev_map,(48-55)j就是根据传入的设备号的个数,将设备号和cdev依次封装到kmalloc_array分配的n个probe结构中,(57-63)就是遍历probs数组,直到找到一个值为NULL的元素,再将probe的地址存入probes。至此,我们就将我们的cdev放入的内核的数据结构,当然,cdev中大量属性都是由内核帮我们填充的。chrdev_open()将设备放入的内核,我们再来看看内核是怎么找到一个特定的cdev的,对一个字符设备的访问流程大概是:文件路径=>inode=>chrdev_open=>cdev->fops->my_chr_open。所以只要通过VFS找到了inode,就可以找到chrdev_open(),这里我们就来关注一个chrdev_open()是怎么从内核的数据结构中找到我们的cdev并回调里满的my_chr_open()的。首先,chrdev_open()尝试将inode->i_cdev(一个cdev结构指针)保存在局部变量p中(359),如果p为空,即inode->i_cdev为空(360),我们就根据inode->i_rdev(设备号)通过kobj_lookup搜索cdev_map,并返回与之对应kobj(364),由于kobject是cdev的父类,我们根据container_of很容易找到相应的cdev结构并将其保存在inode->i_cdev中(367),找到了cdev,我们就可以将inode->devices挂接到inode->i_cdev的管理链表中,这样下次就不用重新搜索,直接cdev_get()即可(378)。找到了我们的cdev结构,我们就可以将其中的操作方法集inode->i_cdev->ops传递给filp->f_ops(386-390),这样,我们就可以回调我们的设备打开函数my_chr_open()(392);/fs/char_dev.c326 static struct kobject *cdev_get(struct cdev *p) 327 328 struct module *owner = p->owner;329 struct kobject *kobj;330 331 if (owner 333 kobj = kobject_get( .336 return kobj;337 351 static int chrdev_open(struct inode *inode, struct file *filp)352 353 const struct file_operations *fops;354 struct cdev *p;355 struct cdev *new = NULL;356 int ret = 0; .359 p = inode->i_cdev;360 if (!p) 361 struct kobject *kobj;362 int idx; .364 kobj = kobj_lookup(cdev_map, inode->i_rdev, .367 new = container_of(kobj, struct cdev, kobj);369 /* Check i_cdev again in case somebody beat us to it while370 we dropped the lock. */371 p = inode->i_cdev;372 if (!p) 373 inode->i_cdev = p = new;374 list_add(375 new = NULL;376 else if (!cdev_get(p)377 ret = -ENXIO;378 else if (!cdev_get(p)379 ret = -ENXIO; .386 fops = fops_get(p->ops); .390 replace_fops(filp, fops);391 if (filp->f_op->open) 392 ret = filp->f_op->open(inode, filp); .395 396 397 return 0;398 399 out_cdev_put:400 cdev_put(p);401 return ret;402  

    注意事项

    本文(Linux设备管理从dev_add说起.doc)为本站会员(白大夫)主动上传,三一文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    经营许可证编号:宁ICP备18001539号-1

    三一文库
    收起
    展开