7.最熟悉的陌生人--probe
話說因爲Hub驅動無所事事,所以hub_thread()進入了睡眠,直到某一天,hub_probe被調用。所以我們來看hub_probe(),這個函數來自drivers/usb/hub.c,其作用就如同當初我們在usb-storage中遇到的那個storage_probe()函數一樣。
- 887 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
- 888 {
- 889 struct usb_host_interface *desc;
- 890 struct usb_endpoint_descriptor *endpoint;
- 891 struct usb_device *hdev;
- 892 struct usb_hub *hub;
- 893
- 894 desc = intf->cur_altsetting;
- 895 hdev = interface_to_usbdev(intf);
- 896
- 897 #ifdef CONFIG_USB_OTG_BLACKLIST_HUB
- 898 if (hdev->parent) {
- 899 dev_warn(&intf->dev, "ignoring external hub\n");
- 900 return -ENODEV;
- 901 }
- 902 #endif
- 903
- 904 /* Some hubs have a subclass of 1, which AFAICT according to the */
- 905 /* specs is not defined, but it works */
- 906 if ((desc->desc.bInterfaceSubClass != 0) &&
- 907 (desc->desc.bInterfaceSubClass != 1)) {
- 908 descriptor_error:
- 909 dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
- 910 return -EIO;
- 911 }
- 912
- 913 /* Multiple endpoints? What kind of mutant ninja-hub is this? */
- 914 if (desc->desc.bNumEndpoints != 1)
- 915 goto descriptor_error;
- 916
- 917 endpoint = &desc->endpoint[0].desc;
- 918
- 919 /* If it's not an interrupt in endpoint, we'd better punt! */
- 920 if (!usb_endpoint_is_int_in(endpoint))
- 921 goto descriptor_error;
- 922
- 923 /* We found a hub */
- 924 dev_info (&intf->dev, "USB hub found\n");
- 925
- 926 hub = kzalloc(sizeof(*hub), GFP_KERNEL);
- 927 if (!hub) {
- 928 dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
- 929 return -ENOMEM;
- 930 }
- 931
- 932 INIT_LIST_HEAD(&hub->event_list);
- 933 hub->intfdev = &intf->dev;
- 934 hub->hdevhdev = hdev;
- 935 INIT_DELAYED_WORK(&hub->leds, led_work);
- 936
- 937 usb_set_intfdata (intf, hub);
- 938 intf->needs_remote_wakeup = 1;
- 939
- 940 if (hdev->speed == USB_SPEED_HIGH)
- 941 highspeed_hubs++;
- 942
- 943 if (hub_configure(hub, endpoint) >= 0)
- 944 return 0;
- 945
- 946 hub_disconnect (intf);
- 947 return -ENODEV;
- 948 }
幸運的是這個函數還不是很長。894行,desc,是這個函數中定義的一個struct usb_host_ interface結構體指針,其實這就相當於struct usb_interface結構中的那個altsetting,只是換了一個名字。
同樣895行這個賦值我們也很眼熟, interface_to_usbdev()這個宏就是爲了從一個struct usb_interface的結構體指針得到那個與它相關的struct usb_device結構體指針。這裏等號右邊的intf自不必說,而左邊的hdev正是我們這裏爲了Hub而定義的一個struct usb_device結構體指針。
897行到902行,這是爲OTG而準備的,爲了簡化問題,在這裏我做一個假設,即假設我們不支持OTG。在內核編譯選項中有一個叫做CONFIG_USB_OTG的選項,OTG就是"On The Go"(正在進行中)的意思,隨着USB傳輸協議的誕生,以及它的迅速走紅,人們不再滿足於以前那種一個設備要麼就是主設備,要麼就是從設備的現狀,也就是說要麼是Host(或者叫主設備);要麼是外設(也叫Slave,或者叫從設備)。在那個年代裏,只有當一臺Host與一臺Slave連接時才能實現數據的傳輸,而後來開發人員們又公佈了USB OTG規範,於是出現了OTG設備,即既可以充當Host,亦能充當Slave的設備。也就是說如果你有一臺數碼相機和一臺打印機,它們各有一個USB接口,把這兩個口連接起來,就可以把你的照片打印出來了。所以我只能假設我們不打開支持OTG的編譯開關,而這裏我們看到的CONFIG_USB_OTG_ BLACKLIST_HUB,其實就是CONFIG_OTG下面的子選項,不選後者根本就見不到前者。
904行到911行,這沒什麼可說的了,每一個USB設備它屬於哪個類,以及哪個子類這都是定好的,比如Hub的子類就是0,即desc->desc這個interface描述符裏邊的bInterfaceSubClass就應該是0。所以這裏是判斷如果bInterfaceSubClass不爲0那就出錯了,那就不往下走了,返回值是-EIO。
914行和915行,其實幹的事情是差不多的,針對接口描述符再做一次判斷,這次是判斷這個Hub有幾個端點。spec規定了Hub只有一個端點(除去端點0)也就是中斷端點,因爲Hub的傳輸是中斷傳輸。當然還有控制傳輸,但是因爲控制傳輸是每一個設備都必須支持的,即每一個USB設備都會有一個控制端點,所以在desc->desc.bNumEndpoints中是不包含那個大家都有的控制端點的。因此如果這個值不爲1,那麼就說明又出錯了,仍然只能是返回。
917行,得到這個唯一的端點所對應的端點描述符,920行和921行就是判斷這個端點是不是中斷端點,如果不是,那還是一樣,返回報錯吧。
如果以上幾種常見的錯誤都沒有出現,這個時候我們纔開始正式地去做一些事情,讓我們繼續。
924行,打印調試信息。
926行,申請Hub的數據結構struct usb_hub。不過926行有一個很新的函數,kzalloc()。其實這個函數就是原來的兩個函數的整合,即原來我們每次申請內存時都會這麼做,先是用kmalloc()申請空間,然後用me mset()來初始化,而現在一步到位,直接調用kzalloc()函數,效果等同於原來那兩個函數,所有申請的元素都被初始化爲0。
其實對於寫驅動的人來說,知道現在應該用kzalloc()函數代替原來的kmalloc()和me mset()函數就可以了,這是內核中內存管理部分做出的改變,確切地說是改進。負責內存管理那部分程序的目標無非就是讓內核跑起來更快一些,而從kmalloc/me mset到kzalloc的改變確實也是爲了實現這方面的優化。所以自從2005年底內核中引入kzalloc之後,整個內核代碼的許多模塊裏面都先後把原來的kmalloc/me mset統統換成了kzalloc()。咱們這裏就是其中一處。927行到930行不用說了,如果沒申請成功那就返回ENOMEM。
932行,還記得之前說的總分的結構,一個總的事件隊列,hub_event_list,然後各個Hub都有一個分的事件隊列,就是這裏的hub->event_list,前面已經初始化了全局的hub_event_list,而這裏咱們針對單個Hub就得爲其初始化一個event_list。
933行和934行,struct usb_hub中的兩個成員:struct device *intfdev;struct usb_device *hdev,幹什麼用的想必不用多說了吧,第一個,不管你是USB設備也好,PCI設備也好,SCSI設備也好,Linux內核中都爲你準備一個struct device結構體來描述,所以intfdev就是和Hub相關聯的struct device指針;第二個,不管是Hub也好,U盤也好,移動硬盤也好,USB鼠標也好,USB Core都準備一個struct usb_device來描述,所以hdev將是與這個Hub相對應的struct usb_device指針。
而這些在我們調用hub_probe之前就已經建立好了,都在參數struct usb_interface *intf中,具體怎麼得到的,對於Root Hub來說,這涉及主機控制器的驅動程序,現在先忽略。但對於一個普通的外接的Hub,後面會看到如何得到它的struct usb_interface,因爲建立並初始化一個USB設備的struct usb_interface正是Hub驅動裏做的事情,其實也就是我們對Hub驅動最好奇的地方。因爲找到了這個問題的答案,我們就知道了對於一個USB設備驅動,其probe指針是在什麼情況下被調用的,比如這裏的hub_probe對於普通Hub來說是誰調用的?比如之前的usb-storage中函數storage_probe()究竟是誰調用的?這正是我們想知道的。