usb suspend/resume

来源:互联网 发布:cn域名个人能备案吗 编辑:程序博客网 时间:2024/05/20 15:42

1. 简介


做USB 这么长时间以来,一直埋头在各种gadget, android framework以及芯片bug,很少涉及到usb core层,今天有机会,正好看了suspend/resume, 下面就以一个具体的实例来回顾下usb suspend/resume。


从上图可以看出,这个实例用的是 Synopsys的usb控制器(dwc),下面来具体介绍下suspen/resume


2. suspend


usb suspend从device开始,然后到host,针对device或者host,则是先suspend每一个interface,然后才是device或host本身,接下来我们看下这个实例的suspend过程


2.1. suspend U盘


usb_dev_suspend --> usb_suspend --> usb_suspend_both

从usb_suspend_both的code中可以看出我们前面提到了一个原则 “先suspend interface, 然后是设备本身"

1168 static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)1169 {1170     int         status = 0;1171     int         i = 0, n = 0;1172     struct usb_interface    *intf;1173 1174     if (udev->state == USB_STATE_NOTATTACHED ||1175             udev->state == USB_STATE_SUSPENDED)1176         goto done;1177 1178     /* Suspend all the interfaces and then udev itself */1179     if (udev->actconfig) {1180         n = udev->actconfig->desc.bNumInterfaces;1181         printk("%s interface:%d\n", __func__, n);1182         for (i = n - 1; i >= 0; --i) {1183             intf = udev->actconfig->interface[i];1184             status = usb_suspend_interface(udev, intf, msg); 1185 1186             /* Ignore errors during system sleep transitions */1187             if (!PMSG_IS_AUTO(msg))1188                 status = 0;1189             if (status != 0)1190                 break;1191         }1192     }1193     if (status == 0) {1194         status = usb_suspend_device(udev, msg);1195 1196         /*1197          * Ignore errors from non-root-hub devices during1198          * system sleep transitions.  For the most part,1199          * these devices should go to low power anyway when1200          * the entire bus is suspended.1201          */1202         if (udev->parent && !PMSG_IS_AUTO(msg))1203             status = 0;1204     }1205 1206     /* If the suspend failed, resume interfaces that did get suspended */1207     if (status != 0) {1208         msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);1209         while (++i < n) {1210             intf = udev->actconfig->interface[i];1211             usb_resume_interface(udev, intf, msg, 0);1212         }1213 1214     /* If the suspend succeeded then prevent any more URB submissions1215      * and flush any outstanding URBs.1216      */1217     } else {1218         udev->can_submit = 0;1219         for (i = 0; i < 16; ++i) {1220             usb_hcd_flush_endpoint(udev, udev->ep_out[i]);1221             usb_hcd_flush_endpoint(udev, udev->ep_in[i]);1222         }1223     }1224 1225  done:1226     dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);1227     return status;1228 }

U盘只有一个interface:mass_storage. 所以这里suspend interface会调用到 usb_stor_suspend(drivers/usb/storage/usb.c),接下来就是suspend U盘本身,这里会调用到

generic_suspend

197 static int generic_suspend(struct usb_device *udev, pm_message_t msg)198 {199     int rc;200 201     /* Normal USB devices suspend through their upstream port.202      * Root hubs don't have upstream ports to suspend,203      * so we have to shut down their downstream HC-to-USB204      * interfaces manually by doing a bus (or "global") suspend.205      */206     if (!udev->parent)207         rc = hcd_bus_suspend(udev, msg);208 209     /* Non-root devices don't need to do anything for FREEZE or PRETHAW */210     else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)211         rc = 0;212     else213         rc = usb_port_suspend(udev, msg);214 215     return rc;216 }


因为这个是外设,所以具体调用的是usb_port_suspend,这个函数的主要作用就是发送usb request SET_FEATURE PORT_SUSPEND给设备。


2.2 suspend OTG Host


和device相同,还是从usb_suspend_both开始,只不过HOST只有一个interface: hub,所以这里会调用到hub_suspend

hub_suspend主要作用是停止urb以及一些delay work. 接下来就是suspend HOST本身,与device相同,这里调用的还是generic_suspend,

只不过由于是root hub,所以调用的是hcd_bus_suspend

1959 int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)1960 {1961     struct usb_hcd  *hcd = container_of(rhdev->bus, struct usb_hcd, self);1962     int     status;1963     int     old_state = hcd->state;1964 1965     dev_dbg(&rhdev->dev, "bus %ssuspend, wakeup %d\n",1966             (PMSG_IS_AUTO(msg) ? "auto-" : ""),1967             rhdev->do_remote_wakeup);1968     if (HCD_DEAD(hcd)) {1969         dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "suspend");1970         return 0;1971     }1972 1973     if (!hcd->driver->bus_suspend) {1974         status = -ENOENT;1975     } else {1976         clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags);1977         hcd->state = HC_STATE_QUIESCING;1978         status = hcd->driver->bus_suspend(hcd);1979     }

这里主要起作用的是 status = hcd->driver->bus_suspend(hcd),这个函数指针会调用到HOST控制器注册的bus_suspend函数,针对这个实例为

static int dwc_otg_bus_suspend(struct usb_hcd *hcd)


3. resume


resume是suspend的一个反过程,从Host到device,从Host/device本身然后再到各个interface.


3.1 resume OTG Host


从usb_resume_both开始

1248 static int usb_resume_both(struct usb_device *udev, pm_message_t msg)1249 {1250     int         status = 0;1251     int         i;1252     struct usb_interface    *intf;1253  1254     if (udev->state == USB_STATE_NOTATTACHED) {1255         status = -ENODEV; 1256         goto done;1257     }1258     udev->can_submit = 1; 1259 1260     /* Resume the device */1261     if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume)1262         status = usb_resume_device(udev, msg);1263 1264     /* Resume the interfaces */1265     if (status == 0 && udev->actconfig) {1266         for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {1267             intf = udev->actconfig->interface[i];1268             usb_resume_interface(udev, intf, msg,1269                     udev->reset_resume);1270         }1271     }1272     usb_mark_last_busy(udev);1273 1274  done:1275     dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);1276     if (!status)1277         udev->reset_resume = 0;1278     return status;1279 }

和suspend对应,这里先resume Host本身,调用dwc_otg_bus_resume。接下来resume interface,调用hub_resume

hub_resume会判断每一个port的port status,然后做对应的处理(这里先略过,需要参照协议)


3.2. resume U盘


从usb_resume_both开始,先resume U盘本身,调用usb_port_resume, 这里会判断port状态,并且下usb request CLEAR_FEATURE PORT_SUSPEND,

通过返回的状态判定是做resume/reset_resume/disconnect。这里先不展开,需要结合协议来看。

接下来会调用usb_stor_resume去resume interface。











原创粉丝点击