Linux裝置驅動之USB hub驅動 續

2021-06-19 15:20:28 字數 4850 閱讀 8368

5.2.2:介面驅動中的hub_thread()函式

我們之前在分析usb_hub_init()的**的時候,忽略掉了一部份.

**片段如下所示:

int usb_hub_init(void)

kthread_run()是kernel中用來啟動乙個新kernel執行緒的介面,它所要執行的函式就是後面跟的第乙個引數.在這裡,也就是hub_thread().另外,順帶提一句,要終止kthread_run()建立的執行緒,可以呼叫kthread_stop().

hub_thread()的**如下:

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;

}在上面的**中, kthread_should_stop()用來判斷是否有kthread_stop()將其終止.

在這裡,我們終止看到,我們在前面要喚醒的等待佇列khubd_wait,也就是在這個地方了.

這個函式的核心處理是hub_events().分段分析**,如下:

static void hub_events(void)

//取hub_event_list中的後乙個元素,並將其斷鏈

tmp = hub_event_list.next;

list_del_init(tmp);

hub = list_entry(tmp, struct usb_hub, event_list);

kref_get(&hub->kref);

spin_unlock_irq(&hub_event_lock);

hdev = hub->hdev;

hub_dev = hub->intfdev;

intf = to_usb_inte***ce(hub_dev);

dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",

hdev->state, hub->descriptor

? hub->descriptor->bnbrports

: 0,

/* note: expects max 15 ports... */

(u16) hub->change_bits[0],

(u16) hub->event_bits[0]);

/* lock the device, then check to see if we were

* disconnected while waiting for the lock to succeed. */

usb_lock_device(hdev);

//如果hub斷開了,繼續hub_event_list中的下乙個

if (unlikely(hub->disconnected))

goto loop;

/* if the hub has died, clean up after it */

//裝置沒有連線上

if (hdev->state == usb_state_notattached)

/* autoresume */

ret = usb_autopm_get_inte***ce(intf);

if (ret)

/* if this is an inactive hub, do nothing */

//hub 暫停

if (hub->quiescing)

goto loop_autopm;

//hub 有錯誤發生?

if (hub->error)

hub->nerrors = 0;

hub->error = 0;

}首先,從hub_event_list摘下第乙個元素,根據我們之前在介面驅動probe過程的kick_khubd()函式分析中,有將hub-> event_list新增到hub_event_list.因此,就可以順藤摸瓜找到hub,再根據hub結構,找到介面結構和所屬的usb 裝置結構.

然後,進行第乙個重要的判斷.如果hub被斷開了,則,斷開hub下面所連線的所有埠,這是在hub_pre_reset()中完成的.

最後,進行第二個重要的判斷,如果hub發生了錯誤,則reset它下面的所有埠,這是在usb_reset_composite_device()中完成的.

/* deal with port status changes */

//遍歷hub中的每乙個port

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

//埠的狀態從enable 變為了disable

if (portchange & usb_port_stat_c_enable)

}//resume完成   

if (portchange & usb_port_stat_c_suspend)

//如果埠沒有連線裝置,就將埠禁用

else

dev_dbg (hub_dev,

"resume on port %d, status %d\n",

i, ret);

}//有過流保護,需要對hub power on

if (portchange & usb_port_stat_c_overcurrent)

//reset狀態已經完成了

if (portchange & usb_port_stat_c_reset)

if (connect_change)

hub_port_connect_change(hub, i,

portstatus, portchange);

}這段**就是最核心的操作了,首先要說明的是,在struct usb_dev中,有乙個struct usb_device *children[usb_maxchildren]的成員,它是表示對應埠序號上所連線的usb裝置.

在這裡,它遍歷hub上的每乙個埠,如果埠的連線會生了改變(connect_change等於1)的情況,就會呼叫hub_port_connect_change().我們來看一下,什麼情況下, hub_port_connect_change才會被設為1.

1:埠在hub->change_bits中被置位.搜尋整個**樹,發生在設定hub->change_bits的地方,只有在hub_port_logical_disconnect()中手動將埠禁用,會將對應位置1.

2:hub上沒有這個裝置樹上沒有這個埠上的裝置.但顯示埠已經連上了裝置

3:hub這個埠上的連線發生了改變,從埠有裝置連線變為無裝置連線,或者從無裝置連線變為有裝置連線.

4:hub的埠變為了disable,此時這個埠上連線了裝置,但被顯示該埠已經變禁用,需要將connect_change設為1.

5:埠狀態從suspend變成了resume,遠端喚醒埠上的裝置失敗,就需要將connect_change設為1.

另外hub_port_connect_change()函式我們放在後面再來討論

//對hub的處理

/* deal with hub status changes */

//如果hub狀態末變化,不需要做任何處理

if (test_and_clear_bit(0, hub->event_bits) == 0)

;   /* do nothing */

//get_hub_status 失敗?

else if (hub_hub_status(hub, &hubstatus, &hubchange)

dev_err (hub_dev, "get_hub_status failed\n");

else

//如果hub 發生過電源保護,需要對hub power on

if (hubchange & hub_change_overcurrent)

}hub->activating = 0;

/* if this is a root hub, tell the hcd it's okay to

* re-enable port-change interrupts now. */

if (!hdev->parent && !hub->busy_bits[0])

usb_enable_root_hub_irq(hdev->bus);

loop_autopm:

/* allow autosuspend if we're not going to run again */

if (list_empty(&hub->event_list))

usb_autopm_enable(intf);

loop:

usb_unlock_device(hdev);

kref_put(&hub->kref, hub_release);

} /* end while (1) */

}處理完hub上的port之後,就要來處理hub本身的狀態改變了,結合**中的注釋應該很容易看懂,在這裡主要是清除hub的對應feature.

之後,將  hub->activating設為了0,如果hub是root hub,需要重新開啟root hub的中斷.

這個函式到這裡就完成了.不過,其中的幾個子函式,涉及到的操作很重要,現分析如下:

1: hub_pre_reset()函式.

該函式在裝置斷開連線的時候,將其下掛載的所有子裝置全部登出掉,**如下所示:

static int hub_pre_reset(struct usb_inte***ce *intf)

hub_quiesce(hub);

return 0;

}

Linux裝置驅動之《字元裝置驅動》

linux裝置中最大的特點就是裝置操作猶如檔案操作一般,在應用層看來,硬體裝置只是乙個裝置檔案。應用程式可以像操作檔案一樣對硬體裝置進行操作,如open close read write 等。下面是乙個字元裝置驅動程式的簡單實現test.c 模組分析 1.初始化裝置驅動的結構體 struct fil...

Linux裝置驅動之字元裝置驅動

一 linux裝置的分類 linux系統將裝置分成三種基本型別,每個模組通常實現為其中某一類 字元模組 塊模組或網路模組。這三種型別有 字元裝置 字元裝置是個能夠像位元組流 類似檔案 一樣被訪問的裝置,由字元裝置驅動程式來實現這種特性。字元裝置可以通過檔案系統節點來訪問,比如 dev tty1等。這...

linux驅動之塊裝置驅動

塊裝置驅動的系統架構 塊裝置註冊過程 1,註冊裝置塊驅動程式 register blkdev 2,初始化請求佇列 blk init queue 3,指明扇區的大小 blk queue logical block size dev queue,sect size 4,申請乙個gendisk結構,初始化...