6.等待,只因曾经承诺

6.等待,只因曾经承诺

hub_thread()中还有一个函数没有讲,它就是try_to_freeze(),这是与电源管理相关的函数。对大多数人来说,关于这个函数,了解就可以了。

随着Linux开始支持suspended之后,有人提倡,每一个内核进程都应该在适当的时候,调用try_to_freeze()。什么意思呢?有这样一个flag,PF_NOFREEZE,如果你这个进程或者内核线程不想进入suspended状态,那么你就可以设置这个flag,正如我们在usb-storage中usb_stor_control_thread()中做的那样。而对于大多数内核线程来说,目前主流的看法是希望你能在某个地方调用try_to_freeze(),这个函数的作用是检测一个flag有没有设置,哪个flag呢,TIF_FREEZE,每个体系结构定义了自己与这有关的flags,比如i386的,include/asm- i386/thread_info.h中:

  1. 126 #define TIF_SYSCALL_TRACE       0       /* syscall trace active */  
  2. 127 #define TIF_NOTIFY_RESUME     1  /* resumption notification requested */  
  3. 128 #define TIF_SIGPENDING          2       /* signal pending */  
  4. 129 #define TIF_NEED_RESCHED        3       /* rescheduling necessary */  
  5. 130 #define TIF_SINGLESTEP  4 /* restore singlestep on return to user mode*/  
  6. 131 #define TIF_IRET                5       /* return with iret */  
  7. 132 #define TIF_SYSCALL_EMU         6       /* syscall emulation active */  
  8. 133 #define TIF_SYSCALL_AUDIT       7       /* syscall auditing active */  
  9. 134 #define TIF_SECCOMP             8       /* secure computing */  
  10. 135 #define TIF_RESTORE_SIGMASK   9 /* restore signal mask in do_signal() */  
  11. 136 #define TIF_MEMDIE              16  
  12. 137 #define TIF_DEBUG               17      /* uses debug registers */  
  13. 138 #define TIF_IO_BITMAP           18      /* uses I/O bitmap */  
  14. 139 #define TIF_FREEZE              19      /* is freezing for suspend */  

一句话,如果你不想支持电源管理,那么你编译内核时把CONFIG_PM给关了。不过,有一个问题,USB设备实际上是有节电这个特性的,也就是说USB的各种规范中就有一个suspend和一个resume,也就是挂起和恢复,换而言之,硬件本身有这样的特性,要是软件不支持的话写出来的代码你敢给客户用吗?不过一个利好消息是,除了这里这个try_to_freeze()比较难一点外,剩下的在USB中出现的电源管理的代码实际上相对来说不是很难理解,毕竟那些东西和硬件规范是对应的,都有章可循,硬件怎么规定就怎么做,所以,不用太担心。

摆平了外面的这行代码,于是现在我们安心来看hub_events()了。hub_events()还是来自drivers/usb/core/hub.c,我们一段一段地来看。

  1. 2595 static void hub_events(void)  
  2. 2596 {  
  3. 2597        struct list_head *tmp;  
  4. 2598    struct usb_device *hdev;  
  5. 2599    struct usb_interface *intf;  
  6. 2600    struct usb_hub *hub;  
  7. 2601    struct device *hub_dev;  
  8. 2602    u16 hubstatus;  
  9. 2603    u16 hubchange;  
  10. 2604    u16 portstatus;  
  11. 2605    u16 portchange;  
  12. 2606    int i, ret;  
  13. 2607    int connect_change;  
  14. 2608  
  15. 2609    /*  
  16. 2610     *  We restart the list every time to avoid a deadlock with  
  17. 2611     * deleting hubs downstream from this one. This should be  
  18. 2612     * safe since we delete the hub from the event list.  
  19. 2613     * Not the most efficient, but avoids deadlocks.  
  20. 2614     */  
  21. 2615    while (1) {  
  22. 2616  
  23. 2617        /* Grab the first entry at the beginning of the list */  
  24. 2618        spin_lock_irq(&hub_event_lock);  
  25. 2619        if (list_empty(&hub_event_list)) {  
  26. 2620                spin_unlock_irq(&hub_event_lock);  
  27. 2621            break;  
  28. 2622        }  
  29. 2623  
  30. 2624        tmp = hub_event_list.next;  
  31. 2625        list_del_init(tmp);  
  32. 2626  
  33. 2627        hub = list_entry(tmp, struct usb_hub, event_list);  
  34. 2628        hdev = hub->hdev;  
  35. 2629        intf = to_usb_interface(hub->intfdev);  
  36. 2630        hub_dev = &intf->dev;  
  37. 2631  
  38. 2632        dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",  
  39. 2633                                 hdev->state, hub->descriptor  
  40. 2634                                         ? hub->descriptor->bNbrPorts  
  41. 2635                                         : 0,  
  42. 2636                            /* NOTE: expects max 15 ports... */  
  43. 2637                                 (u16) hub->change_bits[0],  
  44. 2638                                 (u16) hub->event_bits[0]);  
  45. 2639  
  46. 2640            usb_get_intf(intf);  
  47. 2641        spin_unlock_irq(&hub_event_lock);  

2615行,一个while(1)循环;2619行,判断hub_event_list是否为空,是不是觉得很有趣?第一次调用这个函数时,hub_event_list就是初值,我们说过初值为空,所以这里就是空,即list_empty()返回1,然后break语句跳出while循环。你知道while循环的结尾在哪里吗?就是这个hub_events()函数的结尾,也就是说在这里几百行的代码就结束了,我们直接退出这个函数,返回到hub_thread()中,调用wait_event_interruptible()进入睡眠,然后等待有事件发生。

对于Hub来说,当你插入一个设备到Hub口里,就会触发一件事件。而第一件事件的发生其实是Hub驱动程序本身的初始化,即我们说过,由于Root Hub的存在,所以hub_probe必然会被调用,确切地说,就是在主机控制器的驱动程序中,一定会调用hub_probe的。如果你问我到底什么时候会调用,那么我无可奉告,因为这是在主机控制器的驱动程序中,不管你的主机控制器是属于OHCI的、UHCI的,还是EHCI的,最终在它们的初始化代码中都会调用一个叫做hcd_register_root()的函数,进而转到usb_register_root_hub(),几经周转,最终hub_probe就会被调用。所以你根本不用担心这个函数什么时刻会被调用,反正总会有这个时刻。

所以,我们就转到hub_probe吧,这里hub_events()只是虚晃一枪,不过你别忘了,等到hub_event_list里面有东西了之后,我们还会回来的。要知道hub_events()这个函数才是真正的Hub驱动的核心函数,所有的故事都是在这里发生的。所以,就像你给了某人一个承诺,承诺你还会回来。有了承诺,等待也被赋予了意义。

最后需要记住的是wait_event_interruptible()的第一个参数是&khubd_wait,关于这个函数我们在usb-storage里面已经看过多次了,其中khubd_wait定义于drivers/usb/core/hub.c:

  1. 85 /* Wakes up khubd */  
  2. 86 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); 

这无非就是一个等待队列头,所以我们很清楚,将来要唤醒这个睡眠进程的一定是类似这样的一行代码:wake_up(&khubd_wait)。没错,整个内核代码中只有一个地方会调用这个代码,那就是kick_khubd(),不过调用kick_khubd()的地方可不少。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值