百晓生说,世界上有两样东西最让人捉摸不透,一个是小李飞刀,一个就是linux的设备模型。
进入21世纪,小李飞刀已经在电视上又见过无数遍,早就没了那种神秘感,可linux的设备模型仍然偏居一偶,让人端端的生起许多好奇来。
上文说usb_init给我们留下了一些岔路口,每条都像是不归路,让人不知道从何处开始,也看不到路的尽头。趁着徘徊彷徨的档儿,咱们还是先聊一下linux的设备模型。各位看官听好了,这可不是任小强们摆的房子模型,不存在忽悠你们的可能。
顾名而思义就知道设备模型是关于设备的模型,对咱们写驱动的和不写驱动的人来说,设备的概念就是总线和与其相连的各种设备了。电脑城的IT工作者都会知道设备是通过总线连到计算机上的,而且还需要对应的驱动才能用,可是总线是如何发现设备的,设备又是如何和驱动对应起来的,它们经过怎样的艰辛才找到命里注定的那个他,它们的关系如何,白头偕老型的还是朝三暮四型的,这些问题就不是他们关心的了,是咱们需要关心的。经历过高考千锤百炼的咱们还能够惊喜的发现,这些疑问的中心思想中心词汇就是总线、设备和驱动,没错,它们都是咱们这里要聊的linux设备模型的名角。
总线、设备、驱动,也就是bus、device、driver,既然是名角,在内核里都会有它们自己专属的结构,在include/linux/device.h里定义。
82 unsigned int drivers_autoprobe:1;
421 unsigned uevent_suppress:1;
434 core doesn't touch it */
438 int numa_node; /* NUMA node this device is close to */
441 u64 coherent_dma_mask;/* Like dma_mask, but for
442 alloc_coherent mappings as
443 not all hardware supports
444 64 bit addresses for consistent
445 allocations such descriptors. */
451 /* arch specific additions */
457 /* class_device migration path */
460 dev_t devt; /* dev_t, creates the sysfs "dev" */
133 const char * mod_name; /* used for built-in modules */
没有人会监督我节省纸张,所以就都贴出来了,有没有发现它们的共性是什么?对,都很复杂很长,那是因为还没有见到更复杂更长的。不妨把它们看成艺术品,linux整个内核都是艺术品,既然是艺术,当然不会让你那么容易的就看懂了,不然怎么称大师称名家。这么想想咱们就会比较的宽慰了,阿Q是鲁迅对咱们80后最大的贡献。
我知道进入了21世纪,最缺的就是耐性,房价股价都让咱们没有耐性,内核的代码也让人没有耐性。不过做为最没有耐性的一代人,因为都被压扁了,还是要平心净气的扫一下上面的结构,我们会发现,struct bus_type 结构中有成员struct kset drivers 和struct kset devices,同时struct device结构中有两个成员struct bus_type和struct device_driver,struct device_driver结构中有两个成员struct bus_type和struct klist。先不说什么是klist、kset,光从成员的名字看,它们就是一个完美的三角关系。我们每个人心中是不是都有两个她?一个梦中的她,一个现实中的她。
凭一个男人的直觉,我们可以知道,struct device中的bus表示这个设备连到哪个总线上,driver表示这个设备的驱动是什么,struct device_driver中的bus表示这个驱动属于哪个总线,klist_devices表示这个驱动都支持哪些设备,因为这里device是复数,又是list,因为一个驱动可以支持多个设备,而一个设备只能绑定一个驱动。当然,struct bus_type中的drivers和devices分别表示了这个总线拥有哪些设备和哪些驱动。
单凭直觉,张钰出不了名。我们还需要看看什么是klist、kset。还有上面device和driver结构里出现的kobject结构是什么?作为一个五星红旗下长大的孩子,我可以肯定的告诉你,kobject和kset都是linux设备模型中最基本的元素,总线、设备、驱动是西瓜,kobjcet、klist是种瓜的人,没有幕后种瓜人的汗水不会有清爽解渴的西瓜,我们不能光知道西瓜的的甜,还要知道种瓜人的辛苦。kobject和kset不会在意自己自己的得失,它们存在的意义在于把总线、设备和驱动这样的对象连接到设备模型上。种瓜的人也不会在意自己的汗水,在意的只是能不能送出甜蜜的西瓜。
一般来说应该这么理解,整个linux的设备模型是一个OO的体系结构,总线、设备和驱动都是其中鲜活存在的对象,kobject是它们的基类,所实现的只是一些公共的接口,kset是同种类型kobject对象的集合,也可以说是对象的容器。只是因为C里不可能会有C++里类的class继承、组合等的概念,只有通过kobject嵌入到对象结构里来实现。这样,内核使用kobject将各个对象连接起来组成了一个分层的结构体系,就好像通过马列主义将我们13亿人也连接成了一个分层的社会体系一样。kobject结构里包含了parent成员,指向了另一个kobject结构,也就是这个分层结构的上一层结点。而kset是通过链表来实现的,这样就可以明白,struct bus_type 结构中的成员drivers 和devices表示了一条总线拥有两条链表,一条是设备链表,一条是驱动链表。我们知道了总线对应的数据结构,就可以找到这条总线关联了多少设备,又有哪些驱动来支持这类设备。
那么klist那?其实它就包含了一个链表和一个自旋锁,我们暂且把它看成链表也无妨,本来在2.6.11版本里,struct device_driver结构的devices成员就是一个链表类型。这么一说,咱们上面的直觉都是正确的,如果咱们买股票,摸彩票时直觉都这么管用,那现在哪还有任小强们牛气哄哄的份儿。
是个21世纪的人都知道,三角关系很难处,不要说自己没搞过三角关系,没吃过猪肉还没见过猪跑啊。那么总线、设备和驱动它们只见是如何和谐共处那?还是先说说总线中的那两条链表是怎么形成的吧。复旦人甲说这要求每次出现一个设备就要向总线汇报,或者说注册,每次出现一个驱动,也要向总线汇报,或者说注册。比如系统初始化的时候,会扫描连接了哪些设备,并为每一个设备建立起一个struct device的变量,每一次有一个驱动程序,就要准备一个struct device_driver结构的变量。把这些变量统统加入相应的链表,device 插入devices 链表,driver插入drivers链表。这样通过总线就能找到每一个设备,每一个驱动。然而,假如计算机里只有设备却没有对应的驱动,那么设备无法工作。反过来,倘若只有驱动却没有设备,驱动也起不了任何作用。在他们遇见彼此之前,双方都如同路埂的野草,一个飘啊飘,一个摇啊摇,谁也不知道未来在哪里,只能在生命的风里飘摇。于是总线上的两张表里就慢慢的就挂上了那许多孤单的灵魂。devices开始多了,drivers开始多了,他们像是两个来自世界,devices们彼此取暖,drivers们一起狂欢,但他们有一点是相同的,都只是在等待属于自己的那个另一半。
现在,总线上的两条链表已经有了,这个三角关系三个边已经有了两个,剩下的那个那?链表里的device和driver又是如何联系那?先有device还是先有driver?偷懒一下,仍然摘引复旦人甲的话吧。很久很久以前,在那激情燃烧的岁月里,先有的是device,每一个要用的device在计算机启动之前就已经插好了,插放在它应该在的位置上,然后计算机启动,然后操作系统开始初始化,总线开始扫描设备,每找到一个设备,就为其申请一个struct device结构,并且挂入总线中的devices链表中来,然后每一个驱动程序开始初始化,开始注册其struct device_driver结构,然后它去总线的devices链表中去寻找(遍历),去寻找每一个还没有绑定driver的设备,即struct device中的struct device_driver指针仍为空的设备,然后它会去观察这种设备的特征,看是否是他所支持的设备,如果是,那么调用一个叫做device_bind_driver的函数,然后他们就结为了秦晋之好。换句话说,把struct device中的struct device_driver driver指向这个driver,而struct device_driver driver把struct device加入他的那张struct klist klist_devices链表中来。就这样,bus、device和driver,这三者之间或者说他们中的两两之间,就给联系上了。知道其中之一,就能找到另外两个。一荣俱荣,一损俱损。
但现在情况变了,在这红莲绽放的日子里,在这樱花伤逝的日子里,出现了一种新的名词,叫热插拔。device可以在计算机启动以后在插入或者拔出计算机了。因此,很难再说是先有device还是先有driver了。因为都有可能。device可以在任何时刻出现,而driver 也可以在任何时刻被加载,所以,出现的情况就是,每当一个struct device诞生,它就会去bus的drivers链表中寻找自己的另一半,反之,每当一个一个struct device_driver诞生,它就去bus的devices链表中寻找它的那些设备。如果找到了合适的,那么ok,和之前那种情况一下,调用device_bind_driver绑定好.如果找不到,没有关系,等待吧,等到昙花再开,等到风景看透,心中相信,这世界上总有一个人是你所等的,只是还没有遇到而已。
分享到:
相关推荐
《Linux那些事儿系列之我是U盘》是一篇深入讲解Linux内核中USB驱动技术的文章,由复旦大学的fudan_abc撰写。该系列文章通过风趣的语言和通俗易懂的方式,阐述了Linux内核从2.6.10到2.6.22.1版本中关于USB驱动模块、...
作者用通俗幽默的语言简述了linux的相关知识点,很容易掌握的,建议大家好好学哦 我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核 ...
Linux是世界上最受欢迎的开源操作系统之一,它被广泛应用于服务器、超级计算机、移动设备以及嵌入式系统中。"兄弟连Linux基础知识与系统管理课件"是一份深入学习Linux操作系统的资源,适合初学者和希望提升技能的...
第一章面试受挫——代码无错就是好? 第二章代码规范、重构 第三章复制 VS复用 第四章业务的封装 第五章体会简单工厂模式的美妙 第六章工厂不好用了?...第十三章设计模式不能戏说!设计模式怎就不能戏说?
在《戏说面向对象程序设计C#版.pdf》这本书中,作者可能会以轻松幽默的方式讲解这些概念,通过实际示例帮助读者理解和掌握面向对象编程的思想和技巧。无论是Java还是C#开发者,深入理解OOP都能提升编程能力和代码...
特别是在幼儿教育阶段,如何将传统文化与现代科技相结合,激发儿童的学习兴趣和创造力,成为教育工作者面临的挑战之一。"大班音乐:戏说脸谱.ppt"这一课题,就为我们提供了一个将传统艺术与数字媒体巧妙结合的创新...
《戏说指针》这篇文档由李志勇撰写,旨在帮助读者理解和掌握C/C++中的指针概念。指针在编程中扮演着重要的角色,它允许我们直接操作内存地址,提高程序的灵活性和效率。以下是关于指针的详细解析: 一、如何分析...
C#是一种广泛应用于Windows平台和跨平台开发的强大编程语言,尤其以其面向对象的特性而闻名。面向对象编程(Object-Oriented Programming,OOP)是C#的核心设计理念,它允许开发者通过模拟现实世界中的概念来组织和...
指针的本质、指针的三要素、类型与变量名
**四大发明之活字印刷——面向对象思想的胜利** - **可维护性**:面向对象的设计允许我们轻松地修改现有代码,类似于活字印刷中只需要更换需要更改的部分。这种能力对于软件开发至关重要,尤其是在需求变更频繁的...
幼儿园大班歌唱教案:戏说脸谱.doc
#### 14. 命令模式(Command) 命令模式将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。这种模式适用于需要执行特定动作并希望能够在后续...
戏说国学.doc
幼儿园教案2021-幼儿园大班歌唱教案:戏说脸谱.doc 本教案旨在通过京剧《戏说脸谱》的唱歌活动,培养幼儿对中国国粹的认识和喜爱,提高幼儿的音乐能力和艺术鉴赏力。通过活动,幼儿可以初步学习京剧《戏说脸谱》的...
戏说绩效工资.doc
戏说TCP网络编程.doc
管Thoughtworks的首席科学家Martionfolwer为“持续集成”下了定义,但由于自身背景与经历的不同,每个人对其都有不同的理解。从狭义上讲,持续集成可以认为是一种基于某种或者某些变化对软件系统进行的经常性的构建...
戏说地沟油学习教案.pptx
它在Linux操作系统上运行,能够帮助用户实现高效的数据传输和负载均衡。本安装包"Kangle-3.5.8"提供了在Linux系统上部署Kangle反向代理的所需文件。 在了解如何使用这个安装包之前,我们先来深入理解反向代理的基本...