第二个函数,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设备是否具有被唤醒的能力.如下图所示:
<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_suspended为1,struct usb_device中的一个成员,unsigned discon_suspended,含义很明显,表征Disconnected while suspended.这里这么一设置,暂时我们还不知道有什么用,不过到时候我们就会在电源管理部分的代码里看到判断这个flag了,很显然设置了这个flag就会阻止suspend相关的代码被调用,咱们走着瞧.
Ok,第二个函数就这么轻轻松松搞定!
分享到:
相关推荐
Linux那些事儿之我是Hub,是前面Linux那些事之我是U盘,usb等的姐妹篇
非常不错的一本书,LinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinuxLinux
Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我...
linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 linux那些事儿...
Linux那些事儿第二版我是Hub一章,比较第一版修正了一些错误,增加了电源管理部分的分析,推荐阅读
本文件包括第一第二完成版,第二版基于2.6.22内核,对USB子系统的大部分源代码逐行进行分析,系统地阐释了Linux内核中USB子系统是如何运转的,子系统内部的各个模块之间是如何互相协作、配合的。本次改版修改了第1版...
导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了
》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...
本书基于2.6.22内核,对USB子系统的大部分源代码逐行进行分析,系统地阐释了Linux内核中USB子系统是如何运转的,子系统内部的各个模块之间是如何互相协作、配合的。本次改版修改了第1版中出现的错误,增加了一个附录...
Linux那些事儿之我是Block层 ...Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘
Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf ...Linux那些事儿之我是Hub.pdf Linux那些事儿之我是UHCI.pdf
Linux那些事儿之我是U盘 Linux那些事儿之我是USB_core Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs ...Linux那些事儿之我是Hub Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层
本人整理的fudan_abc的专栏中以完结的文章,在此向原作者表示感谢,给...内容包括:linux那些事儿之我是U盘,linux那些事儿之我是USB,linux那些事儿之我是HUB,linux那些事儿之我是UHCI,linux那些事儿之我是Sysfs。
Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析
包括:Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是...
Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs...
里面包含Linux那些事的九个文档,Block层,ECHI主机控制,HUB,PCI,SCSI硬盘,Sysfs,UHCI,USB+core,U盘等九个文档,内容详细,而且全面都有书签,适合系统学习!
Linux那些事儿之我是Hub Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘 Linux那些事之我是HUB1