也许是在复旦养成了昼伏夜出的坏习惯,工作之后也总是很晚也不愿意睡。来到北京之后,开始听广播听都市之声的北京不眠夜。这个节目是从 23 点直到第二天凌晨一点,我常常是听完了才会睡觉。无论是北京还是上海,对我来说,生存总是那么困难,生活的压力总是那么大,每天只有在这个节目中才能够寻找到一丝温暖。我不喜欢躺在床上听,而是喜欢一边听一边做点别的事情,于是心血来潮的决定,写点文字吧,听着电波里别人分享心情,不妨也用文字来记录自己的心情吧。 我首先想到的是写一些和Linux相关的文字。事实上我并不喜欢Linux,学习Linux完全是一种无奈,工作中要用,迫于生计,不得不去学习,而学习 Linux 的过程中唯一让我觉得还有些乐趣的是当遇到问题的时候可以去网上问去网上查,很多人写了很多文档可以让我们这些菜鸟们参考学习,这样才让我们在工作中走了很多弯路。挺感谢那些分享自己知识的人。碰巧最近 3 我也看了点冬冬,并且这些冬冬在网上的资料也比较少,所以我想我不妨也把自己那一夜的收获写出来,或许以后也能给别人提供一些帮助,想想也是,整个 Linux 社区不正是这样吗,像陈奕迅唱的那样,”把一个人的温暖转移到另一个人的胸膛”。 我要写的是 Linux 设备驱动程序相关的,主要分析的是 Linux 中与 U 盘相关的那部分代码。 过去也没有看过,但是今年 4 月底的某一天,一个偶然的原因,我一时冲动就看了一遍。我们几个同学在人大附近打麻将,打到夜深了,因为我们几人人住的位置都离得挺远的,各自回去都得打车,于是决定不如去权金城开个房间,晚上就睡那得了。在权金城洗浴中心,和几个同学洗浴过后,有人去按摩了,而我和另一个人则留在了房间里,无聊中,那位哥们见我带了电脑,说他有部 A 片,很不错,不是很大,所以他存在 U 盘里的,他还挺逗的说这是 2008 年北京奥运会指定 A 片,问我有没有兴趣,这还用问,当然有兴趣了,于是立马打开电脑,插入 u 盘,然后不一会我就傻了,因为我的电脑根本就不能识别 U 盘,首先我的电脑比较旧,装的是双系统,一个是 Win 98,这个没办法,没有 U 盘驱动,另一个是 Linux,2.6 的内核,按理应该是支持 U 盘的, 问题是实际情况却是我没有看到 U 盘,/dev/目录下面根本没有这么一个盘符,于是我没办法了,一脸沮丧,而同学在旁边自然表示出了对 Linux 很鄙视的神情。 过了一会,他去看电视了,正好有英超,我却没有心情看电视,想想就觉得奇怪,怎么会不能使用 U 盘呢,这不可能啊,一定是我自己对 Linux 下面的一些冬冬没有弄清楚,于是我决定好好看看问题到底出在哪,记得当时看了一下/var/log/messages 这个日志文件里边好像记录了一些信息,感觉像是一些错误信息,但是看不明白它到底在说什么。同学开始劝我,算了算了, 改天再看吧,这话我可不愿意听,不是说 Linux 内核源代码是公开的吗,大不了看看源代码,搞清楚工作原理了还怕问题不能解决?无非就是一些 C 代码而已,好歹哥们也是认真学过谭浩强大哥那本 C 程序设计的。而且当初那本书课后习题老师基本上都让我们做了,虽说是参考了那本习题解答的书,可就算写代码不行,读代码还是没问题吧,语法什么的基本上还是很清楚的,什么判断结构循环结构,包括 goto 语句,还是记得的。 所以我就开始看了,正所谓梦想有多远,就能走多远。以前我只是玩 CS 玩仙剑的时候能够整晚整晚不睡,但那个晚上,为了告诉我同学,Linux 下也能看 A 片,Linux 下遇到问题更适合自己解决,我愣是从一点看到快天亮,终于把 drivers/usb/storage/目录下面一万余行的代码给看了一遍。当然没有看得太仔细,但是很显然把整个原理搞清楚了,问题也很快得以解决。 所以此刻,我整理了一下思路,决定把那晚看的冬冬用文字记录下来。也算为了纪念那个不寻常的夜晚吧。不过我估计这个篇幅不会短,因为光那一万余行的代码贴出来就得占许许多多页了,所以这件事情也许会占用我不少时间,然而,还好,每晚有北京不眠夜的陪伴,而且,也许当我把心思投入到写这个故事的时候,能够把那些压力那些烦恼那种孤独那种郁闷以及那种对生活的绝望给暂时忘记些许。
有一种感动,叫泪流满面,有一种机制,叫模块机制,十月革命一声炮响,给 Linux 送来了模块机制。 显然,这种模块机制给那些 Linux 的发烧友们带来了方便,因为模块机制意味着人们可以把庞大的 Linux 内核划分为许许多多个小的模块,对于编写设备驱动程序的那帮家伙来说,从此以后他们可以编写设备驱动程序却不需要把她编译进内核,不用 reboot 机器,她只是一个模块,当你需要她的时候,你可以把她抱入怀中(insmod),当你不再需要她的时候,你可以把她一脚踢开,甚至, 你可以对她咆哮:“滚吧,贱人!”(rmmod)。她不能成为你的手足,只能算你的衣服。 也许在现实世界里不会这样,但是在 Linux 的虚拟世界里,确实可以是如此,time and time again,我问自己,模块是否就像现实生活中的妓女一样呢?Linux 内核是嫖客,当他需要这个模块的时候,他就把人家揽入怀中,当他不需要人家的时候,就把别人踢开,而且,模块总是能够逆来顺受,尽管 Linux 内核会一次次抛弃她,但是每当 Linux 内核再次需要她的时候,当内核再次执行 insmod 的时候,模块依然会尽自己的能力去取悦内核,这是否太可悲了些!记得孔子曾经说过,读懂Linux内核代码不难,难得是读懂Linux内核代码背后的哲学!难道这就是传说中的藏在Linux 代码背后的哲学!天哪! 抛开这见鬼的哲学吧。让我们从一个伟大的例子去认识模块。这就是传说中的“Hello World!”,这个梦幻般的名字我们看过无数次了,每一次她出现在眼前,就意味着我们开始接触一种新的计算机语言了,或者,如此刻,开始描述一个新的故事。 请看下面这段代码,她就是 Linux 下的一个最简单的模块。当你安装这个模块的时候,她会用她特有的语言向你表白,“Hello,world!”,千真万确,她没有说“Honey,I love you!”,虽然,她可以这么说,如果你要求她这么说。而后来你卸载了这个模块,你无情抛弃了她,她很伤心,她很绝望,但她没有抱怨,她只是淡淡地说,“Goodbye,cruel world!”(再见,残酷的世界!)
其实,module_init/module_exit 只是一个宏,通常写模块的人为了彰显自己的个性,会给自己的初始化函数和注销函数另外起个名字,比如这里 module_init(usb_stor_init)以及 module_exit(usb_stor_exit)实际上就是告诉这个世界,真正的函数是 usb_stor_init 和 usb_stor_exit.这种伎俩在 Linux 内核代码中屡见不鲜。见多了也就不必大惊小怪了,天要下雨娘要嫁人,随她去吧。我们下面当然就从 usb_stor_init 正式开始我们的探索之旅。 外面的世界很精彩看代码之前,我曾经认真的思考过这么一个问题,我需要关注的仅仅是 drivers/usb/storage/目录下面那相关的 3000多行代码吗?就是这样几个文件就能让一个个不同的 U盘在 Linux 下面工作起来吗? 像一开始那样把这个目录比作一个小城的话,也许,城里的月光很漂亮,她能够把人的梦照亮,能够温暖人的心房。但我们真的就能厮守在这个城里,一生一世吗? 很不幸,问题远不是这样简单。外面的世界很精彩,作为 U 盘,她需要与 usb core 打交道,需要与 scsi core 打交道,需要与内存管理单元打交道,还有内核中许许多多其它模块打交道。外面的世界很大,远比我们想象的大。 什么是 usb core?她负责实现一些核心的功能,为别的设备驱动程序提供服务,比如申请内存,比如实现一些所有的设备都会需要的公共的函数,事实上,在 usb 的世界里,一个普通的设备要正常的工作,除了要有设备本身以外,还需要有一个叫做控制器的冬冬,老外把它叫做 host controller, 和这个控制器相连接在一起的有另一个咚咚,她叫 root hub,hub 我们应该不会陌生,在大学里, 有的宿舍里网口有限,但是我们这一代人上大学基本上是每人一台电脑,所以网口不够,于是有人会使用 hub,让多个人共用一个网口,这是以太网上的 hub,而 usb 的世界里同样有 hub,其实原理是一样的,任何支持 usb 的电脑不会说只允许你只能一个时刻使用一个 usb 设备,比如你插入了 u 盘,你同样还可以插入 usb 键盘,还可以再插一个 usb 鼠标,因为你会发现你的电脑里并不只是一个 usb 接口。这些口实际上就是所谓的 hub 口。而现实中经常是让一个 usb 控制器和一个 hub 绑定在一起,专业一点说叫集成,而这个 hub 也被称作 root hub,换言之,和 usb 控制器绑定在一起的hub就是系统中最根本的hub,其它的hub可以连接到她这里,然后可以延伸出去,外接别的设备,当然也可以不用别的 hub,让 usb 设备直接接到 root hub 上.hub 干嘛用的我们知道了,那么 usb host controller 本身是干什么用的呢?controller,控制器,顾名思义,用于控制,控制什么,控制所有的 usb 设备的通信。通常计算机的 cpu 并不是直接和 usb 设备打交道,而是和控制器打交道,他要对设备做什么,他会告诉控制器,而不是直接把指令发给设备,然后控制器再去负责处理这件事情,他会去指挥设备执行命令,而 cpu 就不用管剩下的事情,他还是该干嘛干嘛去, 控制器替他去完成剩下的事情,事情办完了再通知 cpu.否则让 cpu 去盯着每一个设备做每一件事情,那是不现实的,那就好比让一个学院的院长去盯着我们每一个本科生上课,去管理我们的出勤,只能说,不现实。所以我们就被分成了几个系,通常院长有什么指示直接跟各系领导说就可以了, 如果他要和三个系主任说事情,他即使不把三个人都召集起来开个会,也可以给三个人各打一个电话,打完电话他就忙他自己的事情去了,比如去和他带的女硕士风花雪月。而三个系主任就会去安排下面的人去执行具体的任务,完了之后他们就会像院长汇报。 所以,Linux 内核开发者们,专门写了一些代码,并美其名曰 usb core.时代总在发展,当年胖杨贵妃照样迷死唐明皇,而如今人们欣赏的则是林志玲这样的魔鬼身材。同样,早期的 Linux 内核,其结构并不是如今天这般有层次感,远不像今天这般错落有致,那时候 drivers/usb/这个目录下边放了很多很多文件,usb core 与其他各种设备的驱动程序的代码都堆砌在这里,后来,怎奈世间万千的变幻,总爱把有情的人分两端。于是在 drivers/usb/目录下面出来了一个 core 目录,就专门放 11 一些核心的代码,比如初始化整个 usb 系统,初始化 root hub,初始化 host controller 的代码, 再后来甚至把 host controller 相关的代码也单独建了一个目录,叫 host 目录,这是因为 usb host controller 随着时代的发展,也开始有了好几种,不再像刚开始那样只有一种,所以呢,设计者们把一些 host controller 公共的代码仍然留在 core 目录下,而一些各 host controller 单独的代码则移到 host 目录下面让负责各种 host controller 的人去维护,常见的 host controller 有三种,分别叫做 EHCI,UHCI,OHCI,所以这样,出来了三个概念,usb core,usb host,usb device,即原本是一家人,却被活生生的分成了两岸三地。..的确,现实总是很无奈,然而,心若知道灵犀的方向,哪怕不能够朝夕相伴?没错,usb 通信的灵魂就是 usb 协议。 usb 协议将是所有 usb 设备和 usb 主机所必须遵循的游戏规则。这种规则也很自然的体现在了代码中。于是,我们需要了解的不仅仅是 drivers/usb/storage/目录下面的冬冬,还得去了解那外面的世界,虽然,只需要了解一点点。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !