static int if_usb_devices_connected(struct xhci_hcd *xhci) { struct usb_device *usb_dev; int i, connected_devices = 0; if (!xhci) return -EINVAL; usb_dev = xhci->main_hcd->self.root_hub; for (i = 1; i <= usb_dev->maxchild; ++i) { if (usb_hub_find_child(usb_dev, i)) connected_devices++; } usb_dev = xhci->shared_hcd->self.root_hub; for (i = 1; i <= usb_dev->maxchild; ++i) { if (usb_hub_find_child(usb_dev, i)) connected_devices++; } if (connected_devices) return 1; return 0; }
static int tegra_ehci_remove(struct platform_device *pdev) { struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); struct usb_device *rhdev = NULL; struct tegra_usb_platform_data *pdata; unsigned long timeout = 0; wake_lock_destroy(&tegra->ehci_wake_lock); #ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ cancel_delayed_work_sync(&tegra->boost_cpu_freq_work); tegra->cpu_boost_in_work = false; pm_qos_remove_request(&tegra->boost_cpu_freq_req); #endif rhdev = hcd->self.root_hub; pdata = dev_get_platdata(&pdev->dev); if (!IS_ERR_OR_NULL(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, NULL); /* Make sure phy is powered ON to access USB register */ if(!tegra_usb_phy_hw_accessible(tegra->phy)) tegra_usb_phy_power_on(tegra->phy); if (pdata->port_otg) { timeout = jiffies + 5 * HZ; /* wait for devices connected to root hub to disconnect*/ while (rhdev && usb_hub_find_child(rhdev, 1)) { /* wait for any control packets sent to root hub to complete */ if (time_after(jiffies, timeout)) break; msleep(20); cpu_relax(); } } #ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ device_remove_file(hcd->self.controller, &dev_attr_boost_enable); #endif usb_remove_hcd(hcd); usb_put_hcd(hcd); tegra_usb_phy_power_off(tegra->phy); usb_phy_shutdown(get_usb_phy(tegra->phy)); mutex_destroy(&tegra->sync_lock); tegra_pd_remove_device(&pdev->dev); return 0; }
bool ci_hdrc_host_has_device(struct ci_hdrc *ci) { struct usb_device *roothub; int i; if ((ci->role == CI_ROLE_HOST) && ci->hcd) { roothub = ci->hcd->self.root_hub; for (i = 0; i < roothub->maxchild; ++i) { if (usb_hub_find_child(roothub, (i + 1))) return true; } } return false; }
/* * Called by host to poll peripheral if it wants to be host * Return value: * - host request flag(1) if the device wants to be host, * - host request flag(0) if the device keeps peripheral role, * - otherwise, error code. */ int otg_hnp_polling(struct otg_fsm *fsm) { struct usb_device *udev; u8 host_req_flag; int retval; enum usb_otg_state state = fsm->otg->state; if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST) return -EINVAL; udev = usb_hub_find_child(fsm->otg->host->root_hub, 1); if (!udev) { dev_err(fsm->otg->host->controller, "no usb dev connected, can't start HNP polling\n"); return -ENODEV; } /* Get host request flag from connected USB device */ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE, 0, OTG_STS_SELECTOR, &host_req_flag, 1, USB_CTRL_GET_TIMEOUT); if (retval == 1) { if (host_req_flag == HOST_REQUEST_FLAG) { retval = otg_handle_role_switch(fsm, udev); } else if (host_req_flag == 0) { /* Continue polling */ otg_add_timer(fsm, HNP_POLLING); retval = 0; } else { dev_err(&udev->dev, "host request flag is invalid\n"); retval = -EINVAL; } } else { dev_err(&udev->dev, "Get one byte OTG status failed\n"); retval = -EIO; } return retval; }
static void otg_hnp_polling_work(struct work_struct *work) { struct otg_fsm *fsm = container_of(to_delayed_work(work), struct otg_fsm, hnp_polling_work); struct usb_device *udev; enum usb_otg_state state = fsm->otg->state; u8 flag; int retval; if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST) return; udev = usb_hub_find_child(fsm->otg->host->root_hub, 1); if (!udev) { dev_err(fsm->otg->host->controller, "no usb dev connected, can't start HNP polling\n"); return; } *fsm->host_req_flag = 0; /* Get host request flag from connected USB device */ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE, 0, OTG_STS_SELECTOR, fsm->host_req_flag, 1, USB_CTRL_GET_TIMEOUT); if (retval != 1) { dev_err(&udev->dev, "Get one byte OTG status failed\n"); return; } flag = *fsm->host_req_flag; if (flag == 0) { /* Continue HNP polling */ schedule_delayed_work(&fsm->hnp_polling_work, msecs_to_jiffies(T_HOST_REQ_POLL)); return; } else if (flag != HOST_REQUEST_FLAG) { dev_err(&udev->dev, "host request flag %d is invalid\n", flag); return; } /* Host request flag is set */ if (state == OTG_STATE_A_HOST) { /* Set b_hnp_enable */ if (!fsm->otg->host->b_hnp_enable) { retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, 0, USB_DEVICE_B_HNP_ENABLE, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval >= 0) fsm->otg->host->b_hnp_enable = 1; } fsm->a_bus_req = 0; } else if (state == OTG_STATE_B_HOST) { fsm->b_bus_req = 0; } otg_statemachine(fsm); }
/* * This function implements the USB_PORT_FEAT_TEST handling of the * SINGLE_STEP_SET_FEATURE test mode as defined in the Embedded * High-Speed Electrical Test (EHSET) specification. This simply * issues a GetDescriptor control transfer, with an inserted 15-second * delay after the end of the SETUP stage and before the IN token of * the DATA stage is set. The idea is that this gives the test operator * enough time to configure the oscilloscope to perform a measurement * of the response time between the DATA and ACK packets that follow. */ static int xhci_ehset_single_step_set_feature(struct usb_hcd *hcd, int port) { int retval = -ENOMEM; struct usb_ctrlrequest *dr; struct urb *urb; struct usb_device *udev; struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct usb_device_descriptor *buf; unsigned long flags; DECLARE_COMPLETION_ONSTACK(done); /* Obtain udev of the rhub's child port */ udev = usb_hub_find_child(hcd->self.root_hub, port); if (!udev) { xhci_err(xhci, "No device attached to the RootHub\n"); return -ENODEV; } buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); if (!dr) { kfree(buf); return -ENOMEM; } /* Fill Setup packet for GetDescriptor */ dr->bRequestType = USB_DIR_IN; dr->bRequest = USB_REQ_GET_DESCRIPTOR; dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8); dr->wIndex = 0; dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE); urb = xhci_request_single_step_set_feature_urb(udev, dr, buf, &done); if (!urb) goto cleanup; /* Now complete just the SETUP stage */ spin_lock_irqsave(&xhci->lock, flags); retval = xhci_submit_single_step_set_feature(hcd, urb, 1); spin_unlock_irqrestore(&xhci->lock, flags); if (retval) goto out1; if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { usb_kill_urb(urb); retval = -ETIMEDOUT; xhci_err(xhci, "%s SETUP stage timed out on ep0\n", __func__); goto out1; } /* Sleep for 15 seconds; HC will send SOFs during this period */ msleep(15 * 1000); /* Complete remaining DATA and status stages. Re-use same URB */ urb->status = -EINPROGRESS; usb_get_urb(urb); atomic_inc(&urb->use_count); atomic_inc(&urb->dev->urbnum); spin_lock_irqsave(&xhci->lock, flags); retval = xhci_submit_single_step_set_feature(hcd, urb, 0); spin_unlock_irqrestore(&xhci->lock, flags); if (!retval && !wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) { usb_kill_urb(urb); retval = -ETIMEDOUT; xhci_err(xhci, "%s IN stage timed out on ep0\n", __func__); } out1: usb_free_urb(urb); cleanup: kfree(dr); kfree(buf); return retval; }
/* * Called by host to poll peripheral if it wants to be host * Return value: * - host request flag(1) if the device wants to be host, * - host request flag(0) if the device keeps peripheral role, * - otherwise, error code. */ int otg_hnp_polling(struct otg_fsm *fsm) { struct usb_device *udev; int retval; enum usb_otg_state state = fsm->otg->state; struct usb_otg_descriptor *desc = NULL; if ((state != OTG_STATE_A_HOST || !fsm->b_hnp_enable) && state != OTG_STATE_B_HOST) return -EINVAL; udev = usb_hub_find_child(fsm->otg->host->root_hub, 1); if (!udev) { dev_err(fsm->otg->host->controller, "no usb dev connected, can't start HNP polling\n"); return -ENODEV; } if (udev->state != USB_STATE_CONFIGURED) { dev_dbg(&udev->dev, "the B dev is not resumed!\n"); otg_add_timer(fsm, HNP_POLLING); return -EPERM; } /* * Legacy otg test device does not support HNP polling, * start HNP directly for legacy otg test device. */ if (fsm->tst_maint && (__usb_get_extra_descriptor(udev->rawdescriptors[0], le16_to_cpu(udev->config[0].desc.wTotalLength), USB_DT_OTG, (void **) &desc) == 0)) { /* shorter bLength of OTG 1.3 or earlier */ if (desc->bLength < 5) { fsm->a_bus_req = 0; fsm->tst_maint = 0; otg_del_timer(fsm, A_TST_MAINT); return HOST_REQUEST_FLAG; } } fsm->host_req_flag = 0; /* Get host request flag from connected USB device */ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE, 0, OTG_STS_SELECTOR, &fsm->host_req_flag, 1, USB_CTRL_GET_TIMEOUT); if (retval == 1) { if (fsm->host_req_flag == HOST_REQUEST_FLAG) { retval = otg_handle_role_switch(fsm, udev); } else if (fsm->host_req_flag == 0) { /* Continue polling */ otg_add_timer(fsm, HNP_POLLING); retval = 0; } else { dev_err(&udev->dev, "host request flag is invalid\n"); retval = -EINVAL; } } else { dev_warn(&udev->dev, "Get one byte OTG status failed\n"); retval = -EIO; } return retval; }