现在的位置: 首页 > 综合 > 正文

Linux那些事儿之我是Hub(26)支持计划生育–看代码的理由

2013年11月03日 ⁄ 综合 ⁄ 共 6338字 ⁄ 字号 评论关闭

北大校长马寅初先生曾斩钉截铁地跟毛主席讲:”中国人口太多是因为农村晚上没有电.”

因此,为了支持计划生育这项基本国策,每一个男人都有义务认真看一下电源管理的代码.

另一方面,虽然现在已经不住在农村了,但我一直坚定不移的认为,这个世界,最慢的是我家的网速,最快的是我家电表的转速.

所以,为了了解如何让电表转速更慢,让我们一起来看看usb子系统里是如何支持电源管理的吧.

上节说了应该从usb_suspend/usb_resume开始看,那就开始吧.

usb_suspend/usb_resume这两个函数很显然是一对,但是我们不可能同时讲,只能一个一个来.倒不是故意把它们拆开,实在是没有办法.须知,形影不离并不代表相知相惜,感情在乎的是心与心的距离.两情若是久长时,又岂在朝朝暮暮. 先讲usb_suspend,再讲usb_resume.

来看usb_suspend,定义于drivers/usb/core/driver.c:

   1497 static int usb_suspend(struct device *dev, pm_message_t message)

   1498 {

   1499         if (!is_usb_device(dev))        /* Ignore PM for interfaces */

   1500                 return 0;

   1501         return usb_external_suspend_device(to_usb_device(dev), message);

   1502 }

刚说过,usb_suspendusb子系统提供给PM core调用的,所以这里两个参数dev/message都是那边传递过来的,要不是usb device当然就不用做什么了.直接返回.然后调用usb_external_suspend_device(),后者也是来自drivers/usb/core/driver.c.

   1443 /**

   1444  * usb_external_suspend_device - external suspend of a USB device and its interfaces

   1445  * @udev: the usb_device to suspend

   1446  * @msg: Power Management message describing this state transition

   1447  *

   1448  * This routine handles external suspend requests: ones not generated

   1449  * internally by a USB driver (autosuspend) but rather coming from the user

   1450  * (via sysfs) or the PM core (system sleep).  The suspend will be carried

   1451  * out regardless of @udev's usage counter or those of its interfaces,

   1452  * and regardless of whether or not remote wakeup is enabled.  Of course,

   1453  * interface drivers still have the option of failing the suspend (if

   1454  * there are unsuspended children, for example).

   1455  *

   1456  * The caller must hold @udev's device lock.

   1457  */

   1458 int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)

   1459 {

   1460         int     status;

   1461

   1462         usb_pm_lock(udev);

   1463         udev->auto_pm = 0;

   1464         status = usb_suspend_both(udev, msg);

   1465         usb_pm_unlock(udev);

   1466         return status;

   1467 }

1462行和1465,锁的代码暂时先一律飘过.

我们看到,这个函数就做了两件事情,第一,udevauto_pm0,第二,调用usb_suspend_both.

继续跟踪usb_suspend_both.仍然是来自于drivers/usb/core/driver.c:

    993 /**

    994  * usb_suspend_both - suspend a USB device and its interfaces

    995  * @udev: the usb_device to suspend

    996  * @msg: Power Management message describing this state transition

    997  *

    998  * This is the central routine for suspending USB devices.  It calls the

    999  * suspend methods for all the interface drivers in @udev and then calls

   1000  * the suspend method for @udev itself.  If an error occurs at any stage,

   1001  * all the interfaces which were suspended are resumed so that they remain

   1002  * in the same state as the device.

   1003  *

   1004  * If an autosuspend is in progress (@udev->auto_pm is set), the routine

   1005  * checks first to make sure that neither the device itself or any of its

   1006  * active interfaces is in use (pm_usage_cnt is greater than 0).  If they

   1007  * are, the autosuspend fails.

   1008  *

   1009  * If the suspend succeeds, the routine recursively queues an autosuspend

   1010  * request for @udev's parent device, thereby propagating the change up

   1011  * the device tree.  If all of the parent's children are now suspended,

   1012  * the parent will autosuspend in turn.

   1013  *

   1014  * The suspend method calls are subject to mutual exclusion under control

   1015  * of @udev's pm_mutex.  Many of these calls are also under the protection

   1016  * of @udev's device lock (including all requests originating outside the

   1017  * USB subsystem), but autosuspend requests generated by a child device or

   1018  * interface driver may not be.  Usbcore will insure that the method calls

   1019  * do not arrive during bind, unbind, or reset operations.  However, drivers

   1020  * must be prepared to handle suspend calls arriving at unpredictable times.

   1021  * The only way to block such calls is to do an autoresume (preventing

   1022  * autosuspends) while holding @udev's device lock (preventing outside

   1023  * suspends).

   1024  *

   1025  * The caller must hold @udev->pm_mutex.

   1026  *

   1027  * This routine can run only in process context.

   1028  */

   1029 static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)

   1030 {

   1031         int                     status = 0;

   1032         int                     i = 0;

   1033         struct usb_interface    *intf;

   1034         struct usb_device       *parent = udev->parent;

   1035

   1036         if (udev->state == USB_STATE_NOTATTACHED ||

   1037                         udev->state == USB_STATE_SUSPENDED)

   1038                 goto done;

   1039

   1040         udev->do_remote_wakeup = device_may_wakeup(&udev->dev);

   1041

   1042         if (udev->auto_pm) {

   1043                 status = autosuspend_check(udev);

   1044                 if (status < 0)

   1045                         goto done;

   1046         }

   1047

   1048         /* Suspend all the interfaces and then udev itself */

   1049         if (udev->actconfig) {

   1050                 for (; i < udev->actconfig->desc.bNumInterfaces; i++) {

   1051                         intf = udev->actconfig->interface[i];

   1052                         status = usb_suspend_interface(intf, msg);

   1053                         if (status != 0)

   1054                                 break;

   1055                 }

   1056         }

   1057         if (status == 0)

   1058                 status = usb_suspend_device(udev, msg);

   1059

   1060         /* If the suspend failed, resume interfaces that did get suspended */

   1061         if (status != 0) {

   1062                 while (--i >= 0) {

   1063                         intf = udev->actconfig->interface[i];

   1064                         usb_resume_interface(intf);

   1065                 }

   1066

   1067                 /* Try another autosuspend when the interfaces aren't busy */

   1068                 if (udev->auto_pm)

   1069                         autosuspend_check(udev);

   1070

   1071         /* If the suspend succeeded, propagate it up the tree */

   1072         } else {

   1073                 cancel_delayed_work(&udev->autosuspend);

   1074                 if (parent)

   1075                         usb_autosuspend_device(parent);

   1076         }

   1077

   1078  done:

   1079         // dev_dbg(&udev->dev, "%s: status %d/n", __FUNCTION__, status);

   1080         return status;

   1081 }

这里有两个重要的概念,autosuspend/autoresume.autosuspend,即自动挂起,这是由driver自行决定,它自己进行判断,当它觉得应该挂起设备的时候,它就会去Just do it!关于autosuspend我们后面会讲.

1040, device_may_wakeup(),我们前面说过,设备有没有被唤醒的能力有一个flag可以标志,can_wakeup,那么如果有这种能力,用户仍然可以根据实际需要关掉这种能力,或者打开这种能力,这就体现在sysfs下的一个文件.比如:

localhost:~ # cat /sys/bus/usb/devices/1-5/power/wakeup

enabled

localhost:~ # cat /sys/bus/usb/devices/1-5/:1.0/power/wakeup

 

localhost:~ #

可以看到后者的输出值为空,这说明该设备是不支持remote wakeup,换句话说,can_wakeup也应该是设置为了0,这种情况device_may_wakeup返回值必然是false,而前者的输出值为enabled,说明该设备是支持remote wakeup,并且此刻remote wakeup的特性是打开的.别的设备也一样,用户可以通过sysfs来进行设置,你可以把wakeupenabled改为disabled.

为什么需要有这么一个sysfs的接口呢?我们知道usb设备有一种特性,叫做remote wakeup,这种特性不是每个usb设备都支持

抱歉!评论已关闭.