还是 usb_stor_init 这个初始化函数,看了它的代码,每一个人的心中都有一种莫名的兴奋,因为它太短了,就几行,除了两个 printk 语句以外,就是一个函数的调用, usb_register 。 ( 另外还有一个函数, usb_usual_set_present ,但是该函数基本上与本故事无关,它和 usb_stor_exit 中调用的 usb_usual_clear_present 是一对,都可以无视之。 )
printk 不用我说,每一个有志青年都该知道,就算没见过 printk 也该见过 printf 吧,在谭浩强大哥的带领下我们学会了使用 #include<stdio.h>->main()->printf() 来打印“ hello , world !”。而 stdio.h 就是一个 C 库, printf 是一个函数,来自函数库。可是内核中没有标准 C 库,所以 开发人员 们自己准备了一些函数,专门用于内核代码中,所以就出来了一个 printk 。 printk 中的 “ k ” 就是 kernel ,即内核。所以我们只要把它当作 printf 的兄弟即可。如果感兴趣,可以去研究一下 printk 的特点,它和 printf 多少有些不同,但基本思想是一样的。所以我们就不多讲了,当然驱动程序中所有的 printk 语句对 U 盘的工作都没有什么用,它无非是打出来给我们看的,或者打印给用户看,或者打印给 开发人员 看,特别是 开发人员 要调试程序 时 ,就会很有用。
于是我们更开心了,不用看 printk ,那就只有一个函数调用了, usb_register 。这个函数有什么用?首先这个函数正是来自 USB Core 。凡是 USB 设备驱动,都要调用这个函数来向 USB Core 注册,从而让 USB Core 知道有这个设备。这就像政府规定,一对夫妻结婚要到相关部门那里去登记是一样的,我们无需知道政府是如何管理的,只需要知道去政府那里登记即可。
这样, insmod 时, usb_stor_init 这个函数会被调用,初始化就算完成了。于是设备就开始工作了。而当我们 rmmod 时, usb_stor_exit 这个函数会被调用。我们发现,这个函数也很短,我们能看出来, US_DEBUG 也就是打印一些调试信息。因此,这里实际上也就是调用了一个函数 usb_deregister() ,它和 usb_register() 是一对,完成了注销的工作,从此设备就从 USB Core 中消失了。于是我们发现,编写设备驱动竟是如此简单,驱动程序真的就这么结束了?
这一切,不禁让人产生了一种幻觉,让人分不清故事从哪里开始,又从哪里结束,一切都太短暂了。仿佛开始在结束 时 开始,而结束却在开始 时 就早已结束。
真的吗?答案是否定的。
我们并无意去详细介绍 2.6 节内核中的设备模型,但是不懂设备模型又怎能说自己懂设备驱动呢?读代码的人,写代码的人,都要知道,什么是设备驱动 ? 什么又是设备 ? 设备和驱动之间究竟是什么关系 ? 设备如何与计算机主机联系起来 ? 我相信在中关村卖盗版光盘的哥们也能回答这个问题。计算机世界里,设备有很多种类,比如 PCI 设备,比如 ISA 设备,再比如 SCSI 设备,再比如我们这里的 USB 设备。为设备联姻的是总线,是他把设备连入了计算机主机。但是与其说设备是嫁给了计算机主机,倒不如说设备是嫁给了设备驱动程序。很显然,在计算机世界里,无论风里雨里,陪伴着设备的正是驱动程序。
唯一的遗憾是,计算机中的设备和驱动程序的关系却并非如可乐和拉环的关系那样,一对一。然而世上又有多少事情总能如人愿呢。
*****************************
摘自《Linux那些事儿之我是USB》
《Linux那些事儿之我是USB》 链接为:china-pub 、当当 、卓越
《Linux 内核修炼之道》链接为: 卓越 、当当 、 china-pub