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;
}
示例#2
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;
}
示例#5
0
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);
}
示例#6
0
/*
 * 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;
}