一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

USB驅(qū)動(dòng)分析(一)

 Jaylongor 2014-06-11

這個(gè)故事中使用的是2.6.10的內(nèi)核代碼.Linux內(nèi)核代碼目錄中, 所有去設(shè)備驅(qū)動(dòng)程序有關(guān)的代碼都在drivers/目錄下面,在這個(gè)目錄中我們用ls命令可以看到很多子目錄.

localhost:/usr/src/linux-2.6.10/drivers # ls
Kconfig   atm        cdrom    eisa      ide       macintosh  message  net       parport  s390    tc         w1
Makefile  base       char     fc4       ieee1394  mca        misc     nubus     pci      sbus    telephony  zorro
acorn     block      cpufreq  firmware  input     md         mmc      oprofile  pcmcia   scsi    usb
acpi      bluetooth  dio      i2c       isdn      media      mtd      parisc    pnp      serial  video

其中usb目錄包含了所有usb設(shè)備的驅(qū)動(dòng),而usb目錄下面又有它自己的子目錄,進(jìn)去看一下,

localhost:/usr/src/linux-2.6.10/drivers # cd usb/
locahost:/usr/src/linux-2.6.10/drivers/usb # ls
Kconfig  Makefile  README  atm  class  core  gadget  host  image  input  media  misc  net  serial  storage  usb-skeleton.c

注意到每一個(gè)目錄下面都有一個(gè)Kconfig文件和一個(gè)Makefile,這很重要.稍后會(huì)有介紹.

而我們的故事其實(shí)是圍繞著drivers/usb/storage這個(gè)目錄來(lái)展開(kāi)的.實(shí)際上這里邊的代碼清清楚楚地展示了我們?nèi)粘nl繁接觸的U盤(pán)是如何工作的,是如何被驅(qū)動(dòng)起來(lái)的.但是這個(gè)目錄里邊的冬冬并不是生活在世外桃源,他們總是和外面的世界有著千絲萬(wàn)縷的瓜葛.可以繼續(xù)進(jìn)來(lái)看一下,

localhost:/usr/src/linux-2.6.10/drivers/usb # cd storage/
localhost:/usr/src/linux-2.6.10/drivers/usb/storage # ls
Kconfig    debug.c  freecom.c       isd200.c    protocol.c  sddr09.c  shuttle_usbat.c  unusual_devs.h
Makefile   debug.h  freecom.h       isd200.h    protocol.h  sddr09.h  shuttle_usbat.h  usb.c
datafab.c  dpcm.c   initializers.c  jumpshot.c  scsiglue.c  sddr55.c  transport.c      usb.h
datafab.h  dpcm.h   initializers.h  jumpshot.h  scsiglue.h  sddr55.h  transport.h

咋一看,著實(shí)嚇了一跳,用`wc -l *`這個(gè)命令統(tǒng)計(jì)一下,12076行,暈死...

wc [  -c |  -m ] [  -l ] [  -w ] [文件]
或者
wc  -k [  -c ] [  -l ] [  -w ] [文件]

注:缺省情況下,wc 命令對(duì) File 參數(shù)指定的文件中的行數(shù)、字?jǐn)?shù)和字節(jié)數(shù)進(jìn)行計(jì)數(shù)。這個(gè)命令將換行符數(shù)、字?jǐn)?shù)和字節(jié)數(shù)寫(xiě)到標(biāo)準(zhǔn)輸出并為所有指定的文件保留一個(gè)總數(shù)。
當(dāng)使用 File 參數(shù)時(shí), wc 命令顯示文件名以及請(qǐng)求的計(jì)數(shù)。如果沒(méi)有給 File 參數(shù)指定一個(gè)文件名,wc 命令使用標(biāo)準(zhǔn)輸入。
wc 命令受 LANG、LC_ALL、LC_CTYPE 和 LC_MESSAGES 環(huán)境變量影響。
wc 命令將一個(gè)字看作是被一個(gè)空格(如空白和跳格)分隔的非零長(zhǎng)度字符串。

-c 統(tǒng)計(jì)字節(jié)數(shù),除非指定 -k 標(biāo)志。如果指定 -k 標(biāo)志,wc 命令統(tǒng)計(jì)字符數(shù)。
-k 統(tǒng)計(jì)字符數(shù)。指定 -k 標(biāo)志等同于指定 -klwc 標(biāo)志。如果將 -k 標(biāo)志同其他標(biāo)志一起使用,那么必須包含 -c 標(biāo)志。否則,將會(huì)忽略 -k 標(biāo)志。
注:這個(gè)標(biāo)志在將來(lái)的發(fā)行版中將會(huì)撤銷(xiāo)。
-l 統(tǒng)計(jì)行數(shù)。
-m 統(tǒng)計(jì)字符數(shù)。這個(gè)標(biāo)志不能與 -c 標(biāo)志一起使用。
-w 統(tǒng)計(jì)字?jǐn)?shù)。一個(gè)字被定義為由空白、跳格或換行字符分隔的字符串。


但是,也許,生活中總是充滿(mǎn)了跌宕起伏.

認(rèn)真看了一下Makefile和Kconfig之后,心情明顯好了許多.

出來(lái)混,遲早要還的.

從前在復(fù)旦,混了四年,沒(méi)有學(xué)到任何東西,每天就是逃課,上網(wǎng),玩游戲,睡覺(jué).畢業(yè)的時(shí)候,身邊的人讀研的讀研,出國(guó)的出國(guó),找工作的吧,去麥肯錫的去麥肯錫,去IBM的去IBM.而自己卻一無(wú)所長(zhǎng),沒(méi)有任何技能,直到這時(shí)候才發(fā)現(xiàn)那四年欠了很多債,早知今日,何必當(dāng)初.幸運(yùn)的是,我還有一張復(fù)旦的文憑,依靠著這張文憑,混進(jìn)了Intel.然而,工作以后,更是發(fā)現(xiàn)當(dāng)初在校期間沒(méi)有好好讀書(shū)其實(shí)真是在欠債,當(dāng)初沒(méi)學(xué),工作以后還是要學(xué),的確是遲早要還的,逃是逃不掉的.

畢業(yè)的時(shí)候,人家跟我說(shuō)Makefile我完全不知,但是一說(shuō)Make Love我就來(lái)勁了.現(xiàn)在想來(lái)依然覺(jué)得丟人.

基本上,Linux內(nèi)核中每一個(gè)目錄下邊都有一個(gè)Makefile,Makefile和Kconfig就像一個(gè)城市的地圖,地圖帶領(lǐng)我們?nèi)フJ(rèn)識(shí)一個(gè)城市,而Makefile和Kconfig則可以讓我們了解這個(gè)目錄下面的結(jié)構(gòu).drivers/usb/storage/目錄下邊的Makefile內(nèi)容如下:

#
# Makefile for the USB Mass Storage device drivers.
#
# 15 Aug 2000, Christoph Hellwig <
hch@infradead.org>
# Rewritten to use lists instead of if-statements.
#

EXTRA_CFLAGS    := -Idrivers/scsi

obj-$(CONFIG_USB_STORAGE)       += usb-storage.o

usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG)     += debug.o
usb-storage-obj-$(CONFIG_USB_STORAGE_HP8200e)   += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09)    += sddr09.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55)    += sddr55.o
usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM)   += freecom.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)      += dpcm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)    += isd200.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)   += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)  += jumpshot.o

usb-storage-objs :=     scsiglue.o protocol.o transport.o usb.o \
                        initializers.o $(usb-storage-obj-y)

關(guān)于Kconfig文件,在故事的最后會(huì)介紹,此刻暫且不表,Kconfig文件比較長(zhǎng),就不貼出來(lái)了.但是通過(guò)看Kconfig文件,我們可以知道,除了CONFIG_USB_STORAGE這個(gè)編譯選項(xiàng)是我們真正需要的以外,別的選項(xiàng)我們都可以不予理睬.比如,關(guān)于CONFIG_USB_STORAGE_DATAFAB,Kconfig文件中有這么一段,

config USB_STORAGE_DATAFAB
        bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
        depends on USB_STORAGE && EXPERIMENTAL
        help
          Support for certain Datafab CompactFlash readers.
          Datafab has a web page at <http://www./>.

顯然,這個(gè)選項(xiàng)和我們沒(méi)有關(guān)系,首先這是專(zhuān)門(mén)針對(duì)Datafab公司的產(chǎn)品的,其次CompactFlash reader是一種flash設(shè)備,但這顯然不是U盤(pán),因?yàn)閐rivers/usb/storage這個(gè)目錄里邊的代碼是針對(duì)一類(lèi)設(shè)備的,不是某一種特定的設(shè)備,這一類(lèi)設(shè)備就是usb mass storage設(shè)備,關(guān)于這類(lèi)設(shè)備,有專(zhuān)門(mén)的文檔進(jìn)行介紹,有相應(yīng)的spec,描述這類(lèi)設(shè)備的通信或者物理上電特性上等方面的規(guī)范,U盤(pán)只是其中的一種,這種設(shè)備使用的通信協(xié)議被稱(chēng)為Bulk-Only Transport協(xié)議.再比如,關(guān)于CONFIG_USB_STORAGE_SDDR55這個(gè)選項(xiàng),Kconfig文件中也有對(duì)應(yīng)的一段,

config USB_STORAGE_SDDR55
        bool "SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)"
        depends on USB_STORAGE && EXPERIMENTAL
        help
          Say Y here to include additional code to support the Sandisk SDDR-55
          SmartMedia reader in the USB Mass Storage driver.
很顯然這是SanDisk的產(chǎn)品,并且是針對(duì)SM卡的,這也不是U盤(pán),所以我們也都不去理睬了.事實(shí)上,很容易確定,只有CONFIG_USB_STORAGE這個(gè)選項(xiàng)是我們真正關(guān)心的,而它所對(duì)應(yīng)的模塊叫usb-storage,Makefile中最后一行也說(shuō)了,

usb-storage-objs :=     scsiglue.o protocol.o transport.o usb.o \
                        initializers.o $(usb-storage-obj-y)
這就意味著我們只需要關(guān)注的文件就是scsiglue.c,protocol.c,transport.c,usb.c,initializers.c以及它們同名的.h頭文件.再次使用wc -l命令統(tǒng)計(jì)一下這幾個(gè)文件,發(fā)現(xiàn)總長(zhǎng)度只有3701行,比最初看到的12000多行少了許多,當(dāng)時(shí)信心就倍增.

不過(guò)需要特別注意的是,CONFIG_USB_STORAGE_DEBUG這個(gè)編譯選項(xiàng),它不是我們必須的,但是如果真的要自己修改或者調(diào)試usb-storage的代碼,那么打開(kāi)這個(gè)選項(xiàng)是很有必要的,因?yàn)樗鼤?huì)負(fù)責(zé)打印一些調(diào)試信息,以后在源代碼中我們會(huì)看到它的作用.

有一種感動(dòng),叫淚流滿(mǎn)面,有一種機(jī)制,叫模塊機(jī)制,十月革命一聲炮響,給Linux送來(lái)了模塊機(jī)制.顯然,這種模塊機(jī)制給那些Linux的發(fā)燒友們帶來(lái)了方便,因?yàn)槟K機(jī)制意味著人們可以把龐大的Linux內(nèi)核劃分為許許多多個(gè)小的模塊,對(duì)于編寫(xiě)設(shè)備驅(qū)動(dòng)程序的那幫家伙來(lái)說(shuō),從此以后他們可以編寫(xiě)設(shè)備驅(qū)動(dòng)程序卻不需要把她編譯進(jìn)內(nèi)核,不用reboot機(jī)器,她只是一個(gè)模塊,當(dāng)你需要她的時(shí)候,你可以把她抱入懷中(insmod),當(dāng)你不再需要她的時(shí)候,你可以把她一腳踢開(kāi),甚至,你可以對(duì)她咆哮:"滾吧,賤人!"(rmmod).她不能成為你的手足,只能算你的衣服.

也許在現(xiàn)實(shí)世界里不會(huì)這樣,但是在Linux的虛擬世界里,確實(shí)可以是如此,time and time again,我問(wèn)自己,模塊是否就像現(xiàn)實(shí)生活中的妓女一樣呢?Linux內(nèi)核是嫖客,當(dāng)他需要這個(gè)模塊的時(shí)候,他就把人家攬入懷中,當(dāng)他不需要人家的時(shí)候,就把別人踢開(kāi),而且,模塊總是能夠逆來(lái)順受,盡管Linux內(nèi)核會(huì)一次次拋棄她,但是每當(dāng)Linux內(nèi)核再次需要她的時(shí)候,當(dāng)內(nèi)核再次執(zhí)行insmod的時(shí)候,模塊依然會(huì)盡自己的能力去取悅內(nèi)核,這是否太可悲了些!記得孔子曾經(jīng)說(shuō)過(guò),讀懂Linux內(nèi)核代碼不難,難得是讀懂Linux內(nèi)核代碼背后的哲學(xué)!難道這就是傳說(shuō)中的藏在Linux代碼背后的哲學(xué)!天哪!

拋開(kāi)這見(jiàn)鬼的哲學(xué)吧.讓我們從一個(gè)偉大的例子去認(rèn)識(shí)模塊.這就是傳說(shuō)中的"Hello World!",這個(gè)夢(mèng)幻般的名字我們看過(guò)無(wú)數(shù)次了,每一次她出現(xiàn)在眼前,就意味著我們開(kāi)始接觸一種新的計(jì)算機(jī)語(yǔ)言了,或者,如此刻,開(kāi)始描述一個(gè)新的故事.

  請(qǐng)看下面這段代碼,她就是Linux下的一個(gè)最簡(jiǎn)單的模塊.當(dāng)你安裝這個(gè)模塊的時(shí)候,她會(huì)用她特有的語(yǔ)言向你表白,"Hello,world!",千真萬(wàn)確,她沒(méi)有說(shuō)"Honey,I love you!",雖然,她可以這么說(shuō),如果你要求她這么說(shuō).而后來(lái)你卸載了這個(gè)模塊,你無(wú)情拋棄了她,她很傷心,她很絕望,但她沒(méi)有抱怨,她只是淡淡地說(shuō),"Goodbye,cruel world!"(再見(jiàn),殘酷的世界!)

++++++++++++++++++hello.c++++++++++++++++++++

      1 #include <linux/init.h>  /* Needed for the macros */
      2 #include <linux/module.h> /* Needed for all modules */
      3 MODULE_LICENSE("Dual BSD/GPL");
      4 MODULE_AUTHOR("fudan_abc");
      5
      6 static int __init hello_init(void)
      7 {
      8         printk(KERN_ALERT "Hello, world!\n");
      9         return 0;
     10 }
     11
     12 static void __exit hello_exit(void)
     13 {
     14         printk(KERN_ALERT "Goodbye, cruel world\n");
     15 }
     16
     17 module_init(hello_init);
     18 module_exit(hello_exit);

++++++++++++++++++++++++++++++++++++++++++++++++

  你需要使用module_init()module_exit(),你可以稱(chēng)她們?yōu)楹瘮?shù),不過(guò)實(shí)際上她們是一些宏(macro),現(xiàn)在你可以不用去知道她們背后的故事,只需要知道,Linux Kernel 2.6的世界里,你寫(xiě)的任何一個(gè)模塊都需要使用她們來(lái)初始化或退出,或者說(shuō)注冊(cè)以及后來(lái)的注銷(xiāo).當(dāng)你用module_init()為一個(gè)模塊注冊(cè)了之后,在你使用insmod這個(gè)命令去安裝的時(shí)候,module_init()注冊(cè)的函數(shù)將會(huì)被執(zhí)行,而當(dāng)你用rmmod這個(gè)命令去卸載一個(gè)模塊的時(shí)候,module_exit()注冊(cè)的函數(shù)將會(huì)被執(zhí)行.module_init()被稱(chēng)為驅(qū)動(dòng)程序的初始化入口(driver initialization entry point).

  怎么樣演示以上代碼的運(yùn)行呢?沒(méi)錯(cuò),你需要一個(gè)Makefile.

+++++++++++++++++++++Makefile+++++++++++++++++++++++++++

      1 # To build modules outside of the kernel tree, we run "make"
      2 # in the kernel source tree; the Makefile these then includes this
      3 # Makefile once again.
      4 # This conditional selects whether we are being included from the
      5 # kernel Makefile or not.
      6 ifeq ($(KERNELRELEASE),)
      7
      8     # Assume the source tree is where the running kernel was built
      9     # You should set KERNELDIR in the environment if it's elsewhere
     10     KERNELDIR ?= /lib/modules/$(shell uname -r)/build
     11     # The current directory is passed to sub-makes as argument
     12     PWD := $(shell pwd)
     13
     14 modules:
     15         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
     16
     17 modules_install:
     18         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
     19
     20 clean:
     21         rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
     22
     23 .PHONY: modules modules_install clean
     24
     25 else
     26     # called from kernel build system: just declare what our modules are
     27     obj-m := hello.o
     28 endif
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 lwn上可以找到這個(gè)例子,你可以把以上兩個(gè)文件放在你的某個(gè)目錄下,然后執(zhí)行make,也許你不一定能成功,因?yàn)?/span>LK 2.6要求你編譯模塊之前,必須先在內(nèi)核源代碼目錄下執(zhí)行make,換言之,你必須先配置過(guò)內(nèi)核,執(zhí)行過(guò)make,然后才能make你自己的模塊.原因我就不細(xì)說(shuō)了,你按著她要求的這么去做就行了.在內(nèi)核頂層目錄make過(guò)之后,你就可以在你當(dāng)前放置Makefile的目錄下執(zhí)行make.Ok,make之后你就應(yīng)該看到一個(gè)叫做hello.ko的文件生成了,恭喜你,這就是你將要測(cè)試的模塊.

  執(zhí)行命令,

  #insmod hello.ko

  同時(shí)在另一個(gè)窗口,用命令tail -f /var/log/messages察看日志文件,你會(huì)看到

  Hello world被打印了出來(lái).

  再執(zhí)行命令,

  #rmmod hello.ko

  此時(shí),在另一窗口你會(huì)看到Goodbye,cruel world!被打印了出來(lái).

  到這里,我該恭喜你,因?yàn)槟阋呀?jīng)能夠編寫(xiě)Linux內(nèi)核模塊了.這種感覺(jué)很美妙,不是嗎?你可以嘲笑秦皇漢武略輸文采唐宗宋祖稍遜風(fēng)騷,還可以嘲笑一代天驕成吉思汗只識(shí)彎弓射大雕了. 是的,Twins姐姐(s)告訴我們,只要我喜歡,還有什么不可以.

  日后我們會(huì)看到,2.6內(nèi)核中,每個(gè)模塊都是以module_init開(kāi)始,以module_exit結(jié)束.大多數(shù)來(lái)說(shuō)沒(méi)有必要知道這是為什么,記住就可以了,相信每一個(gè)對(duì)Linux有一點(diǎn)常識(shí)的人都會(huì)知道這一點(diǎn)的,對(duì)大多數(shù)人來(lái)說(shuō),這就像是1+1為什么等于2一樣,就像是兩點(diǎn)之間最短的是直線,不需要證明,如果一定要證明兩點(diǎn)之間直線最短,可以扔一塊骨頭在B點(diǎn),讓一條狗從A點(diǎn)出發(fā),你會(huì)發(fā)現(xiàn)狗走的是直線,是的,狗都知道,你還能不知道嗎?

 

既然知道了怎么編寫(xiě)一個(gè)模塊,那么編寫(xiě)設(shè)備驅(qū)動(dòng)程序自然也就不難了.我相信,每一個(gè)會(huì)寫(xiě)模塊的人都不會(huì)覺(jué)得寫(xiě)設(shè)備驅(qū)動(dòng)有困難.對(duì)自己行不行不確定的話(huà),可以去問(wèn)一下葛優(yōu),他準(zhǔn)說(shuō):"(神州行),我看行."

真的,我沒(méi)說(shuō)假話(huà).寫(xiě)驅(qū)動(dòng)不是什么難事,你完全可以很自信的說(shuō),你已經(jīng)可以寫(xiě)Device Driver.對(duì),沒(méi)錯(cuò),飄柔,就這么自信.

前面說(shuō)了每一個(gè)模塊都是以module_init開(kāi)始,module_exit結(jié)束,那么我們就來(lái)看一下U盤(pán)的驅(qū)動(dòng)的這個(gè)模塊.在茫茫人海中,我們很容易找到這個(gè)文件:drivers/usb/storage/usb.c,在這個(gè)文件中又不難發(fā)現(xiàn)下面這段:

/***********************************************************************
   1056  * Initialization and registration
   1057  ***********************************************************************/
   1058
   1059 static int __init usb_stor_init(void)
   1060 {
   1061         int retval;
   1062         printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
   1063
   1064         /* register the driver, return usb_register return code if error */
   1065         retval = usb_register(&usb_storage_driver);
   1066         if (retval == 0)
   1067                 printk(KERN_INFO "USB Mass Storage support registered.\n");
   1068
   1069         return retval;
   1070 }
   1071
   1072 static void __exit usb_stor_exit(void)
   1073 {
   1074         US_DEBUGP("usb_stor_exit() called\n");
   1075
   1076         /* Deregister the driver
   1077          * This will cause disconnect() to be called for each
   1078          * attached unit
   1079          */
   1080         US_DEBUGP("-- calling usb_deregister()\n");
   1081         usb_deregister(&usb_storage_driver) ;
   1082 }
   1083
   1084 module_init(usb_stor_init);
   1085 module_exit(usb_stor_exit);

  其實(shí),module_init/module_exit只是一個(gè)宏,通常寫(xiě)模塊的人為了彰顯自己的個(gè)性,會(huì)給自己的初始化函數(shù)和注銷(xiāo)函數(shù)另外起個(gè)名字,比如這里module_init(usb_stor_init)以及module_exit(usb_stor_exit)實(shí)際上就是告訴這個(gè)世界,真正的函數(shù)是usb_stor_initusb_stor_exit.這種伎倆在Linux內(nèi)核代碼中屢見(jiàn)不鮮.見(jiàn)多了也就不必大驚小怪了,天要下雨娘要嫁人,隨她去吧.我們下面當(dāng)然就從usb_stor_init正式開(kāi)始我們的探索之旅.

 

看代碼之前,我曾經(jīng)認(rèn)真的思考過(guò)這么一個(gè)問(wèn)題,我需要關(guān)注的僅僅是drivers/usb/storage/目錄下面那相關(guān)的3000多行代碼嗎?就是這樣幾個(gè)文件就能讓一個(gè)個(gè)不同的U盤(pán)在Linux下面工作起來(lái)嗎? 像一開(kāi)始那樣把這個(gè)目錄比作一個(gè)小城的話(huà),也許,城里的月光很漂亮,她能夠把人的夢(mèng)照亮,能夠溫暖人的心房.但我們真的就能廝守在這個(gè)城里,一生一世嗎?

很不幸,問(wèn)題遠(yuǎn)不是這樣簡(jiǎn)單.外面的世界很精彩,作為U盤(pán),她需要與usb core打交道,需要與scsi core打交道,需要與內(nèi)存管理單元打交道,還有內(nèi)核中許許多多其它模塊打交道.外面的世界很大,遠(yuǎn)比我們想象的大.

什么是usb core?她負(fù)責(zé)實(shí)現(xiàn)一些核心的功能,為別的設(shè)備驅(qū)動(dòng)程序提供服務(wù),比如申請(qǐng)內(nèi)存,比如實(shí)現(xiàn)一些所有的設(shè)備都會(huì)需要的公共的函數(shù),事實(shí)上,在usb的世界里,一個(gè)普通的設(shè)備要正常的工作,除了要有設(shè)備本身以外,還需要有一個(gè)叫做控制器的冬冬,老外把它叫做host controller,和這個(gè)控制器相連接在一起的有另一個(gè)咚咚,她叫root hub,hub我們應(yīng)該不會(huì)陌生,在大學(xué)里,有的宿舍里網(wǎng)口有限,但是我們這一代人上大學(xué)基本上是每人一臺(tái)電腦,所以網(wǎng)口不夠,于是有人會(huì)使用hub,讓多個(gè)人共用一個(gè)網(wǎng)口,這是以太網(wǎng)上的hub,而usb的世界里同樣有hub,其實(shí)原理是一樣的,任何支持usb的電腦不會(huì)說(shuō)只允許你只能一個(gè)時(shí)刻使用一個(gè)usb設(shè)備,比如你插入了u盤(pán),你同樣還可以插入usb鍵盤(pán),還可以再插一個(gè)usb鼠標(biāo),因?yàn)槟銜?huì)發(fā)現(xiàn)你的電腦里并不只是一個(gè)usb接口.這些口實(shí)際上就是所謂的hub口.而現(xiàn)實(shí)中經(jīng)常是讓一個(gè)usb控制器和一個(gè)hub綁定在一起,專(zhuān)業(yè)一點(diǎn)說(shuō)叫集成,而這個(gè)hub也被稱(chēng)作root hub,換言之,和usb控制器綁定在一起的hub就是系統(tǒng)中最根本的hub,其它的hub可以連接到她這里,然后可以延伸出去,外接別的設(shè)備,當(dāng)然也可以不用別的hub,讓usb設(shè)備直接接到root hub上.hub干嘛用的我們知道了,那么usb host controller本身是干什么用的呢?controller,控制器,顧名思義,用于控制,控制什么,控制所有的usb設(shè)備的通信.通常計(jì)算機(jī)的cpu并不是直接和usb設(shè)備打交道,而是和控制器打交道,他要對(duì)設(shè)備做什么,他會(huì)告訴控制器,而不是直接把指令發(fā)給設(shè)備,然后控制器再去負(fù)責(zé)處理這件事情,他會(huì)去指揮設(shè)備執(zhí)行命令,而cpu就不用管剩下的事情,他還是該干嘛干嘛去,控制器替他去完成剩下的事情,事情辦完了再通知cpu.否則讓cpu去盯著每一個(gè)設(shè)備做每一件事情,那是不現(xiàn)實(shí)的,那就好比讓一個(gè)學(xué)院的院長(zhǎng)去盯著我們每一個(gè)本科生上課,去管理我們的出勤,只能說(shuō),不現(xiàn)實(shí).所以我們就被分成了幾個(gè)系,通常院長(zhǎng)有什么指示直接跟各系領(lǐng)導(dǎo)說(shuō)就可以了,如果他要和三個(gè)系主任說(shuō)事情,他即使不把三個(gè)人都召集起來(lái)開(kāi)個(gè)會(huì),也可以給三個(gè)人各打一個(gè)電話(huà),打完電話(huà)他就忙他自己的事情去了,比如去和他帶的女碩士風(fēng)花雪月.而三個(gè)系主任就會(huì)去安排下面的人去執(zhí)行具體的任務(wù),完了之后他們就會(huì)像院長(zhǎng)匯報(bào).

所以,Linux內(nèi)核開(kāi)發(fā)者們,專(zhuān)門(mén)寫(xiě)了一些代碼,并美其名曰usb core.時(shí)代總在發(fā)展,當(dāng)年胖楊貴妃照樣迷死唐明皇,而如今人們欣賞的則是林志玲這樣的魔鬼身材.同樣,早期的Linux內(nèi)核,其結(jié)構(gòu)并不是如今天這般有層次感,遠(yuǎn)不像今天這般錯(cuò)落有致,那時(shí)候drivers/usb/這個(gè)目錄下邊放了很多很多文件,usb core與其他各種設(shè)備的驅(qū)動(dòng)程序的代碼都堆砌在這里,后來(lái),怎奈世間萬(wàn)千的變幻,總愛(ài)把有情的人分兩端.于是在drivers/usb/目錄下面出來(lái)了一個(gè)core目錄,就專(zhuān)門(mén)放一些核心的代碼,比如初始化整個(gè)usb系統(tǒng),初始化root hub,初始化host controller的代碼,再后來(lái)甚至把host controller相關(guān)的代碼也單獨(dú)建了一個(gè)目錄,叫host目錄,這是因?yàn)閡sb host controller隨著時(shí)代的發(fā)展,也開(kāi)始有了好幾種,不再像剛開(kāi)始那樣只有一種,所以呢,設(shè)計(jì)者們把一些host controller公共的代碼仍然留在core目錄下,而一些各host controller單獨(dú)的代碼則移到host目錄下面讓負(fù)責(zé)各種host controller的人去維護(hù),常見(jiàn)的host controller有三種,分別叫做EHCI,UHCI,OHCI,所以這樣,出來(lái)了三個(gè)概念,usb core,usb host,usb device,即原本是一家人,卻被活生生的分成了兩岸三地...的確,現(xiàn)實(shí)總是很無(wú)奈,然而,心若知道靈犀的方向,哪怕不能夠朝夕相伴?沒(méi)錯(cuò),usb通信的靈魂就是usb協(xié)議. usb協(xié)議將是所有usb設(shè)備和usb主機(jī)所必須遵循的游戲規(guī)則.這種規(guī)則也很自然的體現(xiàn)在了代碼中.于是,我們需要了解的不僅僅是drivers/usb/storage/目錄下面的冬冬,還得去了解那外面的世界,雖然,只需要了解一點(diǎn)點(diǎn).

還是回到那個(gè)初始化函數(shù)吧,usb_stor_init,看了它的代碼每一個(gè)人的心中都有一種莫名的興奮,因?yàn)樗塘?就那么幾行,除了兩個(gè)printk語(yǔ)句以外,就是一個(gè)函數(shù)的調(diào)用,usb_register.

printk不用我說(shuō),每一個(gè)有志青年都該知道,就算沒(méi)見(jiàn)過(guò)printk也該見(jiàn)過(guò)printf吧,否則的話(huà),你捫心自問(wèn),你對(duì)得起譚浩強(qiáng)大哥嗎?在譚浩強(qiáng)大哥的帶領(lǐng)下我們學(xué)會(huì)了用#include<stdio.h>->main()->printf()來(lái)打印hello,world!從而向全世界展示了我們懂C語(yǔ)言.而stdio.h就是一個(gè)C庫(kù),printf是一個(gè)函數(shù),來(lái)自函數(shù)庫(kù),可是內(nèi)核中沒(méi)有標(biāo)準(zhǔn)C庫(kù),所以開(kāi)發(fā)者們自己準(zhǔn)備了一些函數(shù),專(zhuān)門(mén)用于內(nèi)核代碼中,所以就出來(lái)了一個(gè)printk,printk的"k"就是kernel,內(nèi)核.所以我們只要把它當(dāng)作printf的兄弟即可,如果感興趣,可以去研究一下printk的特點(diǎn),她和printf多少有些不同,但基本思想是一樣的.所以我們就不多講了,當(dāng)然驅(qū)動(dòng)程序中所有的printk語(yǔ)句對(duì)U盤(pán)的工作都沒(méi)有什么用,她無(wú)非是打出來(lái)給我們看的,或者說(shuō)打印給用戶(hù)看,或者呢,打印給開(kāi)發(fā)者看,特別是開(kāi)發(fā)者要調(diào)試程序的時(shí)候,就會(huì)很有用.

于是我們更開(kāi)心了,不用看printk的話(huà),那就只有一個(gè)函數(shù)調(diào)用了,usb_register.這個(gè)函數(shù)是干嘛的?首先這個(gè)函數(shù)正是來(lái)自u(píng)sb core.凡是usb設(shè)備驅(qū)動(dòng),都要調(diào)用這個(gè)函數(shù)來(lái)向usb core注冊(cè),從而讓usb core知道有這么一個(gè)設(shè)備.這就像政府規(guī)定,一對(duì)夫妻結(jié)婚要到相關(guān)部門(mén)那里去登記是一樣的,我們無(wú)需知道政府是如何管理的,只需要知道去政府那里登記即可.

這樣,insmod的時(shí)候,usb_stor_init這個(gè)函數(shù)會(huì)被調(diào)用,初始化就算完成了.于是設(shè)備就開(kāi)始工作了...而當(dāng)我們r(jià)mmod的時(shí)候,usb_stor_exit這個(gè)函數(shù)會(huì)被調(diào)用,我們發(fā)現(xiàn),這個(gè)函數(shù)也很短,我們能看出來(lái),US_DEBUG也就是打印一些咚咚,因此,這里實(shí)際上也就是調(diào)用了一個(gè)函數(shù)usb_deregister(),她和usb_register()是一對(duì),完成了注銷(xiāo)的工作,從此設(shè)備就從usb core中消失了.于是我們驚人的發(fā)現(xiàn),編寫(xiě)設(shè)備驅(qū)動(dòng)竟是如此的簡(jiǎn)單,驅(qū)動(dòng)程序真的就這么結(jié)束了?...

這一切,不禁讓人產(chǎn)生了一種幻覺(jué),讓人分不清故事從哪里開(kāi)始,又從哪里結(jié)束,一切都太短暫了.仿佛開(kāi)始在結(jié)束的時(shí)候開(kāi)始,而結(jié)束卻在開(kāi)始的時(shí)候就早已結(jié)束.

真的嗎?

答案是否定的.孔子已經(jīng)教育過(guò)我們,不光要看懂代碼,更要理解代碼背后的哲學(xué).

所以我們?cè)诶^續(xù)之前,先來(lái)看看這里到底有什么哲學(xué).而這,就是偉大的Linux Kernel 2.6中的統(tǒng)一的設(shè)備模型.

我們并無(wú)意去詳細(xì)介紹2.6中的設(shè)備模型,但是不懂設(shè)備模型又怎能說(shuō)自己懂設(shè)備驅(qū)動(dòng)呢?讀代碼的人,寫(xiě)代碼的人,都要知道,什么是設(shè)備驅(qū)動(dòng)?什么又是設(shè)備?設(shè)備和驅(qū)動(dòng)之間究竟是什么關(guān)系?設(shè)備如何與計(jì)算機(jī)主機(jī)聯(lián)系起來(lái)?我相信在中關(guān)村買(mǎi)盜版光盤(pán)的哥們兒也能回答這個(gè)問(wèn)題.計(jì)算機(jī)世界里,設(shè)備有很多種類(lèi),比如PCI設(shè)備,比如ISA設(shè)備,再比如SCSI設(shè)備,再比如我們這里的USB設(shè)備.為設(shè)備聯(lián)姻的是總線,是他把設(shè)備連入了計(jì)算機(jī)主機(jī).但是與其說(shuō)設(shè)備是嫁給了計(jì)算機(jī)主機(jī),倒不如說(shuō)設(shè)備是嫁給了設(shè)備驅(qū)動(dòng)程序.很顯然,在計(jì)算機(jī)世界里,無(wú)論風(fēng)里雨里,陪伴著設(shè)備的正是驅(qū)動(dòng)程序.

唯一的遺憾是,計(jì)算機(jī)中的設(shè)備和驅(qū)動(dòng)程序的關(guān)系卻并非如可樂(lè)和拉環(huán)的關(guān)系那樣,一對(duì)一.然而世上又有多少事情總能如人愿呢.

Linux設(shè)備模型中三個(gè)很重要的概念就是總線,設(shè)備,驅(qū)動(dòng).即bus,device,driver,而實(shí)際上內(nèi)核中也定義了這么一些數(shù)據(jù)結(jié)構(gòu),他們是struct bus_type,struct device,struct device_driver,這三個(gè)重要的數(shù)據(jù)結(jié)構(gòu)都來(lái)自一個(gè)地方,include/linux/device.h.我們知道總線有很多種,pci總線,scsi總線,usb總線,所以我們會(huì)看到Linux內(nèi)核代碼中出現(xiàn)pci_bus_type,scsi_bus_type,usb_bus_type,他們都是struct bus_type類(lèi)型的變量.而struct bus_type結(jié)構(gòu)中兩個(gè)非常重要的成員就是struct kset drivers和struct kset devices.kset和另一個(gè)叫做kobject正是Linux Kernel 2.6中設(shè)備模型的基本元素,但此處我們卻不愿多講,因?yàn)闀簳r(shí)不用去認(rèn)識(shí)他們.我們的生命中會(huì)遇見(jiàn)許許多多的人和事,但更多的人和事與我們只是擦肩而過(guò),只是我們生命中的過(guò)客而已.在我們?nèi)松碾娪爸?他們也許只有一個(gè)鏡頭,甚至那一個(gè)鏡頭后來(lái)也被剪輯掉了.這里我們只需要知道,drivers和devices的存在,讓struct bus_type與兩個(gè)鏈表聯(lián)系了起來(lái),一個(gè)是devices的鏈表,一個(gè)是drivers的鏈表,也就是說(shuō),知道一條總線所對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu),就可以找到這條總線所關(guān)聯(lián)的設(shè)備有哪些,又有哪些支持這類(lèi)設(shè)備的驅(qū)動(dòng)程序.

而要實(shí)現(xiàn)這些,就要求每次出現(xiàn)一個(gè)設(shè)備就要向總線匯報(bào),或者說(shuō)注冊(cè),每次出現(xiàn)一個(gè)驅(qū)動(dòng),也要向總線匯報(bào),或者說(shuō)注冊(cè).比如系統(tǒng)初始化的時(shí)候,會(huì)掃描連接了哪些設(shè)備,并為每一個(gè)設(shè)備建立起一個(gè)struct device的變量,每一次有一個(gè)驅(qū)動(dòng)程序,就要準(zhǔn)備一個(gè)struct device_driver結(jié)構(gòu)的變量.把這些變量統(tǒng)統(tǒng)加入相應(yīng)的鏈表,device插入devices鏈表,driver插入drivers鏈表. 這樣通過(guò)總線就能找到每一個(gè)設(shè)備,每一個(gè)驅(qū)動(dòng).

然而,假如計(jì)算機(jī)里只有設(shè)備卻沒(méi)有對(duì)應(yīng)的驅(qū)動(dòng),那么設(shè)備無(wú)法工作.反過(guò)來(lái),倘若只有驅(qū)動(dòng)卻沒(méi)有設(shè)備,驅(qū)動(dòng)也起不了任何作用.在他們遇見(jiàn)彼此之前,雙方都如同路埂的野草,一個(gè)飄啊飄,一個(gè)搖啊搖,誰(shuí)也不知道未來(lái)在哪里,只能在生命的風(fēng)里飄搖.于是總線上的兩張表里就慢慢的就掛上了那許多孤單的靈魂.devices開(kāi)始多了,drivers開(kāi)始多了,他們像是兩個(gè)來(lái)自世界,devices們彼此取暖,drivers們一起狂歡,但他們有一點(diǎn)是相同的,都只是在等待屬于自己的那個(gè)另一半.

看代碼的我,一直好奇的想知道,他們是否和我們現(xiàn)實(shí)中一樣,有些人注定是等別人,而有些人是注定被人等的.

struct bus_type中為devices和drivers準(zhǔn)備了兩個(gè)鏈表,而代表device的結(jié)構(gòu)體struct device中又有兩個(gè)成員,struct bus_type *bus和struct device_driver *driver,同樣,代表driver的結(jié)構(gòu)體struct device_driver同樣有兩個(gè)成員,struct bus_type *bus和struct list_head devices,struct device和struct device_driver的定義和struct bus_type一樣,在include/linux/device.h中.憑一種男人的直覺(jué),可以知曉,struct device中的bus記錄的是這個(gè)設(shè)備連在哪條總線上,driver記錄的是這個(gè)設(shè)備用的是哪個(gè)驅(qū)動(dòng),反過(guò)來(lái),struct device_driver中的bus代表的也是這個(gè)驅(qū)動(dòng)屬于哪條總線,devices記錄的是這個(gè)驅(qū)動(dòng)支持的那些設(shè)備,沒(méi)錯(cuò),是devices(復(fù)數(shù)),而不是device(單數(shù)),因?yàn)橐粋€(gè)驅(qū)動(dòng)程序可以支持一個(gè)或多個(gè)設(shè)備,反過(guò)來(lái)一個(gè)設(shè)備則只會(huì)綁定給一個(gè)驅(qū)動(dòng)程序.

  1. 于是我們想知道,關(guān)于bus,關(guān)于device,關(guān)于driver,他們是如何建立聯(lián)系的呢?換言之,這三個(gè)數(shù)據(jù)結(jié)構(gòu)中的指針是如何被賦值的?絕對(duì)不可能發(fā)生的事情是,一旦為一條總線申請(qǐng)了一個(gè)struct bus_type的數(shù)據(jù)結(jié)構(gòu)之后,它就知道它的devices鏈表和drivers鏈表會(huì)包含哪些東西,這些咚咚一定不會(huì)是先天就有的,只能是后天填進(jìn)來(lái)的.而具體到usb系統(tǒng),完成這個(gè)工作的就是usb core.usb core的代碼會(huì)進(jìn)行整個(gè)usb系統(tǒng)的初始化,比如申請(qǐng)struct bus_type usb_bus_type,然后會(huì)掃描usb總線,看線上連接了哪些usb設(shè)備,或者說(shuō)root hub上連了哪些usb設(shè)備,比如說(shuō)連了一個(gè)usb鍵盤(pán),那么就為它準(zhǔn)備一個(gè)struct device,根據(jù)它的實(shí)際情況,為這個(gè)struct device賦值,并插入devices鏈表中來(lái).又比如root hub上連了一個(gè)普通的hub,那么除了要為這個(gè)hub本身準(zhǔn)備一個(gè)struct device以外,還得繼續(xù)掃描看這個(gè)hub上是否又連了別的設(shè)備,有的話(huà)繼續(xù)重復(fù)之前的事情,這樣一直進(jìn)行下去,直到完成整個(gè)掃描,最終就把usb_bus_type中的devices鏈表給建立了起來(lái).

那么drivers鏈表呢?這個(gè)就不用bus方面主動(dòng)了,而該由每一個(gè)driver本身去bus上面登記,或者說(shuō)掛牌.具體到usb系統(tǒng),每一個(gè)usb設(shè)備的驅(qū)動(dòng)程序都會(huì)有一個(gè)struct usb_driver結(jié)構(gòu)體,其代碼如下,來(lái)自include/linux/usb.h

    485 /* -------------------------------------------------------------------------- */
    486
    487 /**
    488  * struct usb_driver - identifies USB driver to usbcore
    489  * @owner: Pointer to the module owner of this driver; initialize
    490  *      it using THIS_MODULE.
    491  * @name: The driver name should be unique among USB drivers,
    492  *      and should normally be the same as the module name.
    493  * @probe: Called to see if the driver is willing to manage a particular
    494  *      interface on a device.  If it is, probe returns zero and uses
    495  *      dev_set_drvdata() to associate driver-specific data with the
    496  *      interface.  It may also use usb_set_interface() to specify the
    497  *      appropriate altsetting.  If unwilling to manage the interface,
    498  *      return a negative errno value.
    499  * @disconnect: Called when the interface is no longer accessible, usually
    500  *      because its device has been (or is being) disconnected or the
    501  *      driver module is being unloaded.
    502  * @ioctl: Used for drivers that want to talk to userspace through
    503  *      the "usbfs" filesystem.  This lets devices provide ways to
    504  *      expose information to user space regardless of where they
    505  *      do (or don't) show up otherwise in the filesystem.
    506  * @suspend: Called when the device is going to be suspended by the system.
    507  * @resume: Called when the device is being resumed by the system.
    508  * @id_table: USB drivers use ID table to support hotplugging.
    509  *      Export this with MODULE_DEVICE_TABLE(usb,...).  This must be set
    510  *      or your driver's probe function will never get called.
    511  * @driver: the driver model core driver structure.
    512  *
    513  * USB drivers must provide a name, probe() and disconnect() methods,
    514  * and an id_table.  Other driver fields are optional.
    515  *
    516  * The id_table is used in hotplugging.  It holds a set of descriptors,
    517  * and specialized data may be associated with each entry.  That table
    518  * is used by both user and kernel mode hotplugging support.
    519  *
    520  * The probe() and disconnect() methods are called in a context where
    521  * they can sleep, but they should avoid abusing the privilege.  Most
    522  * work to connect to a device should be done when the device is opened,
    523  * and undone at the last close.  The disconnect code needs to address
    524  * concurrency issues with respect to open() and close() methods, as
    525  * well as forcing all pending I/O requests to complete (by unlinking
    526  * them as necessary, and blocking until the unlinks complete).
    527  */
    528 struct usb_driver {
    529         struct module *owner;
    530
    531         const char *name;
    532
    533         int (*probe) (struct usb_interface *intf,
    534                       const struct usb_device_id *id);
    535
    536         void (*disconnect) (struct usb_interface *intf);
    537
    538         int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
    539
    540         int (*suspend) (struct usb_interface *intf, u32 state);
    541         int (*resume) (struct usb_interface *intf);
    542
    543         const struct usb_device_id *id_table;
    544
    545         struct device_driver driver;
    546 };
    547 #define to_usb_driver(d) container_of(d, struct usb_driver, driver)
  看似很長(zhǎng)一段,實(shí)際上也就是注釋為主.而此刻我們只需注意到其中的struct device_driver driver這個(gè)成員,usb core為每一個(gè)設(shè)備驅(qū)動(dòng)準(zhǔn)備了一個(gè)函數(shù),讓它把自己的這個(gè)struct device_driver driver插入到usb_bus_type中的drivers鏈表中去.而這個(gè)函數(shù)正是我們此前看到的usb_register.而與之對(duì)應(yīng)的usb_deregister所從事的正是與之相反的工作,把這個(gè)結(jié)構(gòu)體從drivers鏈表中刪除.可以說(shuō),usb core的確是用心良苦,為每一個(gè)usb設(shè)備驅(qū)動(dòng)做足了功課,正因?yàn)槿绱?作為一個(gè)實(shí)際的usb設(shè)備驅(qū)動(dòng),它在初始化階段所要做的事情就很少,很簡(jiǎn)單了,直接調(diào)用usb_register即可.事實(shí)上,沒(méi)有人是理所當(dāng)然應(yīng)該為你做什么的,但usb core這么做了.所以每一個(gè)寫(xiě)usb設(shè)備驅(qū)動(dòng)的人應(yīng)該銘記,usb device driver絕不是一個(gè)人在工作,在他身后,是usb core所提供的默默無(wú)聞?dòng)植豢苫蛉钡闹С?

bus上的兩張鏈表記錄了每一個(gè)devicedriver,那么devicedriver這兩者之間又是如何聯(lián)系起來(lái)的呢?此刻,必須拋出這樣一個(gè)問(wèn)題,先有device還是driver?

很久很久以前,在那激情燃燒的歲月里,先有的是device,每一個(gè)要用的device在計(jì)算機(jī)啟動(dòng)之前就已經(jīng)插好了,插放在它應(yīng)該在的位置上,然后計(jì)算機(jī)啟動(dòng),然后操作系統(tǒng)開(kāi)始初始化,總線開(kāi)始掃描設(shè)備,每找到一個(gè)設(shè)備,就為其申請(qǐng)一個(gè)struct device結(jié)構(gòu),并且掛入總線中的devices鏈表中來(lái),然后每一個(gè)驅(qū)動(dòng)程序開(kāi)始初始化,開(kāi)始注冊(cè)其struct device_driver結(jié)構(gòu),然后它去總線的devices鏈表中去尋找(遍歷),去尋找每一個(gè)還沒(méi)有綁定driver的設(shè)備,struct device中的struct device_driver指針仍為空的設(shè)備,然后它會(huì)去觀察這種設(shè)備的特征,看是否是他所支持的設(shè)備,如果是,那么調(diào)用一個(gè)叫做device_bind_driver的函數(shù),然后他們就結(jié)為了秦晉之好.換句話(huà)說(shuō),struct device中的struct device_driver driver指向這個(gè)driver,struct device_driver driverstruct device加入他的那張struct list_head devices鏈表中來(lái).就這樣,bus,device,driver,這三者之間或者說(shuō)他們中的兩兩之間,就給聯(lián)系上了.知道其中之一,就能找到另外兩個(gè).一榮俱榮,一損俱損.

但現(xiàn)在情況變了,在這紅蓮綻放的日子里,在這櫻花傷逝的日子里,出現(xiàn)了一種新的名詞,叫熱插拔.device可以在計(jì)算機(jī)啟動(dòng)以后在插入或者拔出計(jì)算機(jī)了.因此,很難再說(shuō)是先有device還是先有driver了.因?yàn)槎加锌赡?device可以在任何時(shí)刻出現(xiàn),而driver也可以在任何時(shí)刻被加載,所以,出現(xiàn)的情況就是,每當(dāng)一個(gè)struct device誕生,它就會(huì)去bus的drivers鏈表中尋找自己的另一半,反之,每當(dāng)一個(gè)struct device_driver誕生,它就去bus的devices鏈表中尋找它的那些設(shè)備.如果找到了合適的,那么ok,和之前那種情況一下,調(diào)用device_bind_driver綁定好.如果找不到,沒(méi)有關(guān)系,等待吧,等到曇花再開(kāi),等到風(fēng)景看透,心中相信,這世界上總有一個(gè)人是你所等的,只是還沒(méi)有遇到而已.

好,繼續(xù),事實(shí)上,完善這個(gè)三角關(guān)系,正是每一個(gè)設(shè)備驅(qū)動(dòng)初始化階段所完成的重要使命之一.讓我們還是回到代碼中來(lái),usb_register這個(gè)函數(shù)調(diào)用是調(diào)用了,但是傳遞給他的參數(shù)是什么呢?

我們注意到,那句調(diào)用是這樣子的,

   1064         /* register the driver, return usb_register return code if error */
   1065         retval = usb_register(&usb_storage_driver);

是的,傳遞了一個(gè)叫做usb_storage_driver的家伙,這是什么?同一文件中,drivers/usb/storage/usb.c:

    232 struct usb_driver usb_storage_driver = {
    233         .owner =        THIS_MODULE,
    234         .name =         "usb-storage",
    235         .probe =        storage_probe,
    236         .disconnect =   storage_disconnect,
    237         .id_table =     storage_usb_ids,
    238 };


可以看到這里定義了一個(gè)struct usb_driver的結(jié)構(gòu)體變量,usb_storage_driver,關(guān)于usb_driver我們上節(jié)已經(jīng)說(shuō)過(guò)了,當(dāng)時(shí)主要說(shuō)的是其中的成員driver,而眼下要講的則是另外幾個(gè)成員.首先,.owner.name這兩個(gè)沒(méi)啥好多說(shuō)的,owner這玩藝是用來(lái)給模塊計(jì)數(shù)的,每個(gè)模塊都這么用,賦值總是THIS_MODULE,name就是這個(gè)模塊的名字,usb core會(huì)處理它,所以如果這個(gè)模塊正常被加載了的話(huà),使用lsmod命令能看到一個(gè)叫做usb-storage的模塊名.重點(diǎn)要講一講,.probe.disconnect以及這個(gè)id_table.

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多

    日本欧美三级中文字幕| 五月婷婷欧美中文字幕| 国产精品熟女乱色一区二区| 在线免费看国产精品黄片| 好吊日视频这里都是精品| 日本女优一区二区三区免费| 中日韩美女黄色一级片| 欧美午夜不卡在线观看| 欧美自拍系列精品在线| 国产一区二区三区免费福利 | 极品熟女一区二区三区| 国产成人精品视频一二区| 真实国产乱子伦对白视频不卡| 国产精品欧美一区二区三区不卡| 日韩欧美中文字幕人妻| 九九热国产这里只有精品| 一区二区欧美另类稀缺| 国产精品香蕉在线的人| 国产免费成人激情视频| 久久精品国产99国产免费| 丰满熟女少妇一区二区三区| 日韩一区二区三区免费av| 91人妻人澡人人爽人人精品| 有坂深雪中文字幕亚洲中文| 日韩不卡一区二区在线| 国产精品超碰在线观看| 大屁股肥臀熟女一区二区视频 | 久草国产精品一区二区| 色偷偷偷拍视频在线观看| 东京热男人的天堂社区| 五月婷婷综合激情啪啪| 日本乱论一区二区三区| 亚洲中文字幕在线乱码av| 国产av熟女一区二区三区四区| 婷婷基地五月激情五月| 成人国产激情在线视频| 中文日韩精品视频在线| 最近的中文字幕一区二区| 国产亚洲神马午夜福利| 欧美自拍系列精品在线| 少妇特黄av一区二区三区|