bool link_pm_set_active(struct usb_link_device *usb_ld) { int ret; struct link_pm_data *pm_data = usb_ld->link_pm_data; struct device *dev; if (has_hub(usb_ld)) { if (pm_data->hub_status != HUB_STATE_ACTIVE) { INIT_COMPLETION(pm_data->hub_active); SET_SLAVE_WAKEUP(usb_ld->pdata, 1); ret = wait_for_completion_timeout(&pm_data->hub_active, msecs_to_jiffies(2000)); if (!ret) { /*timeout*/ pr_err("%s: hub on timeout - retry\n", __func__); SET_SLAVE_WAKEUP(usb_ld->pdata, 0); queue_delayed_work(usb_ld->ld.tx_wq, &usb_ld->ld.tx_delayed_work, 0); return false; } else { pr_err("wait done\n"); usb_make_resume(usb_ld); return true; } } } else { /* TODO do something */ } return true; }
static int if_usb_resume(struct usb_interface *intf) { int i, ret; struct sk_buff *skb; struct usb_link_device *usb_ld = usb_get_intfdata(intf); struct if_usb_devdata *pipe; struct urb *urb; spin_lock_irq(&usb_ld->lock); if (!atomic_dec_return(&usb_ld->suspend_count)) { spin_unlock_irq(&usb_ld->lock); mif_debug("\n"); wake_lock(&usb_ld->susplock); /* HACK: Runtime pm does not allow requesting autosuspend from * resume callback, delayed it after resume */ queue_delayed_work(system_nrt_wq, &usb_ld->runtime_pm_work, msecs_to_jiffies(50)); for (i = 0; i < IF_USB_DEVNUM_MAX; i++) { pipe = &usb_ld->devdata[i]; while ((urb = usb_get_from_anchor(&pipe->urbs))) { ret = usb_rx_submit(pipe, urb, GFP_KERNEL); if (ret < 0) { usb_put_urb(urb); mif_err( "usb_rx_submit error with (%d)\n", ret); return ret; } usb_put_urb(urb); } } while ((urb = usb_get_from_anchor(&usb_ld->deferred))) { mif_debug("got urb (0x%p) from anchor & resubmit\n", urb); ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { mif_err("resubmit failed\n"); skb = urb->context; dev_kfree_skb_any(skb); usb_free_urb(urb); ret = pm_runtime_put_autosuspend( &usb_ld->usbdev->dev); if (ret < 0 && ret != -EAGAIN) mif_debug("pm_runtime_put_autosuspend " "failed: %d\n", ret); } } SET_SLAVE_WAKEUP(usb_ld->pdata, 1); udelay(100); SET_SLAVE_WAKEUP(usb_ld->pdata, 0); /* if_usb_resume() is atomic. post_resume_work is * a kind of bottom halves */ queue_delayed_work(system_nrt_wq, &usb_ld->post_resume_work, 0); return 0; } spin_unlock_irq(&usb_ld->lock); return 0; }
static int usb_tx_urb_with_skb(struct usb_link_device *usb_ld, struct sk_buff *skb, struct if_usb_devdata *pipe_data) { int ret, cnt = 0; struct urb *urb; struct usb_device *usbdev = usb_ld->usbdev; unsigned long flags; if (!usbdev || (usbdev->state == USB_STATE_NOTATTACHED) || usb_ld->host_wake_timeout_flag) return -ENODEV; pm_runtime_get_noresume(&usbdev->dev); if (usbdev->dev.power.runtime_status == RPM_SUSPENDED || usbdev->dev.power.runtime_status == RPM_SUSPENDING) { usb_ld->resume_status = AP_INITIATED_RESUME; SET_SLAVE_WAKEUP(usb_ld->pdata, 1); while (!wait_event_interruptible_timeout(usb_ld->l2_wait, usbdev->dev.power.runtime_status == RPM_ACTIVE || pipe_data->disconnected, HOST_WAKEUP_TIMEOUT_JIFFIES)) { if (cnt == MAX_RETRY) { mif_err("host wakeup timeout !!\n"); SET_SLAVE_WAKEUP(usb_ld->pdata, 0); pm_runtime_put_autosuspend(&usbdev->dev); schedule_work(&usb_ld->disconnect_work); usb_ld->host_wake_timeout_flag = 1; return -1; } mif_err("host wakeup timeout ! retry..\n"); SET_SLAVE_WAKEUP(usb_ld->pdata, 0); udelay(100); SET_SLAVE_WAKEUP(usb_ld->pdata, 1); cnt++; } if (pipe_data->disconnected) { SET_SLAVE_WAKEUP(usb_ld->pdata, 0); pm_runtime_put_autosuspend(&usbdev->dev); return -ENODEV; } mif_debug("wait_q done (runtime_status=%d)\n", usbdev->dev.power.runtime_status); } urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { mif_err("alloc urb error\n"); if (pm_runtime_put_autosuspend(&usbdev->dev) < 0) mif_debug("pm_runtime_put_autosuspend fail\n"); return -ENOMEM; } urb->transfer_flags = URB_ZERO_PACKET; usb_fill_bulk_urb(urb, usbdev, pipe_data->tx_pipe, skb->data, skb->len, usb_tx_complete, (void *)skb); spin_lock_irqsave(&usb_ld->lock, flags); if (atomic_read(&usb_ld->suspend_count)) { /* transmission will be done in resume */ usb_anchor_urb(urb, &usb_ld->deferred); usb_put_urb(urb); mif_debug("anchor urb (0x%p)\n", urb); spin_unlock_irqrestore(&usb_ld->lock, flags); return 0; } spin_unlock_irqrestore(&usb_ld->lock, flags); ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { mif_err("usb_submit_urb with ret(%d)\n", ret); if (pm_runtime_put_autosuspend(&usbdev->dev) < 0) mif_debug("pm_runtime_put_autosuspend fail\n"); } return ret; }