Linux那些事儿之我是Hub(28)将suspend分析到底

来源:互联网 发布:网游多开软件 编辑:程序博客网 时间:2024/05/18 17:44

伫倚危楼风细细
望极春愁
黯黯生天际
草色烟光残照里
无言谁会凭栏意

拟把疏狂图一醉
对酒当歌
强乐还无味
衣带渐宽终不悔
为伊消得人憔悴

北宋词人柳永曾用这首蝶恋花来抒发对Linux内核中电源管理部分代码的无奈.当年柳永痛苦的看这代码看得想跳楼自尽.这首词,上片写登楼伫望情景.以细风,草色,烟光,残阳几个关合着忧愁的意象,组成一幅黄昏春望图,多层次地描摹写词人愁之景,愁之态,笔意婉约.下片抒情,直抒胸臆,写词人情深志坚.“拟把强乐三句辞意顿折,写词人欲借疏狂之歌呼,陶然之酣醉,谋求醉而忘忧,歌而暂欢,以摆脱读不懂代码的压抑,却落得个还无味的无聊和空虚,可见其愁之浓深、刻骨,竟无法排遣.最后揭明词人对待这种愁的果决态度:“终不悔”.“为伊”,方始画龙点晴地道破憔悴无悔的隐秘:为了看懂这代码,我亦值得憔悴、瘦损,以生命相托!语直情切,挟带着市民式的激情,真是荡气回肠.全词成功地刻画出一个志诚男子的形象,描写心理充分细腻,尤其是词的最后两句,直抒胸臆,画龙点睛般地揭示出主人公的精神境界,被王国维称为专作情语而绝妙者”.

我知道你也会觉得电源管理这部分的代码显得很复杂,调用关系一层又一层.但我们只能继续往下看.如果没有问题,usb_suspend_interface函数就这么返回了.返回值为status,当然就是0.然后我们回到usb_suspend_both,接着看下一个函数usb_suspend_device().同样来自drivers/usb/core/driver.c:

    795 /* Caller has locked udev's pm_mutex */

    796 static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)

    797 {

    798         struct usb_device_driver        *udriver;

    799         int                             status = 0;

    800

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

    802                         udev->state == USB_STATE_SUSPENDED)

    803                 goto done;

    804

    805         /* For devices that don't have a driver, we do a standard suspend. */

    806         if (udev->dev.driver == NULL) {

    807                 udev->do_remote_wakeup = 0;

    808                 status = usb_port_suspend(udev);

    809                 goto done;

    810         }

    811

    812         udriver = to_usb_device_driver(udev->dev.driver);

    813         status = udriver->suspend(udev, msg);

    814

    815 done:

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

    817         if (status == 0)

    818                 udev->dev.power.power_state.event = msg.event;

    819         return status;

    820 }

这里有一个新鲜的东西,过去我们知道usb设备驱动程序都是针对interface,不是针对device,所以很早我们就见到过一个叫做struct usb_driver的结构体,但是敏感的你是否注意到2.6.22.1的内核中还有另一个结构体,struct usb_device_driver?它定义于include/linux/usb.h:

    859 /**

    860  * struct usb_device_driver - identifies USB device driver to usbcore

    861  * @name: The driver name should be unique among USB drivers,

    862  *      and should normally be the same as the module name.

    863  * @probe: Called to see if the driver is willing to manage a particular

    864  *      device.  If it is, probe returns zero and uses dev_set_drvdata()

    865  *      to associate driver-specific data with the device.  If unwilling

    866  *      to manage the device, return a negative errno value.

    867  * @disconnect: Called when the device is no longer accessible, usually

    868  *      because it has been (or is being) disconnected or the driver's

    869  *      module is being unloaded.

    870  * @suspend: Called when the device is going to be suspended by the system.

    871  * @resume: Called when the device is being resumed by the system.

    872  * @drvwrap: Driver-model core structure wrapper.

    873  * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend

    874  *      for devices bound to this driver.

    875  *

    876  * USB drivers must provide all the fields listed above except drvwrap.

    877  */

    878 struct usb_device_driver {

    879         const char *name;

    880

    881         int (*probe) (struct usb_device *udev);

    882         void (*disconnect) (struct usb_device *udev);

    883

    884         int (*suspend) (struct usb_device *udev, pm_message_t message);

    885         int (*resume) (struct usb_device *udev);

    886         struct usbdrv_wrap drvwrap;

    887         unsigned int supports_autosuspend:1;

    888 };

    889 #define to_usb_device_driver(d) container_of(d, struct usb_device_driver, /

    890                 drvwrap.driver)

我们以前说过,usb设备驱动程序往往是针对interface,而不是针对device,换言之,一个interface对应一个driver,这一情况到今天来看仍然是正确的,但将来就未必了,因为有一些行为是针对整个device,比如电源管理中的挂起,可能整个设备需要统一的行为,而不是说每个interface可以单独行动,想干嘛干嘛.一个设备多个interface,那么它们就是一个整体,一个整体对外就会有整体的表现.interface driver就是专门处理各个interface的个性的,device driver,就用来对付整体.而这里我们看到的两个函数usb_suspend_deviceusb_suspend_interface就是这种情况的体现.usb_suspend_device这段代码的意图更是相当的明显,如果有device driver,那就调用它的suspend函数,如果没有,就调用一个通用的函数,usb_port_suspend.我们来看一下这个通用的suspend函数.

   1684 /*

   1685  * usb_port_suspend - suspend a usb device's upstream port

   1686  * @udev: device that's no longer in active use

   1687  * Context: must be able to sleep; device not locked; pm locks held

   1688  *

   1689  * Suspends a USB device that isn't in active use, conserving power.

   1690  * Devices may wake out of a suspend, if anything important happens,

   1691  * using the remote wakeup mechanism.  They may also be taken out of

   1692  * suspend by the host, using usb_port_resume().  It's also routine

   1693  * to disconnect devices while they are suspended.

   1694  *

   1695  * This only affects the USB hardware for a device; its interfaces

   1696  * (and, for hubs, child devices) must already have been suspended.

   1697  *

   1698  * Suspending OTG devices may trigger HNP, if that's been enabled

   1699  * between a pair of dual-role devices.  That will change roles, such

   1700  * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.

   1701  *

   1702  * Returns 0 on success, else negative errno.

   1703  */

   1704 int usb_port_suspend(struct usb_device *udev)

   1705 {

   1706         return __usb_port_suspend(udev, udev->portnum);

   1707 }

原来是一个幌子,真正干实事的是__usb_port_suspend(),当然从这些函数的名字我们也可以看出,实际上针对整个设备的挂起是与usb hub的某个端口有关的,确切的说就是设备所连接的那个端口,这也就是为什么这两个函数都是出现在drivers/usb/core/hub.c,而从这里的注释我们也不难看出,这里的目标就是挂起设备所连接的那个端口.而在此之前,我们已经调用usb_suspend_interface挂起了设备的每一个interface.而如果是hub的话,会先要求挂起其所有的子设备.这一点不用我们操心,因为有设备树的存在,PM core那边自然就知道如何做这件事情了.向伟大的PM core致敬,少先队员行队礼,非少先队员行注目礼.

   1644 /*

   1645  * Devices on USB hub ports have only one "suspend" state, corresponding

   1646  * to ACPI D2, "may cause the device to lose some context".

   1647  * State transitions include:

   1648  *

   1649  *   - suspend, resume ... when the VBUS power link stays live

   1650  *   - suspend, disconnect ... VBUS lost

   1651  *

   1652  * Once VBUS drop breaks the circuit, the port it's using has to go through

   1653  * normal re-enumeration procedures, starting with enabling VBUS power.

   1654  * Other than re-initializing the hub (plug/unplug, except for root hubs),

   1655  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd

   1656  * timer, no SRP, no requests through sysfs.

   1657  *

   1658  * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when

   1659  * the root hub for their bus goes into global suspend ... so we don't

   1660  * (falsely) update the device power state to say it suspended.

   1661  */

   1662 static int __usb_port_suspend (struct usb_device *udev, int port1)

   1663 {

   1664         int     status = 0;

   1665

   1666         /* caller owns the udev device lock */

   1667         if (port1 < 0)

   1668                 return port1;

   1669

   1670         /* we change the device's upstream USB link,

   1671          * but root hubs have no upstream USB link.

   1672          */

   1673         if (udev->parent)

   1674                 status = hub_port_suspend(hdev_to_hub(udev->parent), port1,

   1675                                 udev);

   1676         else {

   1677                 dev_dbg(&udev->dev, "usb %ssuspend/n",

   1678                                 udev->auto_pm ? "auto-" : "");

   1679                 usb_set_device_state(udev, USB_STATE_SUSPENDED);

   1680         }

   1681         return status;

   1682 }

我倒,貌似还是一个幌子,真正的幕后英雄是hub_port_suspend.udev->parent为空的是Root Hub,对于Root Hub,只要设置设备状态为USB_STATE_SUSPENDED即可.因为子设备已经挂起了.Root Hub本身不存在说接在哪个port的问题.于是我们来看hub_port_suspend.

   1587 /*

   1588  * Selective port suspend reduces power; most suspended devices draw

   1589  * less than 500 uA.  It's also used in OTG, along with remote wakeup.

   1590  * All devices below the suspended port are also suspended.

   1591  *

   1592  * Devices leave suspend state when the host wakes them up.  Some devices

   1593  * also support "remote wakeup", where the device can activate the USB

   1594  * tree above them to deliver data, such as a keypress or packet.  In

   1595  * some cases, this wakes the USB host.

   1596  */

   1597 static int hub_port_suspend(struct usb_hub *hub, int port1,

   1598                 struct usb_device *udev)

   1599 {

   1600         int     status;

   1601

   1602         // dev_dbg(hub->intfdev, "suspend port %d/n", port1);

   1603

   1604         /* enable remote wakeup when appropriate; this lets the device

   1605          * wake up the upstream hub (including maybe the root hub).

   1606          *

   1607          * NOTE:  OTG devices may issue remote wakeup (or SRP) even when

   1608          * we don't explicitly enable it here.

   1609          */

   1610         if (udev->do_remote_wakeup) {

   1611                 status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

   1612                                 USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,

   1613                                 USB_DEVICE_REMOTE_WAKEUP, 0,

   1614                                 NULL, 0,

   1615                                 USB_CTRL_SET_TIMEOUT);

   1616                 if (status)

   1617                         dev_dbg(&udev->dev,

   1618                                 "won't remote wakeup, status %d/n",

   1619                                 status);

   1620         }

   1621

   1622         /* see 7.1.7.6 */

   1623         status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);

   1624         if (status) {

   1625                 dev_dbg(hub->intfdev,

   1626                         "can't suspend port %d, status %d/n",

   1627                         port1, status);

   1628                 /* paranoia:  "should not happen" */

   1629                 (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),

   1630                                 USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,

   1631                                 USB_DEVICE_REMOTE_WAKEUP, 0,

   1632                                 NULL, 0,

   1633                                 USB_CTRL_SET_TIMEOUT);

   1634         } else {

   1635                 /* device has up to 10 msec to fully suspend */

   1636                 dev_dbg(&udev->dev, "usb %ssuspend/n",

   1637                                 udev->auto_pm ? "auto-" : "");

   1638                 usb_set_device_state(udev, USB_STATE_SUSPENDED);

   1639                 msleep(10);

   1640         }

   1641         return status;

   1642 }

其实之前我们见到过do_remote_wakeup,不过没有讲,现在不得不讲了.Linux,usb系统里关于电源管理的部分已经做的不错了,这主要是因为usb spec本身就对usb设备做了这方面的规定,usb设备天生就应该支持电源管理,usb spec 2.0,在第七章讲述电学特性的时候,专门有7.17.67.1.7.7两节介绍了usb设备的SuspendResume.这其中,Suspend还包括两种,一种是全局的,叫做global suspend,另一种叫做选择性的,即可以选择单个的端口进行挂起,这叫selective suspend.而咱们这里的的这个hub_port_suspend所执行的当然就是所谓的选择性挂起了,因为它针对的就是某个端口,而不是整个hub.而我们现在要说的是Remote Wakeup,从硬件角度来说,usb设备定义了一个叫做Remote Wakeup的特性,所谓Remote Wakeup指的是设备可以发送一个信号,把自己唤醒,当然实际上唤醒的是总线,或者说最后的反应是唤醒主机.最简单的例子就是usb键盘,你半天不碰计算机可能大家都睡了,可是突然间你按一下某个键,可能就把大家都给唤醒了,因为你实际上是发送了一个硬件信号.再比如hub,可能一开始是睡眠的,但如果hub port上有设备插入或者拔出,那么基本上就会唤醒hub.

而一个设备是否具有Remote Wakeup这种特性,我们前面在设备的配置描述符里就已经说过,配置描述符中的bmAttributes就是标志着设备是否支持Remote Wakeup.

比如下面是我执行lsusb –v命令看到的输出信息中的一部分,这是一个键盘/鼠标的结合体,

Bus 003 Device 002: ID 0624:0294 Avocent Corp.

Device Descriptor:

  bLength                18

  bDescriptorType         1

  bcdUSB               1.10

  bDeviceClass            0 (Defined at Interface level)

  bDeviceSubClass         0

  bDeviceProtocol         0

  bMaxPacketSize0         8

  idVendor           0x0624 Avocent Corp.

  idProduct          0x0294

  bcdDevice            1.00

  iManufacturer           1 Avocent

  iProduct                2 Dell 03R874

  iSerial                 0

  bNumConfigurations      1

  Configuration Descriptor:

    bLength                 9

    bDescriptorType         2

    wTotalLength           59

    bNumInterfaces          2

    bConfigurationValue     1

    iConfiguration          4 HID Keyboard / Mouse

    bmAttributes         0xa0

      (Bus Powered)

      Remote Wakeup

    MaxPower              100mA

    Interface Descriptor:

      bLength                 9

      bDescriptorType         4

      bInterfaceNumber        0

      bAlternateSetting       0

      bNumEndpoints           1

      bInterfaceClass         3 Human Interface Devices

      bInterfaceSubClass      1 Boot Interface Subclass

      bInterfaceProtocol      1 Keyboard

      iInterface              5 EP1 Interrupt

        HID Device Descriptor:

          bLength                 9

          bDescriptorType        33

          bcdHID               1.10

          bCountryCode           33 US

          bNumDescriptors         1

          bDescriptorType        34 Report

          wDescriptorLength      64

         Report Descriptors:

           ** UNAVAILABLE **

      Endpoint Descriptor:

        bLength                 7

        bDescriptorType         5

        bEndpointAddress     0x81  EP 1 IN

        bmAttributes            3

          Transfer Type            Interrupt

          Synch Type               None

          Usage Type               Data

        wMaxPacketSize     0x0008  1x 8 bytes

        bInterval              10

我们可以看到Configuration Descriptor那一段有一个Remote Wakeup.你在自己电脑上执行一下lsusb –v命令,你会发现很多设备的那一段并没有这么一个Remote Wakeup,只有具有这种特性的才会在这里显示出来.很显然你会发现你的U盘是不具有这个特性的,因为usb mass storage协议里也没有定义这方面的特性.

举个例子吧,主持人里,我最喜欢董卿.然而,在上海滩这个地方,一直流传着一个美丽的传说,说央视的当家花旦董卿,原来是在上海,但是后来一步一步睡了上去.我且不说这种说法是否属实,即便真是,那也是人家天生丽质,你有能耐你换芙蓉睡去,看能睡上去不?所以说Remote Wakeup这东西,是设备的特性.不是每个设备都具备的.

当然有这种特性也并不意味着这种特性就是enable,因为usb spec 2.09.1.1.6中有这么一句话,If a USB device is capable of remote wakeup signaling, the device must support the ability of the host to enable and disable this capability.即从软件的角度来说,我们可以enable这种特性,也可以disable这种特性.这道理很简单,董卿虽然天生丽质,但是她可以选择睡也可以选择不睡.她有这种权利.即便那些做小姐的也有这种权利,一代烈女潘金莲说过:骚归骚,骚有骚的贞操;贱归贱,贱有贱的尊严.

那么对于先天性具有这种特性的设备,如何enable这种特性?

usb spec 2.09.4.5中说的很好,当我们向一个设备发送GetStatus()的请求时,其返回值中的D1就是表征此时此刻这种能力是否被enable,默认情况D1应该是0,表示disabled,而如果D1被设置成了1,那么就表示这种特性被enable.如何设置呢?SetFeature()请求,请求的是DEVICE_REMOTE_WAKEUP.用代码来说话,那就是咱们这里的1611,这样就算是enableRemote Wakeup,如果你要disable掉的话,只要把SetFeature换成ClearFeature即可.DEVICE_REMOTE_WAKEUP被称为标准的Feature选择器.如图所示:

do_remote_wakeup作为struct usb_device结构体中的一个成员,其默认值为1.只是刚才在usb_suspend_device函数中,我们判断如果设备没有和driver绑定,就先把其do_remote_wakeup设置为0,理由很简单,没有驱动的话,就没必要找麻烦了,还是那句话,男人,简单就好.

紧接着1623, set_port_feature,这次设置的是USB_PORT_FEAT_SUSPEND,这个宏对应的usb spec 2.0中的PORT_SUSPEND,设置了这个feature就意味着停止这个端口上的总线交通,也因此就意味着该端口连的设备进入了suspend状态.而这也正是我们的最终目标,这之后我们看到1638行就调用usb_set_device_state把设备的状态设置为USB_STATE_SUSPENDED.当然,也要注意到,如果设置PORT_SUSPEND失败了的话,我们就将在1629行发送ClearFeatureRemote Wakeup的特性给清除掉.因为已经没有必要了,没有挂起就没有唤醒,没有共产党就没有新中国,没有新中国就没有性生活.

Ok,不小心把这个suspend的流程走了一遍,不过你一定还要问,为何drivers/usb/core/hub.c中的那个hub_suspend还没讲?于是现在来说hub driver,hub_suspend被赋值给了hub_driver中的suspend成员,hub driver是一个interface driver,所以实际上hub_suspend将会在当初那个usb_suspend_interface中被调用,没错就是866那行,status = driver->suspend(intf, msg);

于是我们就来具体看看hub_suspend.

   1919 static int hub_suspend(struct usb_interface *intf, pm_message_t msg)

   1920 {

   1921         struct usb_hub          *hub = usb_get_intfdata (intf);

   1922         struct usb_device       *hdev = hub->hdev;

   1923         unsigned                port1;

   1924         int                     status = 0;

   1925

   1926         /* fail if children aren't already suspended */

   1927         for (port1 = 1; port1 <= hdev->maxchild; port1++) {

   1928                 struct usb_device       *udev;

   1929

   1930                 udev = hdev->children [port1-1];

   1931                 if (udev && msg.event == PM_EVENT_SUSPEND &&

   1932 #ifdef  CONFIG_USB_SUSPEND

   1933                                 udev->state != USB_STATE_SUSPENDED

   1934 #else

   1935                                 udev->dev.power.power_state.event

   1936                                         == PM_EVENT_ON

   1937 #endif

   1938                                 ) {

   1939                         if (!hdev->auto_pm)

   1940                                 dev_dbg(&intf->dev, "port %d nyet suspended/n",

   1941                                                 port1);

   1942                         return -EBUSY;

   1943                 }

   1944         }

   1945

   1946         dev_dbg(&intf->dev, "%s/n", __FUNCTION__);

   1947

   1948         /* stop khubd and related activity */

   1949         hub_quiesce(hub);

   1950

   1951         /* "global suspend" of the downstream HC-to-USB interface */

   1952         if (!hdev->parent) {

   1953                 status = hcd_bus_suspend(hdev->bus);

   1954                 if (status != 0) {

   1955                         dev_dbg(&hdev->dev, "'global' suspend %d/n", status);

   1956                         hub_activate(hub);

   1957                 }

   1958         }

   1959         return status;

   1960 }

其实也没做什么.不过我们可以看到msg在整个suspend的情节里是代代相传,每个函数都把它当参数.

19271944这一段循环的目的就是判断是否有任何一个Hub的子设备尚未挂起,我们说过只有底层的劳苦大众能够安详的睡眠,上层的公仆们才好意思安心去休息.当然你别美,写代码的无非是描绘一种乌托邦式的世界,这是他们的理想,仅此而已.关于CONFIG_USB_SUSPEND,我们在drivers/usb/core/Kconfig中可以看到,

     74 config USB_SUSPEND

     75         bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"

     76         depends on USB && PM && EXPERIMENTAL

     77         help

     78           If you say Y here, you can use driver calls or the sysfs

     79           "power/state" file to suspend or resume individual USB

     80           peripherals.

     81

     82           Also, USB "remote wakeup" signaling is supported, whereby some

     83           USB devices (like keyboards and network adapters) can wake up

     84           their parent hub.  That wakeup cascades up the USB tree, and

     85           could wake the system from states like suspend-to-RAM.

     86

     87           If you are unsure about this, say N here.

毫无疑问当我们想在usb子系统里支持suspend我们完全可以理直气壮的打开这个编译开关.前面我们说过,dev.power.power_state.event如果等于PM_EVENT_ON,就相当于向世界宣布,本设备当前并不是挂起状态.而这里的udev->state不等于USB_STATE_SUSPENDED也是表征同样的含义,不过你需要注意,USB_STATE_SUSPENDED将由usb_set_device_state来设置,而你不难发现,这个世界上一共有两个函数会调用这个函数来设置这个状态,它们就是刚才说过的__usb_port_suspendhub_port_suspend(),其中,后者还是被前者调用的,__usb_port_suspend调用hub_port_suspend,__usb_port_suspend是被usb_port_suspend调用,我们继续跟踪的话就会发现,如果你没有打开CONFIG_USB_SUSPEND,usb_port_suspend只是一个空函数,啥也不做.

   1886 #else   /* CONFIG_USB_SUSPEND */

   1887

   1888 /* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */

   1889

   1890 int usb_port_suspend(struct usb_device *udev)

   1891 {

   1892         return 0;

   1893 }

所以, 这里判断USB_STATE_SUSPENDED之前要先判断编译开关.另一个问题,这里因为USB_STATE_SUSPENDEDusb这部分代码定义的宏,PM_EVENT_ON毕竟是PM core那边定义的宏,所以,我们应该尽量使用自己的这个宏.实在不行才去使用外部的资源.

auto_pm是用来设置自动挂起的,如果它为1,表明这次挂起是自动挂起,而不是系统级的挂起. 以咱们这个上下文来看,由于咱们在usb_external_suspend_device中设置了auto_pm0,所以这里就直接返回了.

为何auto_pm0就返回,否则就不返回,稍后我们看到autosuspend/autoresume那边的代码就明白了,我们现在这里的思路是,没什么特别的理由,那么子设备如果没有睡眠,那么父设备的suspend就会失败,但是如果这是一次autosuspend,那么就不会失败.因为autosuspend会有专门的方法来处理这种情况.后面会看到.

Ok,千呼万唤始出来的hub_quiesce()函数.很久很久以前我们就见到过那个hub->quiesce,我们曾多次判断过它是否为零,hub_events()中我们判断过,hub_irq()中我们判断过,led_work()中我们判断过.

    500 static void hub_quiesce(struct usb_hub *hub)

    501 {

    502         /* (nonblocking) khubd and related activity won't re-trigger */

    503         hub->quiescing = 1;

    504         hub->activating = 0;

    505

    506         /* (blocking) stop khubd and related activity */

    507         usb_kill_urb(hub->urb);

    508         if (hub->has_indicators)

    509                 cancel_delayed_work(&hub->leds);

    510         if (hub->has_indicators || hub->tt.hub)

    511                 flush_scheduled_work();

    512 }

看到这么短小精悍的函数,不由得一阵喜悦涌上心头.这个函数是唯一一处设置hub->quiescing1的地方.它和另一个函数针锋相对,hub_activate(),hub_activate()中设置hub->quiescing0,而设置hub->activating1.而这个函数恰恰相反,仔细一看你会发现,这两个函数做的事情那几乎是完全相反.那边人家调用usb_submit_urb()提交一个urb,这边就给人拆台,调用usb_kill_urb()来撤掉该urb,那边人家调用schedule_delayed_work建立一个延时工作的函数,这边就调用cancel_delayed_work给人家拆了,flush_scheduled_work()通常在cancel_delayed_work后面被调用,这个函数会使等待队列中所有的任务都被执行.

19521958行是专门针对Root Hub,因为通常Host Controller Driver也会提供自己的suspend函数,所以如果挂起操作已经上升到了Root Hub这一层,就应该调用hcdsuspend函数.hcd_bus_suspend.1954,如果挂起失败了,那么就别挂起,还是调用hub_activate()重新激活,苦海无涯,回头是岸. 
原创粉丝点击