/* suspend/resume wrappers calling both usbnet and the cdc-wdm * subdriver if present. * * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide * wrappers for those without adding usbnet reset support first. */ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); struct qmi_wwan_state *info = (void *)&dev->data; int ret; /* Both usbnet_suspend() and subdriver->suspend() MUST return 0 * in system sleep context, otherwise, the resume callback has * to recover device from previous suspend failure. */ ret = usbnet_suspend(intf, message); if (ret < 0) goto err; if (intf == info->control && info->subdriver && info->subdriver->suspend) ret = info->subdriver->suspend(intf, message); if (ret < 0) usbnet_resume(intf); err: return ret; }
static int rmnet_usb_suspend(struct usb_interface *iface, pm_message_t message) { struct usbnet *unet; struct rmnet_ctrl_dev *dev; char *suspended[2] = {"QMI_STATE=SUSPENDED", NULL}; unet = usb_get_intfdata(iface); dev = (struct rmnet_ctrl_dev *)unet->data[1]; if (work_busy(&dev->get_encap_work)) return -EBUSY; if (usbnet_suspend(iface, message)) return -EBUSY; usb_kill_anchored_urbs(&dev->rx_submitted); kobject_uevent_env(&dev->devicep->kobj, KOBJ_CHANGE, suspended); return 0; }
static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message) { int ret = 0; struct usbnet *dev = usb_get_intfdata(intf); struct cdc_mbim_state *info = (void *)&dev->data; struct cdc_ncm_ctx *ctx = info->ctx; if (ctx == NULL) { ret = -1; goto error; } ret = usbnet_suspend(intf, message); if (ret < 0) goto error; if (intf == ctx->control && info->subdriver && info->subdriver->suspend) ret = info->subdriver->suspend(intf, message); if (ret < 0) usbnet_resume(intf); error: return ret; }
/*=========================================================================== METHOD: GobiNetSuspend (Public Method) DESCRIPTION: Stops QMI traffic while device is suspended PARAMETERS pIntf [ I ] - Pointer to interface powerEvent [ I ] - Power management event RETURN VALUE: int - 0 for success negative errno for failure ===========================================================================*/ int GobiNetSuspend( struct usb_interface * pIntf, pm_message_t powerEvent ) { struct usbnet * pDev; sGobiUSBNet * pGobiDev; if (pIntf == 0) { return -ENOMEM; } #if (LINUX_VERSION_CODE > KERNEL_VERSION( 2,6,23 )) pDev = usb_get_intfdata( pIntf ); #else pDev = (struct usbnet *)pIntf->dev.platform_data; #endif if (pDev == NULL || pDev->net == NULL) { DBG( "failed to get netdevice\n" ); return -ENXIO; } pGobiDev = (sGobiUSBNet *)pDev->data[0]; if (pGobiDev == NULL) { DBG( "failed to get QMIDevice\n" ); return -ENXIO; } // Is this autosuspend or system suspend? // do we allow remote wakeup? #if (LINUX_VERSION_CODE < KERNEL_VERSION( 2,6,33 )) if (pDev->udev->auto_pm == 0) #else if ((powerEvent.event & PM_EVENT_AUTO) == 0) #endif { DBG( "device suspended to power level %d\n", powerEvent.event ); GobiSetDownReason( pGobiDev, DRIVER_SUSPENDED ); } else { DBG( "device autosuspend\n" ); } if (powerEvent.event & PM_EVENT_SUSPEND) { // Stop QMI read callbacks KillRead( pGobiDev ); pDev->udev->reset_resume = 0; // Store power state to avoid duplicate resumes pIntf->dev.power.power_state.event = powerEvent.event; } else { // Other power modes cause QMI connection to be lost pDev->udev->reset_resume = 1; } // Run usbnet's suspend function return usbnet_suspend( pIntf, powerEvent ); }