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设备是否具有被唤醒的能力.如下图所示:

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 252.75pt" type="#_x0000_t75"><imagedata o:title="" src="file:///C:/DOCUME~1/JASON_~1/LOCALS~1/Temp/msohtml1/01/clip_image001.emz"></imagedata></shape>

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[i])

1034 recursively_mark_NOTATTACHED(udev->children[i]);

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,第二个函数就这么轻轻松松搞定!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值