![Rank: 8](images/default/star_level3.gif) ![Rank: 8](images/default/star_level3.gif)
- UID
- 852665
|
![](http://images.eccn.com/silabs/silicon_chip_980x60_202203.jpg)
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_wakeup和should_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_wakeup为1表明一个设备可以被唤醒,设备驱动为了支持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设备是否具有被唤醒的能力.如下图所示:
![](http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/bmAttributes.bmp)
而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_suspended为1,struct usb_device中的一个成员,unsigned discon_suspended,含义很明显,表征Disconnected while suspended.这里这么一设置,暂时我们还不知道有什么用,不过到时候我们就会在电源管理部分的代码里看到判断这个flag了,很显然设置了这个flag就会阻止suspend相关的代码被调用,咱们走着瞧.
Ok,第二个函数就这么轻轻松松搞定! |
|