注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

时间记录器

记录我的Linux、Android学习之路

 
 
 

日志

 
 

hub_thread  

2011-07-15 16:03:13|  分类: Linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

 

一、回顾

1)         守护进程hub_thread

其中的hub_events()函数处理hub上面发生的事件。wait_event_freezable会在那边等待hub总线上面的事件,如果一直没有事件则函数不返回。

         hub_thread第一次执行时会第一次调用hub_events,发现无事可做,执行空,退出去执行wait_event_freezable函数,该函数等待usb总线上的事件,如usb设备插入、拔出等。没有事件不返回。

 

这里的等待是等待【khubd_wait队列】满足【!list_empty(&hub_event_list) || kthread_should_stop()】这个条件。而条件又是【hub_event_list队列】不为空。即,如果队列空,我就一直等,直到非空。

这里涉及到的两个队列的声明如下:

/* List of hubs needing servicing */

static LIST_HEAD(hub_event_list);                //@usb/core/hub.c line 92

/* Wakes up khubd */

static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);  //@usb/core/hub.c line 95

他们都是在kick_khubd()中被改变的

1)         kick_khubd()

2)         hub_thread的创建和触发流程

usb/core/usb.c

3)         hub_events()

 

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 = hub_event_list.next;

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

                   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);

-- change_bits会在hub 第一次初始化时被赋值。

而event_bits则在hub_irq中改变

                            if (!test_and_clear_bit(i, hub->event_bits) &&!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_C_CONNECTION) {

--是否有设备在该端口,存在则将

                                     clear_port_feature(hdev, i,USB_PORT_FEAT_C_CONNECTION);

--将对应的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 (connect_change)  --处理port改变

                                     hub_port_connect_change(hub, i,portstatus, portchange);

                   }

                  if (test_and_clear_bit(0, hub->event_bits) == 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事件。下面就是如何触发这个线程的问题了。

  评论这张
 
阅读(1441)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017