Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4115
  • 博文数量: 5
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-18 16:41
文章分类
文章存档

2015年(5)

我的朋友
最近访客

分类: LINUX

2015-02-07 20:06:18

原文地址:Linux usb hub 处理 作者:steven_miao

Linux usb hub 处理

谨以此文纪念过往的岁月

一.前言

在前文中我们看过了usb hubprobe对于其初始化应该有了一定的了解,那在该文中我们来看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;

}

Eventscode如下,也许大家会很惊讶其巨大,不要怕,咱们一起看下去。不过最好是读者手头有源码还有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,);

--将对应的portstatus16位设置为1.关于其具体的含义在OHCIsection 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设备进行处理了,我们在这里就不说了。


阅读(524) | 评论(0) | 转发(0) |
0

上一篇:linux usb urb详解

下一篇:linux urb处理

给主人留下些什么吧!~~