usb熱插拔實現機制

2021-06-22 10:35:47 字數 3420 閱讀 6252

一.等待

static struct usb_driver hub_driver = ;

int usb_hub_init(void)

khubd_task = kthread_run(hub_thread, null, "khubd");

if (!is_err(khubd_task))

return 0;

/* fall through if kernel_thread failed */

usb_deregister(&hub_driver);

printk(kern_err "%s: can't start khubd\n", usbcore_name);

return -1;

}static int hub_thread(void *__unused)

while (!kthread_should_stop() || !list_empty(&hub_event_list));

pr_debug("%s: khubd exiting\n", usbcore_name);

return 0;

}在hub_thread執行時,會進入hub_events,但是這時候hub_event_list隊列為空,於是hub_events退出並wait

二.喚醒

當主控制器初始化時,會初始化root hub,之後呼叫:

static int hub_probe(struct usb_inte***ce *intf, const struct usb_device_id *id)

hub_probe()所做的工作:

1.為此root hub申請struct usb_hub結構體並初始化它

2.填充並提交中斷in端點(由hub_activate完成)

usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,

hub, endpoint->binterval);

usb_submit_urb(hub->urb, gfp_noio);

3.呼叫kick_khubd(hub)

static void kick_khubd(struct usb_hub *hub)

spin_unlock_irqrestore(&hub_event_lock, flags);

}由於這個時候root hub已經成功初始化了,所以kick_khubd會將root hub的event_list,新增到

hub_event_list,表示root hub已經被識別了,同時wake_up(&khubd_wait)會喚醒上面的等待,

於是hub_events()又一次執行了,但是這次,它是有備而來,因為hub_event_list不為空

三.hub_events

hub_events函式所做的工作:

對每個埠號(共計bnbrports個埠,bnbrports這個值從hub描述符裡邊得到,因為此值描述了hub所用用的埠的情況),假如滿足下列條件則呼叫hub_port_connect_change()

1.連線有變化

2.埠本身重新使能,即所謂的enable,這種情況通常就是為了對付電磁干擾的,正如我們前面的判斷中所說的那樣

3.在復位乙個裝置的時候發現其描述符變了,這通常對應的是硬體本身有了公升級.很顯然,第一種情況是真正的物理變化,後兩者就算是邏輯變化

**模型如下:

for (i = 1; i <= hub->descriptor->bnbrports; i++) {

...if (connect_change)

//對root hub上活躍的port呼叫hub_port_connect_change

hub_port_connect_change(hub, i,

portstatus, portchange);

...    

}hub_port_connect_change()所做的工作:

1.udev = usb_alloc_dev(hdev, hdev_bus, port1);

原型:struct usb_device *usb_alloc_dev(struct usb_device *parent,

struct usb_bus *bus, unsigned port1)

為探測到的usb裝置(包括普通hub,u盤等)分配並初始化udev;

2.status = hub_port_init(hub, udev, port1, i);

先進行兩次新的策略(i=0和=1時),如果不行就再進行兩次舊的策略(i=2和i=3時).所有這一切只有乙個目的,就是為了獲得裝置的描述符,設定了udev->tt、udev->ttport和udev->ep0.desc.wmaxpacketsize,設定udev->status=     

usb_state_address

3.usb_new_device(udev);

(1)usb_configure_device(udev)->

usb_get_configuration(udev);

a.usb_get_descriptor()        

//得到裝置的描述符(包括裝置描述符、配置描述符、介面描述符等)

b.usb_parse_configuration()    

//分析以上描述符資訊,提取出配置、介面等,並賦值給udev結構裡相應的字段

(2)device_add(&udev->dev);

將usb裝置註冊到系統裡,這個動作將觸發驅動的匹配,由於這是個usb裝置,所以萬能usb驅動usb_generic_driver會匹配上,

從而generic_probe會得到執行.關於 generic_probe所做的工作,請參考:

從上面可以看出來,這一次hub_events()呼叫是由於主控制器初始化呼叫了hub_probe,從而引發hub_events呼叫。那root hub初始化完成以後hub_events會如何觸發呢?

答案是通過中斷!而這個中斷的服務函式就是hub_irq,也即是說,凡是真正的有埠變化事件發生,hub_irq就會被呼叫,而hub_irq()最終會呼叫kick_khubd(),觸發hub的event_list,於是再次呼叫hub_events().

那hub_irq是什麼時候註冊的呢?

前面我們講到:

hub_probe()所做的第二項工作是:填充並提交中斷in端點(由hub_activate完成)

usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,

hub, endpoint->binterval);

usb_submit_urb(hub->urb, gfp_noio);

hub_irq作為引數傳給了usb_fill_int_urb,這樣設定以後,只要root hub的埠有變化,hub_irq就會執行到 0

給主人留下些什麼吧!~~

MFC檢測USB熱插拔

在網上找了很久,發現這個方法還是可以實現的,但是必須要知道usb裝置的guid,我準備寫下來留作以便以後查詢 bool cxxdlg ondevicechange uint neventtype,dword dwdata break case dbt devicearrival break defa...

linux下實現USB口的熱插拔

目前要做乙個在嵌入式平台上的usb口的熱插拔事件。經過我現在的分析總結目前有如下方法 1,定時檢查 proc scsi scsi檔案 此方法只能在pc上,但在嵌入式平台上不可用。2,netlink方式 使用netlink.include include include include include...

JAVA SPI機制 實現功能的熱插拔

開發中經常遇到的乙個需求是,處理不同種類的資料,但是完成的功能是相似的,功能隨著傳入型別的不同而變化 1 定義介面 定義乙個介面,編寫不同的實現類 1 使用場景 完成功能相同,引數也類似,只是內部的實現邏輯不同,可以編寫介面實現的配置類,使用時動態獲取實現類 2 缺點 資料的型別必須確定 3 舉例 ...