首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux那些事儿之我是Hub(18)八大重量级函数闪亮登场(二)

Linux那些事儿之我是Hub(18)八大重量级函数闪亮登场(二)

第二个函数,usb_set_device_state(),鉴于网友潜水潜到二零零八提出drivers/usb/core/hub.c出镜频率过于的高,为避免被人成为新时期祥林嫂,经支部开会决定,从此以后凡是出自drivers/usb/core/hub.c这个文件的函数将不再做介绍其来源,这个就当是默认的位置.
   1041 /**
   1042  * usb_set_device_state - change a device's current state (usbcore, hcds)
   1043  * @udev: pointer to device whose state should be changed
   1044  * @new_state: new state value to be stored
   1045  *
   1046  * udev->state is _not_ fully protected by the device lock.  Although
   1047  * most transitions are made only while holding the lock, the state can
   1048  * can change to USB_STATE_NOTATTACHED at almost any time.  This
   1049  * is so that devices can be marked as disconnected as soon as possible,
   1050  * without having to wait for any semaphores to be released.  As a result,
   1051  * all changes to any device's state must be protected by the
   1052  * device_state_lock spinlock.
   1053  *
   1054  * Once a device has been added to the device tree, all changes to its state
   1055  * should be made using this routine.  The state should _not_ be set directly.
   1056  *
   1057  * If udev->state is already USB_STATE_NOTATTACHED then no change is made.
   1058  * Otherwise udev->state is set to new_state, and if new_state is
   1059  * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set
   1060  * to USB_STATE_NOTATTACHED.
   1061  */
   1062 void usb_set_device_state(struct usb_device *udev,
   1063                 enum usb_device_state new_state)
   1064 {
   1065         unsigned long flags;
   1066
   1067         spin_lock_irqsave(&device_state_lock, flags);
   1068         if (udev->state == USB_STATE_NOTATTACHED)
   1069                 ;       /* do nothing */
   1070         else if (new_state != USB_STATE_NOTATTACHED) {
   1071
   1072                 /* root hub wakeup capabilities are managed out-of-band
   1073                  * and may involve silicon errata ... ignore them here.
   1074                  */
   1075                 if (udev->parent) {
   1076                         if (udev->state == USB_STATE_SUSPENDED
   1077                                         || new_state == USB_STATE_SUSPENDED)
   1078                                 ;       /* No change to wakeup settings */
   1079                         else if (new_state == USB_STATE_CONFIGURED)
   1080                                 device_init_wakeup(&udev->dev,
   1081                                         (udev->actconfig->desc.bmAttributes
   1082                                          & USB_CONFIG_ATT_WAKEUP));
   1083                         else
   1084                                 device_init_wakeup(&udev->dev, 0);
   1085                 }
   1086                 udev->state = new_state;
   1087         } else
   1088                 recursively_mark_NOTATTACHED(udev);
   1089         spin_unlock_irqrestore(&device_state_lock, flags);
   1090 }
天可怜见,这个函数不是很长,问题是,这个函数里面又调用了别的函数.
USB_STATE_NOTATTACHED,就是啥也没有,基本上就是说设备已经断开了,这种情况当然啥也不用做.
咱们刚才在usb_alloc_dev设置了等于USB_STATE_ATTACHED,所以继续,new_state,结合实参看一下,传递的是USB_STATE_POWERED,Root Hub另有管理方式,我们这里首先就处理非Root Hub的情况,如果原来就是USB_STATE_SUSPENDED,现还设置USB_STATE_SUSPENDED,那么当然什么也不用做.如果新的状态要被设置为USB_STATE_CONFIGURED,那么调用device_init_wakeup(),初始化唤醒方面的东西,您要是和我一样,对电源管理不感兴趣,那么估计这里您不会被唤醒,您会进入睡眠.不过人在江湖,身不由己,如果能够退出江湖,我们都想退出,然而,任我行说过,有人的地方就有江湖,人就是江湖,你怎么退出?我们又如何退出呢?既然不能退出,那么只好硬着头皮前进.
要认识device_init_wakeup()首先需要知道两个概念,can_wakeupshould_wakeup.这两个家伙从哪里钻出来的?struct device结构体,里面有这么一个成员, struct dev_pm_info power,来看看struct dev_pm_info,来自include/linux/pm.h:
    265 struct dev_pm_info {
    266         pm_message_t            power_state;
    267         unsigned                can_wakeup:1;
    268 #ifdef  CONFIG_PM
    269         unsigned                should_wakeup:1;
    270         pm_message_t            prev_state;
    271         void                    * saved_state;
    272         struct device           * pm_parent;
    273         struct list_head        entry;
    274 #endif
275 };
这些都是电源管理部分的核心数据结构,显然我们没有必要深入研究,只是需要知道,can_wakeup1表明一个设备可以被唤醒,设备驱动为了支持Linux中的电源管理,有责任调用device_init_wakeup()来初始化can_wakeup.should_wakeup则是在设备的电源状态发生变化的时候被device_may_wakeup()用来测试,测试它该不该变化.因此can_wakeup表明的是一种能力,should_wakeup表明的是有了这种能力以后去不去做某件事,就好比我们吵架的时候经常说,不是我打不过你,而是我不想打你.打得过是一种能力,但是有这种能力不一定就会去真的打,还得衡量该不该打.
我们给device_init_wakeup()传递的参数是这个设备以及配置描述符中的bmAttributes&USB_CONFIG_ATT_WAKEUP,这是因为,USB spec中规定了,bmAttributes,D5表明的就是一个USB设备是否具有被唤醒的能力.如下图所示:


USB_CONFIG_ATT_WAKEUP被定义为1<<5,所以这里比较的就是D5是否为1,1就是说:”我能”.
1083这个else就是说,如果设备将要被设置的新状态又不是USB_STATE_CONFIGUERD,那么就执行这里的device_init_wakeup,这里第二个参数传递的是0,就是说先不打开这个设备的wakeup能力.咱们这个上下文就是这种情况,咱们刚刚才说到,咱们的新状态就是USB_STATE_POWERED.
直到1086,才正式把咱们的状态设置为新的这个状态,对于我们这个上下文,那就是USB_STATE_POWERED.
1087行这里又是一个else,那么很显然这个else的意思就是原来的状态不是USB_STATE_NOTATTACHED而现在要设置成USB_STATE_NOTATTACHED.这又是一个递归函数.其作用就是其名字中所说的那样,递归的把各设备都设置成NOTATTACHED状态.
   1028 static void recursively_mark_NOTATTACHED(struct usb_device *udev)

1029 {

   1030         int i;
   1031
   1032         for (i = 0; i < udev->maxchild; ++i) {

1033                 if (udev->children)

   1034                         recursively_mark_NOTATTACHED(udev->children);
   1035         }
   1036         if (udev->state == USB_STATE_SUSPENDED)
   1037                 udev->discon_suspended = 1;
   1038         udev->state = USB_STATE_NOTATTACHED;
   1039 }
这段代码真的是太简单了,属于教科书般的递归函数的经典例子.就是每一个设备遍历自己的子节点,一个个调用recursively_mark_NOTATTACHED()函数把其state设置为USB_STATE_NOTATTACHED.如果设备的状态处于USB_STATE_SUSPENDED,那么设置udev->discon_suspended1,struct usb_device中的一个成员,unsigned discon_suspended,含义很明显,表征Disconnected while suspended.这里这么一设置,暂时我们还不知道有什么用,不过到时候我们就会在电源管理部分的代码里看到判断这个flag,很显然设置了这个flag就会阻止suspend相关的代码被调用,咱们走着瞧.
Ok,第二个函数就这么轻轻松松搞定!
返回列表