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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
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;
}