7.最熟悉的陌生人--probe

7.最熟悉的陌生人--probe

話說因爲Hub驅動無所事事,所以hub_thread()進入了睡眠,直到某一天,hub_probe被調用。所以我們來看hub_probe(),這個函數來自drivers/usb/hub.c,其作用就如同當初我們在usb-storage中遇到的那個storage_probe()函數一樣。

  1. 887 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)  
  2. 888 {  
  3. 889         struct usb_host_interface *desc;  
  4. 890     struct usb_endpoint_descriptor *endpoint;  
  5. 891     struct usb_device *hdev;  
  6. 892     struct usb_hub *hub;  
  7. 893  
  8. 894     desc = intf->cur_altsetting;  
  9. 895     hdev = interface_to_usbdev(intf);  
  10. 896  
  11. 897 #ifdef  CONFIG_USB_OTG_BLACKLIST_HUB  
  12. 898     if (hdev->parent) {  
  13. 899         dev_warn(&intf->dev, "ignoring external hub\n");  
  14. 900             return -ENODEV;  
  15. 901     }  
  16. 902 #endif  
  17. 903  
  18. 904     /* Some hubs have a subclass of 1, which AFAICT according to the */  
  19. 905     /*  specs is not defined, but it works */  
  20. 906     if ((desc->desc.bInterfaceSubClass != 0) &&  
  21. 907             (desc->desc.bInterfaceSubClass != 1)) {  
  22. 908 descriptor_error:  
  23. 909             dev_err (&intf->dev, "bad descriptor, ignoring hub\n");  
  24. 910             return -EIO;  
  25. 911     }  
  26. 912  
  27. 913     /* Multiple endpoints? What kind of mutant ninja-hub is this? */  
  28. 914     if (desc->desc.bNumEndpoints != 1)  
  29. 915             goto descriptor_error;  
  30. 916  
  31. 917     endpoint = &desc->endpoint[0].desc;  
  32. 918  
  33. 919     /* If it's not an interrupt in endpoint, we'd better punt! */  
  34. 920     if (!usb_endpoint_is_int_in(endpoint))  
  35. 921             goto descriptor_error;  
  36. 922  
  37. 923     /* We found a hub */  
  38. 924     dev_info (&intf->dev, "USB hub found\n");  
  39. 925  
  40. 926     hub = kzalloc(sizeof(*hub), GFP_KERNEL);  
  41. 927     if (!hub) {  
  42. 928         dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");  
  43. 929             return -ENOMEM;  
  44. 930     }  
  45. 931  
  46. 932     INIT_LIST_HEAD(&hub->event_list);  
  47. 933     hub->intfdev = &intf->dev;  
  48. 934     hub->hdevhdev = hdev;  
  49. 935         INIT_DELAYED_WORK(&hub->leds, led_work);  
  50. 936  
  51. 937         usb_set_intfdata (intf, hub);  
  52. 938     intf->needs_remote_wakeup = 1;  
  53. 939  
  54. 940     if (hdev->speed == USB_SPEED_HIGH)  
  55. 941             highspeed_hubs++;  
  56. 942  
  57. 943     if (hub_configure(hub, endpoint) >= 0)  
  58. 944             return 0;  
  59. 945  
  60. 946     hub_disconnect (intf);  
  61. 947         return -ENODEV;  
  62. 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()究竟是誰調用的?這正是我們想知道的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章