当前位置: 首页 > 工具软件 > Stat Hub > 使用案例 >

linux usb hub 流程,Linux usb hub 处理

鞠建安
2023-12-01

Linux usb hub处理

谨以此文纪念过往的岁月

一.前言

在前文中我们看过了usb

hub的probe对于其初始化应该有了一定的了解,那在该文中我们来看usb hub守护程序。

二. Hub守护程序

话说前文中在kick_khubd中将khubd_wait唤醒,该工作队列在守护程序中被等待。不出什么特殊情况的话,该守护进程将伴随系统一生。

static int hub_thread(void *__unused)

{

set_freezable();

do

{

hub_events();

wait_event_freezable(khubd_wait,

!list_empty(&hub_event_list)

||

kthread_should_stop());

}

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

return

0;

}

Events的code如下,也许大家会很惊讶其巨大,不要怕,咱们一起看下去。不过最好是读者手头有源码还有source insight。

static void hub_events(void)

{

struct

list_head *tmp;

struct

usb_device *hdev;

struct

usb_interface *intf;

struct

usb_hub *hub;

struct

device *hub_dev;

u16

hubstatus;

u16

hubchange;

u16

portstatus;

u16

portchange;

int

i, ret;

int

connect_change;

while

(1) {

spin_lock_irq(&hub_event_lock);--锁定event自旋锁

if

(list_empty(&hub_event_list)) {--如果事件链表为空跳出,继续等待。

spin_unlock_irq(&hub_event_lock);

break;

}

tmp

= .next;

list_del_init(tmp);--将tmp从中删除并且初始化

hub

= list_entry(tmp, struct usb_hub, event_list); --根据tmp获取hub,也许有人会疑惑上面都删除和初始化了,还能获得不?答案是能,因为该链表是从hub_event_list中删除并且初始化了,但是其地址还是不变的,所以还是能得到的。

kref_get(&hub->kref);--增加hub计数

spin_unlock_irq(&hub_event_lock);

--解锁

hdev

= hub->hdev;

hub_dev

= hub->intfdev;

intf

= to_usb_interface(hub_dev);

usb_lock_device(hdev);

if

(unlikely(hub->disconnected))

goto

loop;

if

(hdev->state == USB_STATE_NOTATTACHED) { --如果hub不在了,将所有的子断开,同时删除urb

hub->error

= -ENODEV;

hub_quiesce(hub,

HUB_DISCONNECT);

goto

loop;

}

ret

= usb_autopm_get_interface(intf); --自动将hub唤醒

if

(ret) {

goto

loop;

}

if

(hub->quiescing)--如果hub本身就是不活动的,什么也要做回吧。

goto

loop_autopm;

if

(hub->error) {--如果hub有错误。

ret

= usb_reset_device(hdev); --重新复位hub

if

(ret) {

goto

loop_autopm;

}

hub->nerrors

= 0;

hub->error

= 0;

}

for

(i = 1; i <= hub->descriptor->bNbrPorts; i++) { --处理端口状态改变

if

(test_bit(i, hub->busy_bits))--检测端口是否忙

continue;

connect_change

= test_bit(i, hub->); -- change_bits会在hub第一次初始化时被赋值。而event_bits则在hub_irq中改变

if

(!test_and_clear_bit(i, hub->) &&!connect_change)—如果都没有改变,继续测试下一个端口。

continue;

ret = hub_port_status(hub, i,&portstatus,

&portchange); --获取第i个端口的状态和改变寄存器,其具体说明在usb 2.0 spec 11.24.2.7中说明。其实也就是获得OHCI中第i个端口的HcRhPortStatus的寄存器值

if

(ret < 0)

continue;

if

(portchange & USB_PORT_STAT_) { --是否有设备在该端口,存在则将

clear_port_feature(hdev,

i,);

--将对应的portstatus的16位设置为1.关于其具体的含义在OHCI的section 7中说明

connect_change

= 1; --连接改变

}

if

(portchange & USB_PORT_STAT_C_ENABLE) {

if

(!connect_change)

clear_port_feature(hdev, i,USB_PORT_FEAT_C_ENABLE);

if

(!(portstatus & USB_PORT_STAT_ENABLE)&& !connect_change

&& hdev->children[i-1]) {

connect_change

= 1;

}

}

if

(portchange & USB_PORT_STAT_C_SUSPEND) {

struct

usb_device *udev;

clear_port_feature(hdev,

i,USB_PORT_FEAT_C_SUSPEND);

udev

= hdev->children[i-1];

if

(udev) {

usb_lock_device(udev);

ret

= remote_wakeup(hdev->children[i-1]);

usb_unlock_device(udev);

if

(ret < 0)

connect_change

= 1;

}

else {

ret

= -ENODEV;

hub_port_disable(hub,

i, 1);

}

}

if

(portchange & USB_PORT_STAT_C_OVERCURRENT) {

clear_port_feature(hdev,

i,USB_PORT_FEAT_C_OVER_CURRENT);

hub_power_on(hub,

true);

}

--关于上面的几个状态说明将在以后的学习中来看。

if

(portchange & USB_PORT_STAT_C_RESET) {

clear_port_feature(hdev,

i,USB_PORT_FEAT_C_RESET);

}

--在上面对port状态的种种检测后,终于到了port的真正处理的函数。

if

()--处理port改变

hub_port_connect_change(hub,

i,portstatus, portchange);

}

if (test_and_clear_bit(0, hub->)

== 0);

else

if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)

dev_err

(hub_dev, "get_hub_status failed\n");

else

{

if

(hubchange & HUB_CHANGE_LOCAL_POWER) {

clear_hub_feature(hdev,

C_HUB_LOCAL_POWER);

if

(hubstatus & HUB_STATUS_LOCAL_POWER)

hub->limited_power

= 1;

else

hub->limited_power

= 0;

}

if

(hubchange & HUB_CHANGE_OVERCURRENT) {

msleep(500);

clear_hub_feature(hdev,

C_HUB_OVER_CURRENT);

hub_power_on(hub, true);

}

}

loop_autopm:

if

(list_empty(&hub->event_list))

usb_autopm_enable(intf);

loop:

usb_unlock_device(hdev);

kref_put(&hub->kref,

hub_release);

}

}

在这之后就是具体的对某一个usb设备进行处理了,我们在这里就不说了。

 类似资料: