Linux那些事兒之我是Hub(17)八大重量級函式閃亮登場(一)
還有人記得1996年那部史詩般的電視劇<<英雄無悔>>嗎?那年我初二.這部戲讓我認識了濮存昕,也是這部戲確立了濮存昕少婦殺手的地位,後來大肆那年濮存昕去過復旦,宣傳艾滋病方面的知識,儘管那時候我正在求職的路上遭遇種種挫折,但還是抽出了時間去五教看了聽了他的講座,完了之後他還即興了一段朗誦.我覺得他身上那種健康的形象是我喜歡的,因為這種積極向上的東西我太缺了.
<<英雄無悔>>裡面濮存昕扮演的公安局長高天有一句最經典的話:世上註定會有撐船人和坐船人,而他應該是那個執著的撐船仔.其實hub在usb世界裡扮演的又何嘗不是這種角色呢?我們來看這個迴圈,
在這個迴圈中,主要涉及這麼八個重量級函式,先點明它們的角色分工.
第一個函式,usb_alloc_dev(),為一個struct usb_device結構體指標,申請記憶體,這個結構體指標可不是為hub準備的,它正是為了hub這個埠所接的裝置而申請的,別忘了我們此時此刻的上下文,之所以進入到了這個迴圈,是因為我們的Hub檢測到某個埠有裝置連線了進來,所以我們作為Hub驅動當然就義不容辭的要為該裝置做點什麼.
第二個函式,usb_set_device_state(),這個函式用來設定裝置的狀態,struct usb_device
第三個函式,choose_address(),為裝置選擇一個地址.一會咱們會用例項來看看效果.
第四個函式,hub_port_init(),不多說了,這個就是埠初始化,主要就是前面說的獲取裝置的描述符.
第五個函式,usb_get_status(),這個函式是專門為hub準備的,不是為當前的這個hub,而是說當前hub的這個埠上連線的如果又是hub,那麼和連線普通裝置當然不一樣.
第六個函式,check_highspeed(),
第七個函式,usb_new_device().尋找驅動程式,呼叫驅動程式的probe,跟蹤這個函式就能一直跟蹤到裝置驅動程式的probe()函式的呼叫.
第八個函式,hub_power_remaining(),別忘了,電源管理將是hub驅動永恆的話題.
Ok,下面就讓我們來認真的逐個看一看這八大函式.
usb_alloc_dev(),drivers/usb/core/usb.c:
226 /**
227* usb_alloc_dev - usb device constructor (usbcore-internal)
228* @parent: hub to which device is connected; null to allocate a root hub
229* @bus: bus used to access the device
230* @port1: one-based index of port; ignored for root hubs
231* Context: !in_interrupt()
232*
233* Only hub drivers (including virtual root hub drivers for host
234* controllers) should ever call this.
235*
236* This call may not be used in a non-sleeping context.
237*/
238 struct usb_device *
239 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
240 {
241struct usb_device *dev;
242
243 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
244if (!dev)
245return NULL;
246
247if (!usb_get_hcd(bus_to_hcd(bus))) {
248kfree(dev);
249return NULL;
250}
251
252device_initialize(&dev->dev);
253dev->dev.bus = &usb_bus_type;
254dev->dev.type = &usb_device_type;
255dev->dev.dma_mask = bus->controller->dma_mask;
256dev->state = USB_STATE_ATTACHED;
257
258INIT_LIST_HEAD(&dev->ep0.urb_list);
259dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
260dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
261/* ep0 maxpacket comes later, from device descriptor */
262dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
263
264/* Save readable and stable topology id, distinguishing devices
265* by location for diagnostics, tools, driver model, etc.The
266* string is a path along hub ports, from the root.Each device's
267* dev->devpath will be stable until USB is re-cabled, and hubs
268* are often labeled with these port numbers.The bus_id isn't
269* as stable:bus->busnum changes easily from modprobe order,
270* cardbus or pci hotplugging, and so on.
271*/
272if (unlikely(!parent)) {
273dev->devpath[0] = '0';
274
275dev->dev.parent = bus->controller;
276sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
277} else {
278/* match any labeling on the hubs; it's one-based */
279if (parent->devpath[0] == '0')
280snprintf(dev->devpath, sizeof dev->devpath,
281"%d", port1);
282else
283snprintf(dev->devpath, sizeof dev->devpath,
284"%s.%d", parent->devpath, port1);
285
286dev->dev.parent = &parent->dev;
287sprintf(&dev->dev.bus_id[0], "%d-%s",
288bus->busnum, dev->devpath);
289
290/* hub driver sets up TT records */
291}
292
293dev->portnum = port1;
294dev->bus = bus;
295dev->parent = parent;
296INIT_LIST_HEAD(&dev->filelist);
297
298 #ifdefCONFIG_PM
299mutex_init(&dev->pm_mutex);
300INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
301dev->autosuspend_delay = usb_autosuspend_delay * HZ;
302 #endif
303return dev;
304 }
首先是申請記憶體,申請一個struct usb_device結構體指標的記憶體,這個指標就是dev,bus就是匯流排,這裡傳遞進來的兩個實參我們看到,一個是hdev,一個是hdve->bus,hdev自然很明確,就是hub所對應的那個struct usb_device指標,它的bus當然更加明確,一個主機控制器就對應一條匯流排,那麼不管我們在哪裡說,都是那條匯流排.bus是struct usb_bus結構體指標,而bus_to_hcd()得到的就是該匯流排對應的主機控制器,江湖上的人都知道,主機控制器就是代表一條匯流排.主機控制器由一個結構體struct usb_hcd表示,struct usb_hcd定義於drivers/usb/core/hcd.c,它有一個成員,struct usb_bus self.那麼這裡bus_to_hcd()就是得到該bus所屬於的那個struct usb_hcd所對應的指標,usb_get_hcd()是增加引用計數,具體怎麼實現咱們在裝置模型裡面有過交待.這裡很顯然,因為這個主機控制器的總線上多了一個裝置,當然得為主機控制器增加引用計數,只要有裝置在,主機控制器的資料結構就得在,否則系統肯定掛了.這裡如果usb_get_hcd()失敗了那就沒啥好說的了,釋放記憶體吧,哪涼快去哪待著.
然後device_initialize(&dev->dev),初始化裝置,第一個dev是struct usb_device結構體指標,而第二個dev是struct device結構體,這是裝置模型裡面一個最最基本的結構體,使用它必然要先初始化,device_initialize就是核心提供給咱們的初始化函式.
接下來,關於struct device結構體,我們迫不得已必須講兩句了,熟悉2.6裝置模型的兄弟們一