说说usb suspend/resume

  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, 然后是设备本身"

  [cpp] view plaincopy

在CODE上查看代码片
派生到我的代码片
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 during

  1198 * system sleep transitions. For the most part,

  1199 * these devices should go to low power anyway when

  1200 * 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 submissions

  1215 * 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

  [objc] view plaincopy

在CODE上查看代码片
派生到我的代码片
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-USB

  204 * 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 else

  213 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

  [cpp] view plaincopy

在CODE上查看代码片
派生到我的代码片
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开始

  [cpp] view plaincopy

在CODE上查看代码片
派生到我的代码片
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。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值