xref: /dflybsd-src/sys/bus/u4b/usb_request.c (revision 2b3f93ea6d1f70880f3e87f3c2cbe0dc0bfc9332)
1b86003c4SMarkus Pfeiffer /* $FreeBSD: head/sys/dev/usb/usb_request.c 276701 2015-01-05 15:04:17Z hselasky $ */
212bd3c8bSSascha Wildner /*-
312bd3c8bSSascha Wildner  * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
412bd3c8bSSascha Wildner  * Copyright (c) 1998 Lennart Augustsson. All rights reserved.
512bd3c8bSSascha Wildner  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
612bd3c8bSSascha Wildner  *
712bd3c8bSSascha Wildner  * Redistribution and use in source and binary forms, with or without
812bd3c8bSSascha Wildner  * modification, are permitted provided that the following conditions
912bd3c8bSSascha Wildner  * are met:
1012bd3c8bSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
1112bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
1212bd3c8bSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1312bd3c8bSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
1412bd3c8bSSascha Wildner  *    documentation and/or other materials provided with the distribution.
1512bd3c8bSSascha Wildner  *
1612bd3c8bSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1712bd3c8bSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1812bd3c8bSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1912bd3c8bSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2012bd3c8bSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2112bd3c8bSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2212bd3c8bSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2312bd3c8bSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2412bd3c8bSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2512bd3c8bSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2612bd3c8bSSascha Wildner  * SUCH DAMAGE.
2712bd3c8bSSascha Wildner  */
2812bd3c8bSSascha Wildner 
2912bd3c8bSSascha Wildner #include <sys/stdint.h>
3012bd3c8bSSascha Wildner #include <sys/param.h>
3112bd3c8bSSascha Wildner #include <sys/queue.h>
3212bd3c8bSSascha Wildner #include <sys/types.h>
3312bd3c8bSSascha Wildner #include <sys/systm.h>
3412bd3c8bSSascha Wildner #include <sys/kernel.h>
3512bd3c8bSSascha Wildner #include <sys/bus.h>
3612bd3c8bSSascha Wildner #include <sys/module.h>
3712bd3c8bSSascha Wildner #include <sys/lock.h>
3812bd3c8bSSascha Wildner #include <sys/mutex.h>
3912bd3c8bSSascha Wildner #include <sys/condvar.h>
4012bd3c8bSSascha Wildner #include <sys/sysctl.h>
4112bd3c8bSSascha Wildner #include <sys/unistd.h>
4212bd3c8bSSascha Wildner #include <sys/callout.h>
4312bd3c8bSSascha Wildner #include <sys/malloc.h>
44*2b3f93eaSMatthew Dillon #include <sys/caps.h>
4512bd3c8bSSascha Wildner 
46722d05c3SSascha Wildner #include <bus/u4b/usb.h>
47722d05c3SSascha Wildner #include <bus/u4b/usbdi.h>
48722d05c3SSascha Wildner #include <bus/u4b/usbdi_util.h>
49722d05c3SSascha Wildner #include <bus/u4b/usb_ioctl.h>
50722d05c3SSascha Wildner #include <bus/u4b/usbhid.h>
51fe8b458aSMatthew Dillon #include <bus/u4b/quirk/usb_quirk.h>
5212bd3c8bSSascha Wildner 
5312bd3c8bSSascha Wildner #define	USB_DEBUG_VAR usb_debug
5412bd3c8bSSascha Wildner 
55722d05c3SSascha Wildner #include <bus/u4b/usb_core.h>
56722d05c3SSascha Wildner #include <bus/u4b/usb_busdma.h>
57722d05c3SSascha Wildner #include <bus/u4b/usb_request.h>
58722d05c3SSascha Wildner #include <bus/u4b/usb_process.h>
59722d05c3SSascha Wildner #include <bus/u4b/usb_transfer.h>
60722d05c3SSascha Wildner #include <bus/u4b/usb_debug.h>
61722d05c3SSascha Wildner #include <bus/u4b/usb_device.h>
62722d05c3SSascha Wildner #include <bus/u4b/usb_util.h>
63722d05c3SSascha Wildner #include <bus/u4b/usb_dynamic.h>
6412bd3c8bSSascha Wildner 
65722d05c3SSascha Wildner #include <bus/u4b/usb_controller.h>
66722d05c3SSascha Wildner #include <bus/u4b/usb_bus.h>
6712bd3c8bSSascha Wildner #include <sys/ctype.h>
6812bd3c8bSSascha Wildner 
6912bd3c8bSSascha Wildner static int usb_no_cs_fail;
7012bd3c8bSSascha Wildner 
7112bd3c8bSSascha Wildner SYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW,
7212bd3c8bSSascha Wildner     &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set");
73dd681da6SMatthew Dillon TUNABLE_INT("hw.usb.no_cs_fail", &usb_no_cs_fail);
7412bd3c8bSSascha Wildner 
7557bed822SMarkus Pfeiffer static int usb_full_ddesc;
7657bed822SMarkus Pfeiffer 
7757bed822SMarkus Pfeiffer SYSCTL_INT(_hw_usb, OID_AUTO, full_ddesc, CTLFLAG_RW,
7857bed822SMarkus Pfeiffer     &usb_full_ddesc, 0, "USB always read complete device descriptor, if set");
79dd681da6SMatthew Dillon TUNABLE_INT("hw.usb.full_ddesc", &usb_full_ddesc);
8057bed822SMarkus Pfeiffer 
8112bd3c8bSSascha Wildner #ifdef USB_DEBUG
8212bd3c8bSSascha Wildner #ifdef USB_REQ_DEBUG
8312bd3c8bSSascha Wildner /* The following structures are used in connection to fault injection. */
8412bd3c8bSSascha Wildner struct usb_ctrl_debug {
8512bd3c8bSSascha Wildner 	int bus_index;		/* target bus */
8612bd3c8bSSascha Wildner 	int dev_index;		/* target address */
8712bd3c8bSSascha Wildner 	int ds_fail;		/* fail data stage */
8857bed822SMarkus Pfeiffer 	int ss_fail;		/* fail status stage */
8912bd3c8bSSascha Wildner 	int ds_delay;		/* data stage delay in ms */
9012bd3c8bSSascha Wildner 	int ss_delay;		/* status stage delay in ms */
9112bd3c8bSSascha Wildner 	int bmRequestType_value;
9212bd3c8bSSascha Wildner 	int bRequest_value;
9312bd3c8bSSascha Wildner };
9412bd3c8bSSascha Wildner 
9512bd3c8bSSascha Wildner struct usb_ctrl_debug_bits {
9612bd3c8bSSascha Wildner 	uint16_t ds_delay;
9712bd3c8bSSascha Wildner 	uint16_t ss_delay;
9812bd3c8bSSascha Wildner 	uint8_t ds_fail:1;
9912bd3c8bSSascha Wildner 	uint8_t ss_fail:1;
10012bd3c8bSSascha Wildner 	uint8_t enabled:1;
10112bd3c8bSSascha Wildner };
10212bd3c8bSSascha Wildner 
10312bd3c8bSSascha Wildner /* The default is to disable fault injection. */
10412bd3c8bSSascha Wildner 
10512bd3c8bSSascha Wildner static struct usb_ctrl_debug usb_ctrl_debug = {
10612bd3c8bSSascha Wildner 	.bus_index = -1,
10712bd3c8bSSascha Wildner 	.dev_index = -1,
10812bd3c8bSSascha Wildner 	.bmRequestType_value = -1,
10912bd3c8bSSascha Wildner 	.bRequest_value = -1,
11012bd3c8bSSascha Wildner };
11112bd3c8bSSascha Wildner 
112dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RWTUN,
11312bd3c8bSSascha Wildner     &usb_ctrl_debug.bus_index, 0, "USB controller index to fail");
114dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RWTUN,
11512bd3c8bSSascha Wildner     &usb_ctrl_debug.dev_index, 0, "USB device address to fail");
116dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RWTUN,
11712bd3c8bSSascha Wildner     &usb_ctrl_debug.ds_fail, 0, "USB fail data stage");
118dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RWTUN,
11912bd3c8bSSascha Wildner     &usb_ctrl_debug.ss_fail, 0, "USB fail status stage");
120dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RWTUN,
12112bd3c8bSSascha Wildner     &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms");
122dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RWTUN,
12312bd3c8bSSascha Wildner     &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms");
124dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RWTUN,
12512bd3c8bSSascha Wildner     &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail");
126dd681da6SMatthew Dillon SYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RWTUN,
12712bd3c8bSSascha Wildner     &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail");
12812bd3c8bSSascha Wildner 
12912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
13012bd3c8bSSascha Wildner  *	usbd_get_debug_bits
13112bd3c8bSSascha Wildner  *
13212bd3c8bSSascha Wildner  * This function is only useful in USB host mode.
13312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
13412bd3c8bSSascha Wildner static void
usbd_get_debug_bits(struct usb_device * udev,struct usb_device_request * req,struct usb_ctrl_debug_bits * dbg)13512bd3c8bSSascha Wildner usbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req,
13612bd3c8bSSascha Wildner     struct usb_ctrl_debug_bits *dbg)
13712bd3c8bSSascha Wildner {
13812bd3c8bSSascha Wildner 	int temp;
13912bd3c8bSSascha Wildner 
14012bd3c8bSSascha Wildner 	memset(dbg, 0, sizeof(*dbg));
14112bd3c8bSSascha Wildner 
14212bd3c8bSSascha Wildner 	/* Compute data stage delay */
14312bd3c8bSSascha Wildner 
14412bd3c8bSSascha Wildner 	temp = usb_ctrl_debug.ds_delay;
14512bd3c8bSSascha Wildner 	if (temp < 0)
14612bd3c8bSSascha Wildner 		temp = 0;
14712bd3c8bSSascha Wildner 	else if (temp > (16*1024))
14812bd3c8bSSascha Wildner 		temp = (16*1024);
14912bd3c8bSSascha Wildner 
15012bd3c8bSSascha Wildner 	dbg->ds_delay = temp;
15112bd3c8bSSascha Wildner 
15212bd3c8bSSascha Wildner 	/* Compute status stage delay */
15312bd3c8bSSascha Wildner 
15412bd3c8bSSascha Wildner 	temp = usb_ctrl_debug.ss_delay;
15512bd3c8bSSascha Wildner 	if (temp < 0)
15612bd3c8bSSascha Wildner 		temp = 0;
15712bd3c8bSSascha Wildner 	else if (temp > (16*1024))
15812bd3c8bSSascha Wildner 		temp = (16*1024);
15912bd3c8bSSascha Wildner 
16012bd3c8bSSascha Wildner 	dbg->ss_delay = temp;
16112bd3c8bSSascha Wildner 
16212bd3c8bSSascha Wildner 	/* Check if this control request should be failed */
16312bd3c8bSSascha Wildner 
16412bd3c8bSSascha Wildner 	if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index)
16512bd3c8bSSascha Wildner 		return;
16612bd3c8bSSascha Wildner 
16712bd3c8bSSascha Wildner 	if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index)
16812bd3c8bSSascha Wildner 		return;
16912bd3c8bSSascha Wildner 
17012bd3c8bSSascha Wildner 	temp = usb_ctrl_debug.bmRequestType_value;
17112bd3c8bSSascha Wildner 
17212bd3c8bSSascha Wildner 	if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255))
17312bd3c8bSSascha Wildner 		return;
17412bd3c8bSSascha Wildner 
17512bd3c8bSSascha Wildner 	temp = usb_ctrl_debug.bRequest_value;
17612bd3c8bSSascha Wildner 
17712bd3c8bSSascha Wildner 	if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255))
17812bd3c8bSSascha Wildner 		return;
17912bd3c8bSSascha Wildner 
18012bd3c8bSSascha Wildner 	temp = usb_ctrl_debug.ds_fail;
18112bd3c8bSSascha Wildner 	if (temp)
18212bd3c8bSSascha Wildner 		dbg->ds_fail = 1;
18312bd3c8bSSascha Wildner 
18412bd3c8bSSascha Wildner 	temp = usb_ctrl_debug.ss_fail;
18512bd3c8bSSascha Wildner 	if (temp)
18612bd3c8bSSascha Wildner 		dbg->ss_fail = 1;
18712bd3c8bSSascha Wildner 
18812bd3c8bSSascha Wildner 	dbg->enabled = 1;
18912bd3c8bSSascha Wildner }
19012bd3c8bSSascha Wildner #endif	/* USB_REQ_DEBUG */
19112bd3c8bSSascha Wildner #endif	/* USB_DEBUG */
19212bd3c8bSSascha Wildner 
19312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
19412bd3c8bSSascha Wildner  *	usbd_do_request_callback
19512bd3c8bSSascha Wildner  *
19612bd3c8bSSascha Wildner  * This function is the USB callback for generic USB Host control
19712bd3c8bSSascha Wildner  * transfers.
19812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
19912bd3c8bSSascha Wildner void
usbd_do_request_callback(struct usb_xfer * xfer,usb_error_t error)20012bd3c8bSSascha Wildner usbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error)
20112bd3c8bSSascha Wildner {
20212bd3c8bSSascha Wildner 	;				/* workaround for a bug in "indent" */
20312bd3c8bSSascha Wildner 
20412bd3c8bSSascha Wildner 	DPRINTF("st=%u\n", USB_GET_STATE(xfer));
20512bd3c8bSSascha Wildner 
20612bd3c8bSSascha Wildner 	switch (USB_GET_STATE(xfer)) {
20712bd3c8bSSascha Wildner 	case USB_ST_SETUP:
20812bd3c8bSSascha Wildner 		usbd_transfer_submit(xfer);
20912bd3c8bSSascha Wildner 		break;
21012bd3c8bSSascha Wildner 	default:
211ccb00b06SMatthew Dillon 		wakeup(xfer);
21212bd3c8bSSascha Wildner 		break;
21312bd3c8bSSascha Wildner 	}
21412bd3c8bSSascha Wildner }
21512bd3c8bSSascha Wildner 
21612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
21712bd3c8bSSascha Wildner  *	usb_do_clear_stall_callback
21812bd3c8bSSascha Wildner  *
21912bd3c8bSSascha Wildner  * This function is the USB callback for generic clear stall requests.
22012bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
22112bd3c8bSSascha Wildner void
usb_do_clear_stall_callback(struct usb_xfer * xfer,usb_error_t error)22212bd3c8bSSascha Wildner usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
22312bd3c8bSSascha Wildner {
22412bd3c8bSSascha Wildner 	struct usb_device_request req;
22512bd3c8bSSascha Wildner 	struct usb_device *udev;
22612bd3c8bSSascha Wildner 	struct usb_endpoint *ep;
22712bd3c8bSSascha Wildner 	struct usb_endpoint *ep_end;
22812bd3c8bSSascha Wildner 	struct usb_endpoint *ep_first;
2295e41ab93SMarkus Pfeiffer 	usb_stream_t x;
23012bd3c8bSSascha Wildner 	uint8_t to;
23112bd3c8bSSascha Wildner 
23212bd3c8bSSascha Wildner 	udev = xfer->xroot->udev;
23312bd3c8bSSascha Wildner 
23412bd3c8bSSascha Wildner 	USB_BUS_LOCK(udev->bus);
23512bd3c8bSSascha Wildner 
23612bd3c8bSSascha Wildner 	/* round robin endpoint clear stall */
23712bd3c8bSSascha Wildner 
23812bd3c8bSSascha Wildner 	ep = udev->ep_curr;
23912bd3c8bSSascha Wildner 	ep_end = udev->endpoints + udev->endpoints_max;
24012bd3c8bSSascha Wildner 	ep_first = udev->endpoints;
24112bd3c8bSSascha Wildner 	to = udev->endpoints_max;
24212bd3c8bSSascha Wildner 
24312bd3c8bSSascha Wildner 	switch (USB_GET_STATE(xfer)) {
24412bd3c8bSSascha Wildner 	case USB_ST_TRANSFERRED:
24512bd3c8bSSascha Wildner tr_transferred:
24612bd3c8bSSascha Wildner 		/* reset error counter */
24712bd3c8bSSascha Wildner 		udev->clear_stall_errors = 0;
24812bd3c8bSSascha Wildner 
24912bd3c8bSSascha Wildner 		if (ep == NULL)
25012bd3c8bSSascha Wildner 			goto tr_setup;		/* device was unconfigured */
25112bd3c8bSSascha Wildner 		if (ep->edesc &&
25212bd3c8bSSascha Wildner 		    ep->is_stalled) {
25312bd3c8bSSascha Wildner 			ep->toggle_next = 0;
25412bd3c8bSSascha Wildner 			ep->is_stalled = 0;
25512bd3c8bSSascha Wildner 			/* some hardware needs a callback to clear the data toggle */
25612bd3c8bSSascha Wildner 			usbd_clear_stall_locked(udev, ep);
2575e41ab93SMarkus Pfeiffer 			for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
2585e41ab93SMarkus Pfeiffer 				/* start the current or next transfer, if any */
2595e41ab93SMarkus Pfeiffer 				usb_command_wrapper(&ep->endpoint_q[x],
2605e41ab93SMarkus Pfeiffer 				    ep->endpoint_q[x].curr);
2615e41ab93SMarkus Pfeiffer 			}
26212bd3c8bSSascha Wildner 		}
26312bd3c8bSSascha Wildner 		ep++;
26412bd3c8bSSascha Wildner 
26512bd3c8bSSascha Wildner 	case USB_ST_SETUP:
26612bd3c8bSSascha Wildner tr_setup:
26712bd3c8bSSascha Wildner 		if (to == 0)
26812bd3c8bSSascha Wildner 			break;			/* no endpoints - nothing to do */
26912bd3c8bSSascha Wildner 		if ((ep < ep_first) || (ep >= ep_end))
27012bd3c8bSSascha Wildner 			ep = ep_first;	/* endpoint wrapped around */
27112bd3c8bSSascha Wildner 		if (ep->edesc &&
27212bd3c8bSSascha Wildner 		    ep->is_stalled) {
27312bd3c8bSSascha Wildner 
27412bd3c8bSSascha Wildner 			/* setup a clear-stall packet */
27512bd3c8bSSascha Wildner 
27612bd3c8bSSascha Wildner 			req.bmRequestType = UT_WRITE_ENDPOINT;
27712bd3c8bSSascha Wildner 			req.bRequest = UR_CLEAR_FEATURE;
27812bd3c8bSSascha Wildner 			USETW(req.wValue, UF_ENDPOINT_HALT);
27912bd3c8bSSascha Wildner 			req.wIndex[0] = ep->edesc->bEndpointAddress;
28012bd3c8bSSascha Wildner 			req.wIndex[1] = 0;
28112bd3c8bSSascha Wildner 			USETW(req.wLength, 0);
28212bd3c8bSSascha Wildner 
28312bd3c8bSSascha Wildner 			/* copy in the transfer */
28412bd3c8bSSascha Wildner 
28512bd3c8bSSascha Wildner 			usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
28612bd3c8bSSascha Wildner 
28712bd3c8bSSascha Wildner 			/* set length */
28812bd3c8bSSascha Wildner 			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
28912bd3c8bSSascha Wildner 			xfer->nframes = 1;
29012bd3c8bSSascha Wildner 			USB_BUS_UNLOCK(udev->bus);
29112bd3c8bSSascha Wildner 
29212bd3c8bSSascha Wildner 			usbd_transfer_submit(xfer);
29312bd3c8bSSascha Wildner 
29412bd3c8bSSascha Wildner 			USB_BUS_LOCK(udev->bus);
29512bd3c8bSSascha Wildner 			break;
29612bd3c8bSSascha Wildner 		}
29712bd3c8bSSascha Wildner 		ep++;
29812bd3c8bSSascha Wildner 		to--;
29912bd3c8bSSascha Wildner 		goto tr_setup;
30012bd3c8bSSascha Wildner 
30112bd3c8bSSascha Wildner 	default:
30212bd3c8bSSascha Wildner 		if (error == USB_ERR_CANCELLED)
30312bd3c8bSSascha Wildner 			break;
30412bd3c8bSSascha Wildner 
30512bd3c8bSSascha Wildner 		DPRINTF("Clear stall failed.\n");
30612bd3c8bSSascha Wildner 
30712bd3c8bSSascha Wildner 		/*
30812bd3c8bSSascha Wildner 		 * Some VMs like VirtualBox always return failure on
30912bd3c8bSSascha Wildner 		 * clear-stall which we sometimes should just ignore.
31012bd3c8bSSascha Wildner 		 */
31112bd3c8bSSascha Wildner 		if (usb_no_cs_fail)
31212bd3c8bSSascha Wildner 			goto tr_transferred;
31312bd3c8bSSascha Wildner 		if (udev->clear_stall_errors == USB_CS_RESET_LIMIT)
31412bd3c8bSSascha Wildner 			goto tr_setup;
31512bd3c8bSSascha Wildner 
31612bd3c8bSSascha Wildner 		if (error == USB_ERR_TIMEOUT) {
31712bd3c8bSSascha Wildner 			udev->clear_stall_errors = USB_CS_RESET_LIMIT;
31812bd3c8bSSascha Wildner 			DPRINTF("Trying to re-enumerate.\n");
31912bd3c8bSSascha Wildner 			usbd_start_re_enumerate(udev);
32012bd3c8bSSascha Wildner 		} else {
32112bd3c8bSSascha Wildner 			udev->clear_stall_errors++;
32212bd3c8bSSascha Wildner 			if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) {
32312bd3c8bSSascha Wildner 				DPRINTF("Trying to re-enumerate.\n");
32412bd3c8bSSascha Wildner 				usbd_start_re_enumerate(udev);
32512bd3c8bSSascha Wildner 			}
32612bd3c8bSSascha Wildner 		}
32712bd3c8bSSascha Wildner 		goto tr_setup;
32812bd3c8bSSascha Wildner 	}
32912bd3c8bSSascha Wildner 
33012bd3c8bSSascha Wildner 	/* store current endpoint */
33112bd3c8bSSascha Wildner 	udev->ep_curr = ep;
33212bd3c8bSSascha Wildner 	USB_BUS_UNLOCK(udev->bus);
33312bd3c8bSSascha Wildner }
33412bd3c8bSSascha Wildner 
33512bd3c8bSSascha Wildner static usb_handle_req_t *
usbd_get_hr_func(struct usb_device * udev)33612bd3c8bSSascha Wildner usbd_get_hr_func(struct usb_device *udev)
33712bd3c8bSSascha Wildner {
33812bd3c8bSSascha Wildner 	/* figure out if there is a Handle Request function */
33912bd3c8bSSascha Wildner 	if (udev->flags.usb_mode == USB_MODE_DEVICE)
34012bd3c8bSSascha Wildner 		return (usb_temp_get_desc_p);
34112bd3c8bSSascha Wildner 	else if (udev->parent_hub == NULL)
34212bd3c8bSSascha Wildner 		return (udev->bus->methods->roothub_exec);
34312bd3c8bSSascha Wildner 	else
34412bd3c8bSSascha Wildner 		return (NULL);
34512bd3c8bSSascha Wildner }
34612bd3c8bSSascha Wildner 
34712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
34812bd3c8bSSascha Wildner  *	usbd_do_request_flags and usbd_do_request
34912bd3c8bSSascha Wildner  *
35012bd3c8bSSascha Wildner  * Description of arguments passed to these functions:
35112bd3c8bSSascha Wildner  *
35212bd3c8bSSascha Wildner  * "udev" - this is the "usb_device" structure pointer on which the
35312bd3c8bSSascha Wildner  * request should be performed. It is possible to call this function
35412bd3c8bSSascha Wildner  * in both Host Side mode and Device Side mode.
35512bd3c8bSSascha Wildner  *
35612bd3c8bSSascha Wildner  * "mtx" - if this argument is non-NULL the mutex pointed to by it
35712bd3c8bSSascha Wildner  * will get dropped and picked up during the execution of this
35812bd3c8bSSascha Wildner  * function, hence this function sometimes needs to sleep. If this
35912bd3c8bSSascha Wildner  * argument is NULL it has no effect.
36012bd3c8bSSascha Wildner  *
36112bd3c8bSSascha Wildner  * "req" - this argument must always be non-NULL and points to an
36212bd3c8bSSascha Wildner  * 8-byte structure holding the USB request to be done. The USB
36312bd3c8bSSascha Wildner  * request structure has a bit telling the direction of the USB
36412bd3c8bSSascha Wildner  * request, if it is a read or a write.
36512bd3c8bSSascha Wildner  *
36612bd3c8bSSascha Wildner  * "data" - if the "wLength" part of the structure pointed to by "req"
36712bd3c8bSSascha Wildner  * is non-zero this argument must point to a valid kernel buffer which
36812bd3c8bSSascha Wildner  * can hold at least "wLength" bytes. If "wLength" is zero "data" can
36912bd3c8bSSascha Wildner  * be NULL.
37012bd3c8bSSascha Wildner  *
37112bd3c8bSSascha Wildner  * "flags" - here is a list of valid flags:
37212bd3c8bSSascha Wildner  *
37312bd3c8bSSascha Wildner  *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
37412bd3c8bSSascha Wildner  *  specified
37512bd3c8bSSascha Wildner  *
37612bd3c8bSSascha Wildner  *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
37712bd3c8bSSascha Wildner  *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
37812bd3c8bSSascha Wildner  *  sysctl. This flag is mostly useful for debugging.
37912bd3c8bSSascha Wildner  *
38012bd3c8bSSascha Wildner  *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
38112bd3c8bSSascha Wildner  *  pointer.
38212bd3c8bSSascha Wildner  *
38312bd3c8bSSascha Wildner  * "actlen" - if non-NULL the actual transfer length will be stored in
38412bd3c8bSSascha Wildner  * the 16-bit unsigned integer pointed to by "actlen". This
38512bd3c8bSSascha Wildner  * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
38612bd3c8bSSascha Wildner  * used.
38712bd3c8bSSascha Wildner  *
38812bd3c8bSSascha Wildner  * "timeout" - gives the timeout for the control transfer in
38912bd3c8bSSascha Wildner  * milliseconds. A "timeout" value less than 50 milliseconds is
39012bd3c8bSSascha Wildner  * treated like a 50 millisecond timeout. A "timeout" value greater
39112bd3c8bSSascha Wildner  * than 30 seconds is treated like a 30 second timeout. This USB stack
39212bd3c8bSSascha Wildner  * does not allow control requests without a timeout.
39312bd3c8bSSascha Wildner  *
3948922de18SMarkus Pfeiffer  * NOTE: This function is thread safe. All calls to "usbd_do_request_flags"
3958922de18SMarkus Pfeiffer  * will be serialized by the use of the USB device enumeration lock.
39612bd3c8bSSascha Wildner  *
39712bd3c8bSSascha Wildner  * Returns:
39812bd3c8bSSascha Wildner  *    0: Success
39912bd3c8bSSascha Wildner  * Else: Failure
40012bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
40112bd3c8bSSascha Wildner usb_error_t
usbd_do_request_flags(struct usb_device * udev,struct lock * lock,struct usb_device_request * req,void * data,uint16_t flags,uint16_t * actlen,usb_timeout_t timeout)402722d05c3SSascha Wildner usbd_do_request_flags(struct usb_device *udev, struct lock *lock,
40312bd3c8bSSascha Wildner     struct usb_device_request *req, void *data, uint16_t flags,
40412bd3c8bSSascha Wildner     uint16_t *actlen, usb_timeout_t timeout)
40512bd3c8bSSascha Wildner {
40612bd3c8bSSascha Wildner #ifdef USB_REQ_DEBUG
40712bd3c8bSSascha Wildner 	struct usb_ctrl_debug_bits dbg;
40812bd3c8bSSascha Wildner #endif
40912bd3c8bSSascha Wildner 	usb_handle_req_t *hr_func;
41012bd3c8bSSascha Wildner 	struct usb_xfer *xfer;
41112bd3c8bSSascha Wildner 	const void *desc;
41212bd3c8bSSascha Wildner 	int err = 0;
41312bd3c8bSSascha Wildner 	usb_ticks_t start_ticks;
41412bd3c8bSSascha Wildner 	usb_ticks_t delta_ticks;
41512bd3c8bSSascha Wildner 	usb_ticks_t max_ticks;
41612bd3c8bSSascha Wildner 	uint16_t length;
41712bd3c8bSSascha Wildner 	uint16_t temp;
41812bd3c8bSSascha Wildner 	uint16_t acttemp;
41957bed822SMarkus Pfeiffer 	uint8_t do_unlock;
42012bd3c8bSSascha Wildner 
42112bd3c8bSSascha Wildner 	if (timeout < 50) {
42212bd3c8bSSascha Wildner 		/* timeout is too small */
42312bd3c8bSSascha Wildner 		timeout = 50;
42412bd3c8bSSascha Wildner 	}
42512bd3c8bSSascha Wildner 	if (timeout > 30000) {
42612bd3c8bSSascha Wildner 		/* timeout is too big */
42712bd3c8bSSascha Wildner 		timeout = 30000;
42812bd3c8bSSascha Wildner 	}
42912bd3c8bSSascha Wildner 	length = UGETW(req->wLength);
43012bd3c8bSSascha Wildner 
43112bd3c8bSSascha Wildner 	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
43212bd3c8bSSascha Wildner 	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
43312bd3c8bSSascha Wildner 	    udev, req->bmRequestType, req->bRequest,
43412bd3c8bSSascha Wildner 	    req->wValue[1], req->wValue[0],
43512bd3c8bSSascha Wildner 	    req->wIndex[1], req->wIndex[0],
43612bd3c8bSSascha Wildner 	    req->wLength[1], req->wLength[0]);
43712bd3c8bSSascha Wildner 
43812bd3c8bSSascha Wildner 	/* Check if the device is still alive */
43912bd3c8bSSascha Wildner 	if (udev->state < USB_STATE_POWERED) {
44012bd3c8bSSascha Wildner 		DPRINTF("usb device has gone\n");
44112bd3c8bSSascha Wildner 		return (USB_ERR_NOT_CONFIGURED);
44212bd3c8bSSascha Wildner 	}
44312bd3c8bSSascha Wildner 
44412bd3c8bSSascha Wildner 	/*
44512bd3c8bSSascha Wildner 	 * Set "actlen" to a known value in case the caller does not
44612bd3c8bSSascha Wildner 	 * check the return value:
44712bd3c8bSSascha Wildner 	 */
44812bd3c8bSSascha Wildner 	if (actlen)
44912bd3c8bSSascha Wildner 		*actlen = 0;
45012bd3c8bSSascha Wildner 
45112bd3c8bSSascha Wildner #if (USB_HAVE_USER_IO == 0)
45212bd3c8bSSascha Wildner 	if (flags & USB_USER_DATA_PTR)
45312bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
45412bd3c8bSSascha Wildner #endif
45563da4a34SSascha Wildner #if 0
45612bd3c8bSSascha Wildner 	if ((mtx != NULL) && (mtx != &Giant)) {
45763da4a34SSascha Wildner #endif
458722d05c3SSascha Wildner 	if (lock != NULL) {
459722d05c3SSascha Wildner 		lockmgr(lock, LK_RELEASE);
4603a76bbe8SSascha Wildner 		KKASSERT(!lockowned(lock));
46112bd3c8bSSascha Wildner 	}
46212bd3c8bSSascha Wildner 
46312bd3c8bSSascha Wildner 	/*
46457bed822SMarkus Pfeiffer 	 * Grab the USB device enumeration SX-lock serialization is
46557bed822SMarkus Pfeiffer 	 * achieved when multiple threads are involved:
46657bed822SMarkus Pfeiffer 	 */
46757bed822SMarkus Pfeiffer 	do_unlock = usbd_enum_lock(udev);
46857bed822SMarkus Pfeiffer 
46957bed822SMarkus Pfeiffer 	/*
47012bd3c8bSSascha Wildner 	 * We need to allow suspend and resume at this point, else the
47112bd3c8bSSascha Wildner 	 * control transfer will timeout if the device is suspended!
47212bd3c8bSSascha Wildner 	 */
47312bd3c8bSSascha Wildner 	usbd_sr_unlock(udev);
47412bd3c8bSSascha Wildner 
47512bd3c8bSSascha Wildner 	hr_func = usbd_get_hr_func(udev);
47612bd3c8bSSascha Wildner 
47712bd3c8bSSascha Wildner 	if (hr_func != NULL) {
47812bd3c8bSSascha Wildner 		DPRINTF("Handle Request function is set\n");
47912bd3c8bSSascha Wildner 
48012bd3c8bSSascha Wildner 		desc = NULL;
48112bd3c8bSSascha Wildner 		temp = 0;
48212bd3c8bSSascha Wildner 
48312bd3c8bSSascha Wildner 		if (!(req->bmRequestType & UT_READ)) {
48412bd3c8bSSascha Wildner 			if (length != 0) {
48512bd3c8bSSascha Wildner 				DPRINTFN(1, "The handle request function "
48612bd3c8bSSascha Wildner 				    "does not support writing data!\n");
48712bd3c8bSSascha Wildner 				err = USB_ERR_INVAL;
48812bd3c8bSSascha Wildner 				goto done;
48912bd3c8bSSascha Wildner 			}
49012bd3c8bSSascha Wildner 		}
49112bd3c8bSSascha Wildner 
49212bd3c8bSSascha Wildner 		/* The root HUB code needs the BUS lock locked */
49312bd3c8bSSascha Wildner 
49412bd3c8bSSascha Wildner 		USB_BUS_LOCK(udev->bus);
49512bd3c8bSSascha Wildner 		err = (hr_func) (udev, req, &desc, &temp);
49612bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(udev->bus);
49712bd3c8bSSascha Wildner 
49812bd3c8bSSascha Wildner 		if (err)
49912bd3c8bSSascha Wildner 			goto done;
50012bd3c8bSSascha Wildner 
50112bd3c8bSSascha Wildner 		if (length > temp) {
50212bd3c8bSSascha Wildner 			if (!(flags & USB_SHORT_XFER_OK)) {
50312bd3c8bSSascha Wildner 				err = USB_ERR_SHORT_XFER;
50412bd3c8bSSascha Wildner 				goto done;
50512bd3c8bSSascha Wildner 			}
50612bd3c8bSSascha Wildner 			length = temp;
50712bd3c8bSSascha Wildner 		}
50812bd3c8bSSascha Wildner 		if (actlen)
50912bd3c8bSSascha Wildner 			*actlen = length;
51012bd3c8bSSascha Wildner 
51112bd3c8bSSascha Wildner 		if (length > 0) {
51212bd3c8bSSascha Wildner #if USB_HAVE_USER_IO
51312bd3c8bSSascha Wildner 			if (flags & USB_USER_DATA_PTR) {
51412bd3c8bSSascha Wildner 				if (copyout(desc, data, length)) {
51512bd3c8bSSascha Wildner 					err = USB_ERR_INVAL;
51612bd3c8bSSascha Wildner 					goto done;
51712bd3c8bSSascha Wildner 				}
51812bd3c8bSSascha Wildner 			} else
51912bd3c8bSSascha Wildner #endif
52012bd3c8bSSascha Wildner 				memcpy(data, desc, length);
52112bd3c8bSSascha Wildner 		}
52212bd3c8bSSascha Wildner 		goto done;		/* success */
52312bd3c8bSSascha Wildner 	}
52412bd3c8bSSascha Wildner 
52512bd3c8bSSascha Wildner 	/*
52612bd3c8bSSascha Wildner 	 * Setup a new USB transfer or use the existing one, if any:
52712bd3c8bSSascha Wildner 	 */
52812bd3c8bSSascha Wildner 	usbd_ctrl_transfer_setup(udev);
52912bd3c8bSSascha Wildner 
53012bd3c8bSSascha Wildner 	xfer = udev->ctrl_xfer[0];
53112bd3c8bSSascha Wildner 	if (xfer == NULL) {
53212bd3c8bSSascha Wildner 		/* most likely out of memory */
53312bd3c8bSSascha Wildner 		err = USB_ERR_NOMEM;
53412bd3c8bSSascha Wildner 		goto done;
53512bd3c8bSSascha Wildner 	}
53612bd3c8bSSascha Wildner 
53712bd3c8bSSascha Wildner #ifdef USB_REQ_DEBUG
53812bd3c8bSSascha Wildner 	/* Get debug bits */
53912bd3c8bSSascha Wildner 	usbd_get_debug_bits(udev, req, &dbg);
54012bd3c8bSSascha Wildner 
54112bd3c8bSSascha Wildner 	/* Check for fault injection */
54212bd3c8bSSascha Wildner 	if (dbg.enabled)
54312bd3c8bSSascha Wildner 		flags |= USB_DELAY_STATUS_STAGE;
54412bd3c8bSSascha Wildner #endif
54512bd3c8bSSascha Wildner 	USB_XFER_LOCK(xfer);
54612bd3c8bSSascha Wildner 
54712bd3c8bSSascha Wildner 	if (flags & USB_DELAY_STATUS_STAGE)
54812bd3c8bSSascha Wildner 		xfer->flags.manual_status = 1;
54912bd3c8bSSascha Wildner 	else
55012bd3c8bSSascha Wildner 		xfer->flags.manual_status = 0;
55112bd3c8bSSascha Wildner 
55212bd3c8bSSascha Wildner 	if (flags & USB_SHORT_XFER_OK)
55312bd3c8bSSascha Wildner 		xfer->flags.short_xfer_ok = 1;
55412bd3c8bSSascha Wildner 	else
55512bd3c8bSSascha Wildner 		xfer->flags.short_xfer_ok = 0;
55612bd3c8bSSascha Wildner 
55712bd3c8bSSascha Wildner 	xfer->timeout = timeout;
55812bd3c8bSSascha Wildner 
55912bd3c8bSSascha Wildner 	start_ticks = ticks;
56012bd3c8bSSascha Wildner 
56112bd3c8bSSascha Wildner 	max_ticks = USB_MS_TO_TICKS(timeout);
56212bd3c8bSSascha Wildner 
56312bd3c8bSSascha Wildner 	usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req));
56412bd3c8bSSascha Wildner 
56512bd3c8bSSascha Wildner 	usbd_xfer_set_frame_len(xfer, 0, sizeof(*req));
56612bd3c8bSSascha Wildner 
56712bd3c8bSSascha Wildner 	while (1) {
56812bd3c8bSSascha Wildner 		temp = length;
56912bd3c8bSSascha Wildner 		if (temp > usbd_xfer_max_len(xfer)) {
57012bd3c8bSSascha Wildner 			temp = usbd_xfer_max_len(xfer);
57112bd3c8bSSascha Wildner 		}
57212bd3c8bSSascha Wildner #ifdef USB_REQ_DEBUG
57312bd3c8bSSascha Wildner 		if (xfer->flags.manual_status) {
57412bd3c8bSSascha Wildner 			if (usbd_xfer_frame_len(xfer, 0) != 0) {
57512bd3c8bSSascha Wildner 				/* Execute data stage separately */
57612bd3c8bSSascha Wildner 				temp = 0;
57712bd3c8bSSascha Wildner 			} else if (temp > 0) {
57812bd3c8bSSascha Wildner 				if (dbg.ds_fail) {
57912bd3c8bSSascha Wildner 					err = USB_ERR_INVAL;
58012bd3c8bSSascha Wildner 					break;
58112bd3c8bSSascha Wildner 				}
58212bd3c8bSSascha Wildner 				if (dbg.ds_delay > 0) {
58312bd3c8bSSascha Wildner 					usb_pause_mtx(
584722d05c3SSascha Wildner 					    xfer->xroot->xfer_lock,
58512bd3c8bSSascha Wildner 				            USB_MS_TO_TICKS(dbg.ds_delay));
58612bd3c8bSSascha Wildner 					/* make sure we don't time out */
58712bd3c8bSSascha Wildner 					start_ticks = ticks;
58812bd3c8bSSascha Wildner 				}
58912bd3c8bSSascha Wildner 			}
59012bd3c8bSSascha Wildner 		}
59112bd3c8bSSascha Wildner #endif
59212bd3c8bSSascha Wildner 		usbd_xfer_set_frame_len(xfer, 1, temp);
59312bd3c8bSSascha Wildner 
59412bd3c8bSSascha Wildner 		if (temp > 0) {
59512bd3c8bSSascha Wildner 			if (!(req->bmRequestType & UT_READ)) {
59612bd3c8bSSascha Wildner #if USB_HAVE_USER_IO
59712bd3c8bSSascha Wildner 				if (flags & USB_USER_DATA_PTR) {
59812bd3c8bSSascha Wildner 					USB_XFER_UNLOCK(xfer);
59912bd3c8bSSascha Wildner 					err = usbd_copy_in_user(xfer->frbuffers + 1,
60012bd3c8bSSascha Wildner 					    0, data, temp);
60112bd3c8bSSascha Wildner 					USB_XFER_LOCK(xfer);
60212bd3c8bSSascha Wildner 					if (err) {
60312bd3c8bSSascha Wildner 						err = USB_ERR_INVAL;
60412bd3c8bSSascha Wildner 						break;
60512bd3c8bSSascha Wildner 					}
60612bd3c8bSSascha Wildner 				} else
60712bd3c8bSSascha Wildner #endif
60812bd3c8bSSascha Wildner 					usbd_copy_in(xfer->frbuffers + 1,
60912bd3c8bSSascha Wildner 					    0, data, temp);
61012bd3c8bSSascha Wildner 			}
61112bd3c8bSSascha Wildner 			usbd_xfer_set_frames(xfer, 2);
61212bd3c8bSSascha Wildner 		} else {
61312bd3c8bSSascha Wildner 			if (usbd_xfer_frame_len(xfer, 0) == 0) {
61412bd3c8bSSascha Wildner 				if (xfer->flags.manual_status) {
61512bd3c8bSSascha Wildner #ifdef USB_REQ_DEBUG
61612bd3c8bSSascha Wildner 					if (dbg.ss_fail) {
61712bd3c8bSSascha Wildner 						err = USB_ERR_INVAL;
61812bd3c8bSSascha Wildner 						break;
61912bd3c8bSSascha Wildner 					}
62012bd3c8bSSascha Wildner 					if (dbg.ss_delay > 0) {
62112bd3c8bSSascha Wildner 						usb_pause_mtx(
622722d05c3SSascha Wildner 						    xfer->xroot->xfer_lock,
62312bd3c8bSSascha Wildner 						    USB_MS_TO_TICKS(dbg.ss_delay));
62412bd3c8bSSascha Wildner 						/* make sure we don't time out */
62512bd3c8bSSascha Wildner 						start_ticks = ticks;
62612bd3c8bSSascha Wildner 					}
62712bd3c8bSSascha Wildner #endif
62812bd3c8bSSascha Wildner 					xfer->flags.manual_status = 0;
62912bd3c8bSSascha Wildner 				} else {
63012bd3c8bSSascha Wildner 					break;
63112bd3c8bSSascha Wildner 				}
63212bd3c8bSSascha Wildner 			}
63312bd3c8bSSascha Wildner 			usbd_xfer_set_frames(xfer, 1);
63412bd3c8bSSascha Wildner 		}
63512bd3c8bSSascha Wildner 
63612bd3c8bSSascha Wildner 		usbd_transfer_start(xfer);
63712bd3c8bSSascha Wildner 
638ccb00b06SMatthew Dillon 		/*
639ccb00b06SMatthew Dillon 		 * XXX hack, the wakeup of xfer can race conditions which
640ccb00b06SMatthew Dillon 		 *     clear the pending status of the xfer.
641ccb00b06SMatthew Dillon 		 */
64212bd3c8bSSascha Wildner 		while (usbd_transfer_pending(xfer)) {
643ccb00b06SMatthew Dillon 			lksleep(xfer, xfer->xroot->xfer_lock, 0, "WXFER", hz);
64412bd3c8bSSascha Wildner 		}
64512bd3c8bSSascha Wildner 
64612bd3c8bSSascha Wildner 		err = xfer->error;
64712bd3c8bSSascha Wildner 
64812bd3c8bSSascha Wildner 		if (err) {
64912bd3c8bSSascha Wildner 			break;
65012bd3c8bSSascha Wildner 		}
65112bd3c8bSSascha Wildner 
65212bd3c8bSSascha Wildner 		/* get actual length of DATA stage */
65312bd3c8bSSascha Wildner 
65412bd3c8bSSascha Wildner 		if (xfer->aframes < 2) {
65512bd3c8bSSascha Wildner 			acttemp = 0;
65612bd3c8bSSascha Wildner 		} else {
65712bd3c8bSSascha Wildner 			acttemp = usbd_xfer_frame_len(xfer, 1);
65812bd3c8bSSascha Wildner 		}
65912bd3c8bSSascha Wildner 
66012bd3c8bSSascha Wildner 		/* check for short packet */
66112bd3c8bSSascha Wildner 
66212bd3c8bSSascha Wildner 		if (temp > acttemp) {
66312bd3c8bSSascha Wildner 			temp = acttemp;
66412bd3c8bSSascha Wildner 			length = temp;
66512bd3c8bSSascha Wildner 		}
66612bd3c8bSSascha Wildner 		if (temp > 0) {
66712bd3c8bSSascha Wildner 			if (req->bmRequestType & UT_READ) {
66812bd3c8bSSascha Wildner #if USB_HAVE_USER_IO
66912bd3c8bSSascha Wildner 				if (flags & USB_USER_DATA_PTR) {
67012bd3c8bSSascha Wildner 					USB_XFER_UNLOCK(xfer);
67112bd3c8bSSascha Wildner 					err = usbd_copy_out_user(xfer->frbuffers + 1,
67212bd3c8bSSascha Wildner 					    0, data, temp);
67312bd3c8bSSascha Wildner 					USB_XFER_LOCK(xfer);
67412bd3c8bSSascha Wildner 					if (err) {
67512bd3c8bSSascha Wildner 						err = USB_ERR_INVAL;
67612bd3c8bSSascha Wildner 						break;
67712bd3c8bSSascha Wildner 					}
67812bd3c8bSSascha Wildner 				} else
67912bd3c8bSSascha Wildner #endif
68012bd3c8bSSascha Wildner 					usbd_copy_out(xfer->frbuffers + 1,
68112bd3c8bSSascha Wildner 					    0, data, temp);
68212bd3c8bSSascha Wildner 			}
68312bd3c8bSSascha Wildner 		}
68412bd3c8bSSascha Wildner 		/*
68512bd3c8bSSascha Wildner 		 * Clear "frlengths[0]" so that we don't send the setup
68612bd3c8bSSascha Wildner 		 * packet again:
68712bd3c8bSSascha Wildner 		 */
68812bd3c8bSSascha Wildner 		usbd_xfer_set_frame_len(xfer, 0, 0);
68912bd3c8bSSascha Wildner 
69012bd3c8bSSascha Wildner 		/* update length and data pointer */
69112bd3c8bSSascha Wildner 		length -= temp;
69212bd3c8bSSascha Wildner 		data = USB_ADD_BYTES(data, temp);
69312bd3c8bSSascha Wildner 
69412bd3c8bSSascha Wildner 		if (actlen) {
69512bd3c8bSSascha Wildner 			(*actlen) += temp;
69612bd3c8bSSascha Wildner 		}
69712bd3c8bSSascha Wildner 		/* check for timeout */
69812bd3c8bSSascha Wildner 
69912bd3c8bSSascha Wildner 		delta_ticks = ticks - start_ticks;
70012bd3c8bSSascha Wildner 		if (delta_ticks > max_ticks) {
70112bd3c8bSSascha Wildner 			if (!err) {
70212bd3c8bSSascha Wildner 				err = USB_ERR_TIMEOUT;
70312bd3c8bSSascha Wildner 			}
70412bd3c8bSSascha Wildner 		}
70512bd3c8bSSascha Wildner 		if (err) {
70612bd3c8bSSascha Wildner 			break;
70712bd3c8bSSascha Wildner 		}
70812bd3c8bSSascha Wildner 	}
70912bd3c8bSSascha Wildner 
71012bd3c8bSSascha Wildner 	if (err) {
71112bd3c8bSSascha Wildner 		/*
71212bd3c8bSSascha Wildner 		 * Make sure that the control endpoint is no longer
71312bd3c8bSSascha Wildner 		 * blocked in case of a non-transfer related error:
71412bd3c8bSSascha Wildner 		 */
71512bd3c8bSSascha Wildner 		usbd_transfer_stop(xfer);
71612bd3c8bSSascha Wildner 	}
71712bd3c8bSSascha Wildner 	USB_XFER_UNLOCK(xfer);
71812bd3c8bSSascha Wildner 
719fe8b458aSMatthew Dillon 	if (udev->flags.uq_delay_ctrl) {
720fe8b458aSMatthew Dillon 		usb_pause_mtx(NULL, 200 * hz / 1000 + 1);
721fe8b458aSMatthew Dillon 	}
722fe8b458aSMatthew Dillon 
72312bd3c8bSSascha Wildner done:
72412bd3c8bSSascha Wildner 	usbd_sr_lock(udev);
72512bd3c8bSSascha Wildner 
72657bed822SMarkus Pfeiffer 	if (do_unlock)
72757bed822SMarkus Pfeiffer 		usbd_enum_unlock(udev);
72857bed822SMarkus Pfeiffer 
72963da4a34SSascha Wildner #if 0
73012bd3c8bSSascha Wildner 	if ((mtx != NULL) && (mtx != &Giant))
73163da4a34SSascha Wildner #endif
732722d05c3SSascha Wildner 	if (lock != NULL)
733722d05c3SSascha Wildner 		lockmgr(lock, LK_EXCLUSIVE);
73412bd3c8bSSascha Wildner 
735b86003c4SMarkus Pfeiffer 	switch (err) {
736b86003c4SMarkus Pfeiffer 	case USB_ERR_NORMAL_COMPLETION:
737b86003c4SMarkus Pfeiffer 	case USB_ERR_SHORT_XFER:
738b86003c4SMarkus Pfeiffer 	case USB_ERR_STALLED:
739b86003c4SMarkus Pfeiffer 	case USB_ERR_CANCELLED:
740b86003c4SMarkus Pfeiffer 		break;
741b86003c4SMarkus Pfeiffer 	default:
742b86003c4SMarkus Pfeiffer 		DPRINTF("I/O error - waiting a bit for TT cleanup\n");
743b86003c4SMarkus Pfeiffer 		usb_pause_mtx(lock, hz / 16);
744b86003c4SMarkus Pfeiffer 		break;
745b86003c4SMarkus Pfeiffer 	}
74612bd3c8bSSascha Wildner 	return ((usb_error_t)err);
74712bd3c8bSSascha Wildner }
74812bd3c8bSSascha Wildner 
74912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
75012bd3c8bSSascha Wildner  *	usbd_do_request_proc - factored out code
75112bd3c8bSSascha Wildner  *
75212bd3c8bSSascha Wildner  * This function is factored out code. It does basically the same like
75312bd3c8bSSascha Wildner  * usbd_do_request_flags, except it will check the status of the
75412bd3c8bSSascha Wildner  * passed process argument before doing the USB request. If the
75512bd3c8bSSascha Wildner  * process is draining the USB_ERR_IOERROR code will be returned. It
75612bd3c8bSSascha Wildner  * is assumed that the mutex associated with the process is locked
75712bd3c8bSSascha Wildner  * when calling this function.
75812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
75912bd3c8bSSascha Wildner usb_error_t
76012bd3c8bSSascha Wildner usbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc,
76112bd3c8bSSascha Wildner     struct usb_device_request *req, void *data, uint16_t flags,
76212bd3c8bSSascha Wildner     uint16_t *actlen, usb_timeout_t timeout)
76312bd3c8bSSascha Wildner {
76412bd3c8bSSascha Wildner 	usb_error_t err;
76512bd3c8bSSascha Wildner 	uint16_t len;
76612bd3c8bSSascha Wildner 
76712bd3c8bSSascha Wildner 	/* get request data length */
76812bd3c8bSSascha Wildner 	len = UGETW(req->wLength);
76912bd3c8bSSascha Wildner 
77012bd3c8bSSascha Wildner 	/* check if the device is being detached */
77112bd3c8bSSascha Wildner 	if (usb_proc_is_gone(pproc)) {
77212bd3c8bSSascha Wildner 		err = USB_ERR_IOERROR;
77312bd3c8bSSascha Wildner 		goto done;
77412bd3c8bSSascha Wildner 	}
77512bd3c8bSSascha Wildner 
77612bd3c8bSSascha Wildner 	/* forward the USB request */
777722d05c3SSascha Wildner 	err = usbd_do_request_flags(udev, pproc->up_lock,
77812bd3c8bSSascha Wildner 	    req, data, flags, actlen, timeout);
77912bd3c8bSSascha Wildner 
78012bd3c8bSSascha Wildner done:
78112bd3c8bSSascha Wildner 	/* on failure we zero the data */
78212bd3c8bSSascha Wildner 	/* on short packet we zero the unused data */
78312bd3c8bSSascha Wildner 	if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) {
78412bd3c8bSSascha Wildner 		if (err)
78512bd3c8bSSascha Wildner 			memset(data, 0, len);
78612bd3c8bSSascha Wildner 		else if (actlen && *actlen != len)
78712bd3c8bSSascha Wildner 			memset(((uint8_t *)data) + *actlen, 0, len - *actlen);
78812bd3c8bSSascha Wildner 	}
78912bd3c8bSSascha Wildner 	return (err);
79012bd3c8bSSascha Wildner }
79112bd3c8bSSascha Wildner 
79212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
79312bd3c8bSSascha Wildner  *	usbd_req_reset_port
79412bd3c8bSSascha Wildner  *
79512bd3c8bSSascha Wildner  * This function will instruct a USB HUB to perform a reset sequence
79612bd3c8bSSascha Wildner  * on the specified port number.
79712bd3c8bSSascha Wildner  *
79812bd3c8bSSascha Wildner  * Returns:
79912bd3c8bSSascha Wildner  *    0: Success. The USB device should now be at address zero.
80012bd3c8bSSascha Wildner  * Else: Failure. No USB device is present and the USB port should be
80112bd3c8bSSascha Wildner  *       disabled.
80212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
80312bd3c8bSSascha Wildner usb_error_t
804722d05c3SSascha Wildner usbd_req_reset_port(struct usb_device *udev, struct lock *lock, uint8_t port)
80512bd3c8bSSascha Wildner {
80612bd3c8bSSascha Wildner 	struct usb_port_status ps;
80712bd3c8bSSascha Wildner 	usb_error_t err;
80812bd3c8bSSascha Wildner 	uint16_t n;
80912bd3c8bSSascha Wildner 	uint16_t status;
81012bd3c8bSSascha Wildner 	uint16_t change;
81112bd3c8bSSascha Wildner 
81212bd3c8bSSascha Wildner 	DPRINTF("\n");
81312bd3c8bSSascha Wildner 
81412bd3c8bSSascha Wildner 	/* clear any leftover port reset changes first */
81512bd3c8bSSascha Wildner 	usbd_req_clear_port_feature(
816722d05c3SSascha Wildner 	    udev, lock, port, UHF_C_PORT_RESET);
81712bd3c8bSSascha Wildner 
81812bd3c8bSSascha Wildner 	/* assert port reset on the given port */
81912bd3c8bSSascha Wildner 	err = usbd_req_set_port_feature(
820722d05c3SSascha Wildner 	    udev, lock, port, UHF_PORT_RESET);
82112bd3c8bSSascha Wildner 
82212bd3c8bSSascha Wildner 	/* check for errors */
82312bd3c8bSSascha Wildner 	if (err)
82412bd3c8bSSascha Wildner 		goto done;
82512bd3c8bSSascha Wildner 	n = 0;
82612bd3c8bSSascha Wildner 	while (1) {
82712bd3c8bSSascha Wildner 		/* wait for the device to recover from reset */
8285e41ab93SMarkus Pfeiffer 		usb_pause_mtx(lock, USB_MS_TO_TICKS(usb_port_reset_delay));
8295e41ab93SMarkus Pfeiffer 		n += usb_port_reset_delay;
830722d05c3SSascha Wildner 		err = usbd_req_get_port_status(udev, lock, &ps, port);
83112bd3c8bSSascha Wildner 		if (err)
83212bd3c8bSSascha Wildner 			goto done;
83312bd3c8bSSascha Wildner 
83412bd3c8bSSascha Wildner 		status = UGETW(ps.wPortStatus);
83512bd3c8bSSascha Wildner 		change = UGETW(ps.wPortChange);
83612bd3c8bSSascha Wildner 
83712bd3c8bSSascha Wildner 		/* if the device disappeared, just give up */
83812bd3c8bSSascha Wildner 		if (!(status & UPS_CURRENT_CONNECT_STATUS))
83912bd3c8bSSascha Wildner 			goto done;
84012bd3c8bSSascha Wildner 
84112bd3c8bSSascha Wildner 		/* check if reset is complete */
84212bd3c8bSSascha Wildner 		if (change & UPS_C_PORT_RESET)
84312bd3c8bSSascha Wildner 			break;
84412bd3c8bSSascha Wildner 
84512bd3c8bSSascha Wildner 		/*
84612bd3c8bSSascha Wildner 		 * Some Virtual Machines like VirtualBox 4.x fail to
84712bd3c8bSSascha Wildner 		 * generate a port reset change event. Check if reset
84812bd3c8bSSascha Wildner 		 * is no longer asserted.
84912bd3c8bSSascha Wildner 		 */
85012bd3c8bSSascha Wildner 		if (!(status & UPS_RESET))
85112bd3c8bSSascha Wildner 			break;
85212bd3c8bSSascha Wildner 
85312bd3c8bSSascha Wildner 		/* check for timeout */
85412bd3c8bSSascha Wildner 		if (n > 1000) {
85512bd3c8bSSascha Wildner 			n = 0;
85612bd3c8bSSascha Wildner 			break;
85712bd3c8bSSascha Wildner 		}
85812bd3c8bSSascha Wildner 	}
85912bd3c8bSSascha Wildner 
86012bd3c8bSSascha Wildner 	/* clear port reset first */
86112bd3c8bSSascha Wildner 	err = usbd_req_clear_port_feature(
862722d05c3SSascha Wildner 	    udev, lock, port, UHF_C_PORT_RESET);
86312bd3c8bSSascha Wildner 	if (err)
86412bd3c8bSSascha Wildner 		goto done;
86512bd3c8bSSascha Wildner 
86612bd3c8bSSascha Wildner 	/* check for timeout */
86712bd3c8bSSascha Wildner 	if (n == 0) {
86812bd3c8bSSascha Wildner 		err = USB_ERR_TIMEOUT;
86912bd3c8bSSascha Wildner 		goto done;
87012bd3c8bSSascha Wildner 	}
87112bd3c8bSSascha Wildner 	/* wait for the device to recover from reset */
87257bed822SMarkus Pfeiffer 	usb_pause_mtx(lock, USB_MS_TO_TICKS(usb_port_reset_recovery));
87312bd3c8bSSascha Wildner 
87412bd3c8bSSascha Wildner done:
87512bd3c8bSSascha Wildner 	DPRINTFN(2, "port %d reset returning error=%s\n",
87612bd3c8bSSascha Wildner 	    port, usbd_errstr(err));
87712bd3c8bSSascha Wildner 	return (err);
87812bd3c8bSSascha Wildner }
87912bd3c8bSSascha Wildner 
88012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
88112bd3c8bSSascha Wildner  *	usbd_req_warm_reset_port
88212bd3c8bSSascha Wildner  *
88312bd3c8bSSascha Wildner  * This function will instruct an USB HUB to perform a warm reset
88412bd3c8bSSascha Wildner  * sequence on the specified port number. This kind of reset is not
88512bd3c8bSSascha Wildner  * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted
88612bd3c8bSSascha Wildner  * for SUPER-speed USB HUBs.
88712bd3c8bSSascha Wildner  *
88812bd3c8bSSascha Wildner  * Returns:
88912bd3c8bSSascha Wildner  *    0: Success. The USB device should now be available again.
89012bd3c8bSSascha Wildner  * Else: Failure. No USB device is present and the USB port should be
89112bd3c8bSSascha Wildner  *       disabled.
89212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
89312bd3c8bSSascha Wildner usb_error_t
894722d05c3SSascha Wildner usbd_req_warm_reset_port(struct usb_device *udev, struct lock *lock,
89512bd3c8bSSascha Wildner     uint8_t port)
89612bd3c8bSSascha Wildner {
89712bd3c8bSSascha Wildner 	struct usb_port_status ps;
89812bd3c8bSSascha Wildner 	usb_error_t err;
89912bd3c8bSSascha Wildner 	uint16_t n;
90012bd3c8bSSascha Wildner 	uint16_t status;
90112bd3c8bSSascha Wildner 	uint16_t change;
90212bd3c8bSSascha Wildner 
90312bd3c8bSSascha Wildner 	DPRINTF("\n");
90412bd3c8bSSascha Wildner 
905722d05c3SSascha Wildner 	err = usbd_req_get_port_status(udev, lock, &ps, port);
90612bd3c8bSSascha Wildner 	if (err)
90712bd3c8bSSascha Wildner 		goto done;
90812bd3c8bSSascha Wildner 
90912bd3c8bSSascha Wildner 	status = UGETW(ps.wPortStatus);
91012bd3c8bSSascha Wildner 
91112bd3c8bSSascha Wildner 	switch (UPS_PORT_LINK_STATE_GET(status)) {
91212bd3c8bSSascha Wildner 	case UPS_PORT_LS_U3:
91312bd3c8bSSascha Wildner 	case UPS_PORT_LS_COMP_MODE:
91412bd3c8bSSascha Wildner 	case UPS_PORT_LS_LOOPBACK:
91512bd3c8bSSascha Wildner 	case UPS_PORT_LS_SS_INA:
91612bd3c8bSSascha Wildner 		break;
91712bd3c8bSSascha Wildner 	default:
91812bd3c8bSSascha Wildner 		DPRINTF("Wrong state for warm reset\n");
91912bd3c8bSSascha Wildner 		return (0);
92012bd3c8bSSascha Wildner 	}
92112bd3c8bSSascha Wildner 
92212bd3c8bSSascha Wildner 	/* clear any leftover warm port reset changes first */
923722d05c3SSascha Wildner 	usbd_req_clear_port_feature(udev, lock,
92412bd3c8bSSascha Wildner 	    port, UHF_C_BH_PORT_RESET);
92512bd3c8bSSascha Wildner 
92612bd3c8bSSascha Wildner 	/* set warm port reset */
927722d05c3SSascha Wildner 	err = usbd_req_set_port_feature(udev, lock,
92812bd3c8bSSascha Wildner 	    port, UHF_BH_PORT_RESET);
92912bd3c8bSSascha Wildner 	if (err)
93012bd3c8bSSascha Wildner 		goto done;
93112bd3c8bSSascha Wildner 
93212bd3c8bSSascha Wildner 	n = 0;
93312bd3c8bSSascha Wildner 	while (1) {
93412bd3c8bSSascha Wildner 		/* wait for the device to recover from reset */
93557bed822SMarkus Pfeiffer 		usb_pause_mtx(lock, USB_MS_TO_TICKS(usb_port_reset_delay));
93657bed822SMarkus Pfeiffer 		n += usb_port_reset_delay;
937722d05c3SSascha Wildner 		err = usbd_req_get_port_status(udev, lock, &ps, port);
93812bd3c8bSSascha Wildner 		if (err)
93912bd3c8bSSascha Wildner 			goto done;
94012bd3c8bSSascha Wildner 
94112bd3c8bSSascha Wildner 		status = UGETW(ps.wPortStatus);
94212bd3c8bSSascha Wildner 		change = UGETW(ps.wPortChange);
94312bd3c8bSSascha Wildner 
94412bd3c8bSSascha Wildner 		/* if the device disappeared, just give up */
94512bd3c8bSSascha Wildner 		if (!(status & UPS_CURRENT_CONNECT_STATUS))
94612bd3c8bSSascha Wildner 			goto done;
94712bd3c8bSSascha Wildner 
94812bd3c8bSSascha Wildner 		/* check if reset is complete */
94912bd3c8bSSascha Wildner 		if (change & UPS_C_BH_PORT_RESET)
95012bd3c8bSSascha Wildner 			break;
95112bd3c8bSSascha Wildner 
95212bd3c8bSSascha Wildner 		/* check for timeout */
95312bd3c8bSSascha Wildner 		if (n > 1000) {
95412bd3c8bSSascha Wildner 			n = 0;
95512bd3c8bSSascha Wildner 			break;
95612bd3c8bSSascha Wildner 		}
95712bd3c8bSSascha Wildner 	}
95812bd3c8bSSascha Wildner 
95912bd3c8bSSascha Wildner 	/* clear port reset first */
96012bd3c8bSSascha Wildner 	err = usbd_req_clear_port_feature(
961722d05c3SSascha Wildner 	    udev, lock, port, UHF_C_BH_PORT_RESET);
96212bd3c8bSSascha Wildner 	if (err)
96312bd3c8bSSascha Wildner 		goto done;
96412bd3c8bSSascha Wildner 
96512bd3c8bSSascha Wildner 	/* check for timeout */
96612bd3c8bSSascha Wildner 	if (n == 0) {
96712bd3c8bSSascha Wildner 		err = USB_ERR_TIMEOUT;
96812bd3c8bSSascha Wildner 		goto done;
96912bd3c8bSSascha Wildner 	}
97012bd3c8bSSascha Wildner 	/* wait for the device to recover from reset */
9715e41ab93SMarkus Pfeiffer 	usb_pause_mtx(lock, USB_MS_TO_TICKS(usb_port_reset_recovery));
97212bd3c8bSSascha Wildner 
97312bd3c8bSSascha Wildner done:
97412bd3c8bSSascha Wildner 	DPRINTFN(2, "port %d warm reset returning error=%s\n",
97512bd3c8bSSascha Wildner 	    port, usbd_errstr(err));
97612bd3c8bSSascha Wildner 	return (err);
97712bd3c8bSSascha Wildner }
97812bd3c8bSSascha Wildner 
97912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
98012bd3c8bSSascha Wildner  *	usbd_req_get_desc
98112bd3c8bSSascha Wildner  *
98212bd3c8bSSascha Wildner  * This function can be used to retrieve USB descriptors. It contains
98312bd3c8bSSascha Wildner  * some additional logic like zeroing of missing descriptor bytes and
98412bd3c8bSSascha Wildner  * retrying an USB descriptor in case of failure. The "min_len"
98512bd3c8bSSascha Wildner  * argument specifies the minimum descriptor length. The "max_len"
98612bd3c8bSSascha Wildner  * argument specifies the maximum descriptor length. If the real
98712bd3c8bSSascha Wildner  * descriptor length is less than the minimum length the missing
98812bd3c8bSSascha Wildner  * byte(s) will be zeroed. The type field, the second byte of the USB
98912bd3c8bSSascha Wildner  * descriptor, will get forced to the correct type. If the "actlen"
99012bd3c8bSSascha Wildner  * pointer is non-NULL, the actual length of the transfer will get
99112bd3c8bSSascha Wildner  * stored in the 16-bit unsigned integer which it is pointing to. The
99212bd3c8bSSascha Wildner  * first byte of the descriptor will not get updated. If the "actlen"
99312bd3c8bSSascha Wildner  * pointer is NULL the first byte of the descriptor will get updated
99412bd3c8bSSascha Wildner  * to reflect the actual length instead. If "min_len" is not equal to
99512bd3c8bSSascha Wildner  * "max_len" then this function will try to retrive the beginning of
99612bd3c8bSSascha Wildner  * the descriptor and base the maximum length on the first byte of the
99712bd3c8bSSascha Wildner  * descriptor.
99812bd3c8bSSascha Wildner  *
99912bd3c8bSSascha Wildner  * Returns:
100012bd3c8bSSascha Wildner  *    0: Success
100112bd3c8bSSascha Wildner  * Else: Failure
100212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
100312bd3c8bSSascha Wildner usb_error_t
100412bd3c8bSSascha Wildner usbd_req_get_desc(struct usb_device *udev,
1005722d05c3SSascha Wildner     struct lock *lock, uint16_t *actlen, void *desc,
100612bd3c8bSSascha Wildner     uint16_t min_len, uint16_t max_len,
100712bd3c8bSSascha Wildner     uint16_t id, uint8_t type, uint8_t index,
100812bd3c8bSSascha Wildner     uint8_t retries)
100912bd3c8bSSascha Wildner {
101012bd3c8bSSascha Wildner 	struct usb_device_request req;
101112bd3c8bSSascha Wildner 	uint8_t *buf;
101212bd3c8bSSascha Wildner 	usb_error_t err;
101312bd3c8bSSascha Wildner 
101412bd3c8bSSascha Wildner 	DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n",
101512bd3c8bSSascha Wildner 	    id, type, index, max_len);
101612bd3c8bSSascha Wildner 
101712bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_DEVICE;
101812bd3c8bSSascha Wildner 	req.bRequest = UR_GET_DESCRIPTOR;
101912bd3c8bSSascha Wildner 	USETW2(req.wValue, type, index);
102012bd3c8bSSascha Wildner 	USETW(req.wIndex, id);
102112bd3c8bSSascha Wildner 
1022b86003c4SMarkus Pfeiffer 	while (1) {
1023b86003c4SMarkus Pfeiffer 
102412bd3c8bSSascha Wildner 		if ((min_len < 2) || (max_len < 2)) {
102512bd3c8bSSascha Wildner 			err = USB_ERR_INVAL;
102612bd3c8bSSascha Wildner 			goto done;
102712bd3c8bSSascha Wildner 		}
102812bd3c8bSSascha Wildner 		USETW(req.wLength, min_len);
102912bd3c8bSSascha Wildner 
1030722d05c3SSascha Wildner 		err = usbd_do_request_flags(udev, lock, &req,
1031ccb00b06SMatthew Dillon 		    desc, 0, NULL, 1000 /* ms */);
103212bd3c8bSSascha Wildner 
103312bd3c8bSSascha Wildner 		if (err) {
103412bd3c8bSSascha Wildner 			if (!retries) {
103512bd3c8bSSascha Wildner 				goto done;
103612bd3c8bSSascha Wildner 			}
103712bd3c8bSSascha Wildner 			retries--;
103812bd3c8bSSascha Wildner 
1039722d05c3SSascha Wildner 			usb_pause_mtx(lock, hz / 5);
104012bd3c8bSSascha Wildner 
104112bd3c8bSSascha Wildner 			continue;
104212bd3c8bSSascha Wildner 		}
104312bd3c8bSSascha Wildner 		buf = desc;
104412bd3c8bSSascha Wildner 
104512bd3c8bSSascha Wildner 		if (min_len == max_len) {
104612bd3c8bSSascha Wildner 
104712bd3c8bSSascha Wildner 			/* enforce correct length */
104812bd3c8bSSascha Wildner 			if ((buf[0] > min_len) && (actlen == NULL))
104912bd3c8bSSascha Wildner 				buf[0] = min_len;
105012bd3c8bSSascha Wildner 
105112bd3c8bSSascha Wildner 			/* enforce correct type */
105212bd3c8bSSascha Wildner 			buf[1] = type;
105312bd3c8bSSascha Wildner 
105412bd3c8bSSascha Wildner 			goto done;
105512bd3c8bSSascha Wildner 		}
105612bd3c8bSSascha Wildner 		/* range check */
105712bd3c8bSSascha Wildner 
105812bd3c8bSSascha Wildner 		if (max_len > buf[0]) {
105912bd3c8bSSascha Wildner 			max_len = buf[0];
106012bd3c8bSSascha Wildner 		}
106112bd3c8bSSascha Wildner 		/* zero minimum data */
106212bd3c8bSSascha Wildner 
106312bd3c8bSSascha Wildner 		while (min_len > max_len) {
106412bd3c8bSSascha Wildner 			min_len--;
106512bd3c8bSSascha Wildner 			buf[min_len] = 0;
106612bd3c8bSSascha Wildner 		}
106712bd3c8bSSascha Wildner 
106812bd3c8bSSascha Wildner 		/* set new minimum length */
106912bd3c8bSSascha Wildner 
107012bd3c8bSSascha Wildner 		min_len = max_len;
107112bd3c8bSSascha Wildner 	}
107212bd3c8bSSascha Wildner done:
107312bd3c8bSSascha Wildner 	if (actlen != NULL) {
107412bd3c8bSSascha Wildner 		if (err)
107512bd3c8bSSascha Wildner 			*actlen = 0;
107612bd3c8bSSascha Wildner 		else
107712bd3c8bSSascha Wildner 			*actlen = min_len;
107812bd3c8bSSascha Wildner 	}
107912bd3c8bSSascha Wildner 	return (err);
108012bd3c8bSSascha Wildner }
108112bd3c8bSSascha Wildner 
108212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
108312bd3c8bSSascha Wildner  *	usbd_req_get_string_any
108412bd3c8bSSascha Wildner  *
108512bd3c8bSSascha Wildner  * This function will return the string given by "string_index"
108612bd3c8bSSascha Wildner  * using the first language ID. The maximum length "len" includes
108712bd3c8bSSascha Wildner  * the terminating zero. The "len" argument should be twice as
108812bd3c8bSSascha Wildner  * big pluss 2 bytes, compared with the actual maximum string length !
108912bd3c8bSSascha Wildner  *
109012bd3c8bSSascha Wildner  * Returns:
109112bd3c8bSSascha Wildner  *    0: Success
109212bd3c8bSSascha Wildner  * Else: Failure
109312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
109412bd3c8bSSascha Wildner usb_error_t
1095722d05c3SSascha Wildner usbd_req_get_string_any(struct usb_device *udev, struct lock *lock, char *buf,
109612bd3c8bSSascha Wildner     uint16_t len, uint8_t string_index)
109712bd3c8bSSascha Wildner {
109812bd3c8bSSascha Wildner 	char *s;
109912bd3c8bSSascha Wildner 	uint8_t *temp;
110012bd3c8bSSascha Wildner 	uint16_t i;
110112bd3c8bSSascha Wildner 	uint16_t n;
110212bd3c8bSSascha Wildner 	uint16_t c;
110312bd3c8bSSascha Wildner 	uint8_t swap;
110412bd3c8bSSascha Wildner 	usb_error_t err;
110512bd3c8bSSascha Wildner 
110612bd3c8bSSascha Wildner 	if (len == 0) {
110712bd3c8bSSascha Wildner 		/* should not happen */
110812bd3c8bSSascha Wildner 		return (USB_ERR_NORMAL_COMPLETION);
110912bd3c8bSSascha Wildner 	}
111012bd3c8bSSascha Wildner 	if (string_index == 0) {
111112bd3c8bSSascha Wildner 		/* this is the language table */
111212bd3c8bSSascha Wildner 		buf[0] = 0;
111312bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
111412bd3c8bSSascha Wildner 	}
111512bd3c8bSSascha Wildner 	if (udev->flags.no_strings) {
111612bd3c8bSSascha Wildner 		buf[0] = 0;
111712bd3c8bSSascha Wildner 		return (USB_ERR_STALLED);
111812bd3c8bSSascha Wildner 	}
111912bd3c8bSSascha Wildner 	err = usbd_req_get_string_desc
1120722d05c3SSascha Wildner 	    (udev, lock, buf, len, udev->langid, string_index);
112112bd3c8bSSascha Wildner 	if (err) {
112212bd3c8bSSascha Wildner 		buf[0] = 0;
112312bd3c8bSSascha Wildner 		return (err);
112412bd3c8bSSascha Wildner 	}
112512bd3c8bSSascha Wildner 	temp = (uint8_t *)buf;
112612bd3c8bSSascha Wildner 
112712bd3c8bSSascha Wildner 	if (temp[0] < 2) {
112812bd3c8bSSascha Wildner 		/* string length is too short */
112912bd3c8bSSascha Wildner 		buf[0] = 0;
113012bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
113112bd3c8bSSascha Wildner 	}
113212bd3c8bSSascha Wildner 	/* reserve one byte for terminating zero */
113312bd3c8bSSascha Wildner 	len--;
113412bd3c8bSSascha Wildner 
113512bd3c8bSSascha Wildner 	/* find maximum length */
113612bd3c8bSSascha Wildner 	s = buf;
113712bd3c8bSSascha Wildner 	n = (temp[0] / 2) - 1;
113812bd3c8bSSascha Wildner 	if (n > len) {
113912bd3c8bSSascha Wildner 		n = len;
114012bd3c8bSSascha Wildner 	}
114112bd3c8bSSascha Wildner 	/* skip descriptor header */
114212bd3c8bSSascha Wildner 	temp += 2;
114312bd3c8bSSascha Wildner 
114412bd3c8bSSascha Wildner 	/* reset swap state */
114512bd3c8bSSascha Wildner 	swap = 3;
114612bd3c8bSSascha Wildner 
114712bd3c8bSSascha Wildner 	/* convert and filter */
114812bd3c8bSSascha Wildner 	for (i = 0; (i != n); i++) {
114912bd3c8bSSascha Wildner 		c = UGETW(temp + (2 * i));
115012bd3c8bSSascha Wildner 
115112bd3c8bSSascha Wildner 		/* convert from Unicode, handle buggy strings */
115212bd3c8bSSascha Wildner 		if (((c & 0xff00) == 0) && (swap & 1)) {
115312bd3c8bSSascha Wildner 			/* Little Endian, default */
115412bd3c8bSSascha Wildner 			*s = c;
115512bd3c8bSSascha Wildner 			swap = 1;
115612bd3c8bSSascha Wildner 		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
115712bd3c8bSSascha Wildner 			/* Big Endian */
115812bd3c8bSSascha Wildner 			*s = c >> 8;
115912bd3c8bSSascha Wildner 			swap = 2;
116012bd3c8bSSascha Wildner 		} else {
116112bd3c8bSSascha Wildner 			/* silently skip bad character */
116212bd3c8bSSascha Wildner 			continue;
116312bd3c8bSSascha Wildner 		}
116412bd3c8bSSascha Wildner 
116512bd3c8bSSascha Wildner 		/*
116612bd3c8bSSascha Wildner 		 * Filter by default - We only allow alphanumerical
116712bd3c8bSSascha Wildner 		 * and a few more to avoid any problems with scripts
116812bd3c8bSSascha Wildner 		 * and daemons.
116912bd3c8bSSascha Wildner 		 */
117012bd3c8bSSascha Wildner 		if (isalpha(*s) ||
117112bd3c8bSSascha Wildner 		    isdigit(*s) ||
117212bd3c8bSSascha Wildner 		    *s == '-' ||
117312bd3c8bSSascha Wildner 		    *s == '+' ||
117412bd3c8bSSascha Wildner 		    *s == ' ' ||
117512bd3c8bSSascha Wildner 		    *s == '.' ||
117612bd3c8bSSascha Wildner 		    *s == ',') {
117712bd3c8bSSascha Wildner 			/* allowed */
117812bd3c8bSSascha Wildner 			s++;
117912bd3c8bSSascha Wildner 		}
118012bd3c8bSSascha Wildner 		/* silently skip bad character */
118112bd3c8bSSascha Wildner 	}
118212bd3c8bSSascha Wildner 	*s = 0;				/* zero terminate resulting string */
118312bd3c8bSSascha Wildner 	return (USB_ERR_NORMAL_COMPLETION);
118412bd3c8bSSascha Wildner }
118512bd3c8bSSascha Wildner 
118612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
118712bd3c8bSSascha Wildner  *	usbd_req_get_string_desc
118812bd3c8bSSascha Wildner  *
118912bd3c8bSSascha Wildner  * If you don't know the language ID, consider using
119012bd3c8bSSascha Wildner  * "usbd_req_get_string_any()".
119112bd3c8bSSascha Wildner  *
119212bd3c8bSSascha Wildner  * Returns:
119312bd3c8bSSascha Wildner  *    0: Success
119412bd3c8bSSascha Wildner  * Else: Failure
119512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
119612bd3c8bSSascha Wildner usb_error_t
1197722d05c3SSascha Wildner usbd_req_get_string_desc(struct usb_device *udev, struct lock *lock, void *sdesc,
119812bd3c8bSSascha Wildner     uint16_t max_len, uint16_t lang_id,
119912bd3c8bSSascha Wildner     uint8_t string_index)
120012bd3c8bSSascha Wildner {
1201722d05c3SSascha Wildner 	return (usbd_req_get_desc(udev, lock, NULL, sdesc, 2, max_len, lang_id,
120212bd3c8bSSascha Wildner 	    UDESC_STRING, string_index, 0));
120312bd3c8bSSascha Wildner }
120412bd3c8bSSascha Wildner 
120512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
120612bd3c8bSSascha Wildner  *	usbd_req_get_config_desc_ptr
120712bd3c8bSSascha Wildner  *
120812bd3c8bSSascha Wildner  * This function is used in device side mode to retrieve the pointer
120912bd3c8bSSascha Wildner  * to the generated config descriptor. This saves allocating space for
121012bd3c8bSSascha Wildner  * an additional config descriptor when setting the configuration.
121112bd3c8bSSascha Wildner  *
121212bd3c8bSSascha Wildner  * Returns:
121312bd3c8bSSascha Wildner  *    0: Success
121412bd3c8bSSascha Wildner  * Else: Failure
121512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
121612bd3c8bSSascha Wildner usb_error_t
121712bd3c8bSSascha Wildner usbd_req_get_descriptor_ptr(struct usb_device *udev,
121812bd3c8bSSascha Wildner     struct usb_config_descriptor **ppcd, uint16_t wValue)
121912bd3c8bSSascha Wildner {
122012bd3c8bSSascha Wildner 	struct usb_device_request req;
122112bd3c8bSSascha Wildner 	usb_handle_req_t *hr_func;
122212bd3c8bSSascha Wildner 	const void *ptr;
122312bd3c8bSSascha Wildner 	uint16_t len;
122412bd3c8bSSascha Wildner 	usb_error_t err;
122512bd3c8bSSascha Wildner 
1226fe8b458aSMatthew Dillon 	if (udev->flags.uq_delay_init) {
1227fe8b458aSMatthew Dillon 		usb_pause_mtx(NULL, 200 * hz / 1000 + 1);
1228fe8b458aSMatthew Dillon 	}
1229fe8b458aSMatthew Dillon 
123012bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_DEVICE;
123112bd3c8bSSascha Wildner 	req.bRequest = UR_GET_DESCRIPTOR;
123212bd3c8bSSascha Wildner 	USETW(req.wValue, wValue);
123312bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
123412bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
123512bd3c8bSSascha Wildner 
123612bd3c8bSSascha Wildner 	ptr = NULL;
123712bd3c8bSSascha Wildner 	len = 0;
123812bd3c8bSSascha Wildner 
123912bd3c8bSSascha Wildner 	hr_func = usbd_get_hr_func(udev);
124012bd3c8bSSascha Wildner 
124112bd3c8bSSascha Wildner 	if (hr_func == NULL)
124212bd3c8bSSascha Wildner 		err = USB_ERR_INVAL;
124312bd3c8bSSascha Wildner 	else {
124412bd3c8bSSascha Wildner 		USB_BUS_LOCK(udev->bus);
124512bd3c8bSSascha Wildner 		err = (hr_func) (udev, &req, &ptr, &len);
124612bd3c8bSSascha Wildner 		USB_BUS_UNLOCK(udev->bus);
124712bd3c8bSSascha Wildner 	}
124812bd3c8bSSascha Wildner 
124912bd3c8bSSascha Wildner 	if (err)
125012bd3c8bSSascha Wildner 		ptr = NULL;
125112bd3c8bSSascha Wildner 	else if (ptr == NULL)
125212bd3c8bSSascha Wildner 		err = USB_ERR_INVAL;
125312bd3c8bSSascha Wildner 
125412bd3c8bSSascha Wildner 	*ppcd = __DECONST(struct usb_config_descriptor *, ptr);
125512bd3c8bSSascha Wildner 
125612bd3c8bSSascha Wildner 	return (err);
125712bd3c8bSSascha Wildner }
125812bd3c8bSSascha Wildner 
125912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
126012bd3c8bSSascha Wildner  *	usbd_req_get_config_desc
126112bd3c8bSSascha Wildner  *
126212bd3c8bSSascha Wildner  * Returns:
126312bd3c8bSSascha Wildner  *    0: Success
126412bd3c8bSSascha Wildner  * Else: Failure
126512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
126612bd3c8bSSascha Wildner usb_error_t
1267722d05c3SSascha Wildner usbd_req_get_config_desc(struct usb_device *udev, struct lock *lock,
126812bd3c8bSSascha Wildner     struct usb_config_descriptor *d, uint8_t conf_index)
126912bd3c8bSSascha Wildner {
127012bd3c8bSSascha Wildner 	usb_error_t err;
127112bd3c8bSSascha Wildner 
127212bd3c8bSSascha Wildner 	DPRINTFN(4, "confidx=%d\n", conf_index);
127312bd3c8bSSascha Wildner 
1274722d05c3SSascha Wildner 	err = usbd_req_get_desc(udev, lock, NULL, d, sizeof(*d),
127512bd3c8bSSascha Wildner 	    sizeof(*d), 0, UDESC_CONFIG, conf_index, 0);
127612bd3c8bSSascha Wildner 	if (err) {
127712bd3c8bSSascha Wildner 		goto done;
127812bd3c8bSSascha Wildner 	}
127912bd3c8bSSascha Wildner 	/* Extra sanity checking */
12805e41ab93SMarkus Pfeiffer 	if (UGETW(d->wTotalLength) < (uint16_t)sizeof(*d)) {
128112bd3c8bSSascha Wildner 		err = USB_ERR_INVAL;
128212bd3c8bSSascha Wildner 	}
128312bd3c8bSSascha Wildner done:
128412bd3c8bSSascha Wildner 	return (err);
128512bd3c8bSSascha Wildner }
128612bd3c8bSSascha Wildner 
128712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
128857bed822SMarkus Pfeiffer  *	usbd_alloc_config_desc
128957bed822SMarkus Pfeiffer  *
129057bed822SMarkus Pfeiffer  * This function is used to allocate a zeroed configuration
129157bed822SMarkus Pfeiffer  * descriptor.
129257bed822SMarkus Pfeiffer  *
129357bed822SMarkus Pfeiffer  * Returns:
129457bed822SMarkus Pfeiffer  * NULL: Failure
129557bed822SMarkus Pfeiffer  * Else: Success
129657bed822SMarkus Pfeiffer  *------------------------------------------------------------------------*/
129757bed822SMarkus Pfeiffer void *
129857bed822SMarkus Pfeiffer usbd_alloc_config_desc(struct usb_device *udev, uint32_t size)
129957bed822SMarkus Pfeiffer {
130057bed822SMarkus Pfeiffer 	if (size > USB_CONFIG_MAX) {
130157bed822SMarkus Pfeiffer 		DPRINTF("Configuration descriptor too big\n");
130257bed822SMarkus Pfeiffer 		return (NULL);
130357bed822SMarkus Pfeiffer 	}
130457bed822SMarkus Pfeiffer #if (USB_HAVE_FIXED_CONFIG == 0)
130557bed822SMarkus Pfeiffer 	return (kmalloc(size, M_USBDEV, M_ZERO | M_WAITOK));
130657bed822SMarkus Pfeiffer #else
130757bed822SMarkus Pfeiffer 	memset(udev->config_data, 0, sizeof(udev->config_data));
130857bed822SMarkus Pfeiffer 	return (udev->config_data);
130957bed822SMarkus Pfeiffer #endif
131057bed822SMarkus Pfeiffer }
131157bed822SMarkus Pfeiffer 
131257bed822SMarkus Pfeiffer /*------------------------------------------------------------------------*
131357bed822SMarkus Pfeiffer  *	usbd_alloc_config_desc
131457bed822SMarkus Pfeiffer  *
131557bed822SMarkus Pfeiffer  * This function is used to free a configuration descriptor.
131657bed822SMarkus Pfeiffer  *------------------------------------------------------------------------*/
131757bed822SMarkus Pfeiffer void
131857bed822SMarkus Pfeiffer usbd_free_config_desc(struct usb_device *udev, void *ptr)
131957bed822SMarkus Pfeiffer {
132057bed822SMarkus Pfeiffer #if (USB_HAVE_FIXED_CONFIG == 0)
132157bed822SMarkus Pfeiffer 	if(ptr) {
132257bed822SMarkus Pfeiffer 		kfree(ptr, M_USBDEV);
132357bed822SMarkus Pfeiffer 	} else {
132457bed822SMarkus Pfeiffer 		kprintf("usbd_free_config_desc: nullpointer\n");
132557bed822SMarkus Pfeiffer 	}
132657bed822SMarkus Pfeiffer #endif
132757bed822SMarkus Pfeiffer }
132857bed822SMarkus Pfeiffer 
132957bed822SMarkus Pfeiffer /*------------------------------------------------------------------------*
133012bd3c8bSSascha Wildner  *	usbd_req_get_config_desc_full
133112bd3c8bSSascha Wildner  *
133212bd3c8bSSascha Wildner  * This function gets the complete USB configuration descriptor and
133357bed822SMarkus Pfeiffer  * ensures that "wTotalLength" is correct. The returned configuration
133457bed822SMarkus Pfeiffer  * descriptor is freed by calling "usbd_free_config_desc()".
133512bd3c8bSSascha Wildner  *
133612bd3c8bSSascha Wildner  * Returns:
133712bd3c8bSSascha Wildner  *    0: Success
133812bd3c8bSSascha Wildner  * Else: Failure
133912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
134012bd3c8bSSascha Wildner usb_error_t
1341722d05c3SSascha Wildner usbd_req_get_config_desc_full(struct usb_device *udev, struct lock *lock,
134257bed822SMarkus Pfeiffer     struct usb_config_descriptor **ppcd, uint8_t index)
134312bd3c8bSSascha Wildner {
134412bd3c8bSSascha Wildner 	struct usb_config_descriptor cd;
134512bd3c8bSSascha Wildner 	struct usb_config_descriptor *cdesc;
134657bed822SMarkus Pfeiffer 	uint32_t len;
134712bd3c8bSSascha Wildner 	usb_error_t err;
134812bd3c8bSSascha Wildner 
134912bd3c8bSSascha Wildner 	DPRINTFN(4, "index=%d\n", index);
135012bd3c8bSSascha Wildner 
135112bd3c8bSSascha Wildner 	*ppcd = NULL;
135212bd3c8bSSascha Wildner 
1353722d05c3SSascha Wildner 	err = usbd_req_get_config_desc(udev, lock, &cd, index);
135412bd3c8bSSascha Wildner 	if (err) {
135512bd3c8bSSascha Wildner 		return (err);
135612bd3c8bSSascha Wildner 	}
135712bd3c8bSSascha Wildner 	/* get full descriptor */
135812bd3c8bSSascha Wildner 	len = UGETW(cd.wTotalLength);
135957bed822SMarkus Pfeiffer 	if (len < (uint32_t)sizeof(*cdesc)) {
136012bd3c8bSSascha Wildner 		/* corrupt descriptor */
136112bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
136257bed822SMarkus Pfeiffer 	} else if (len > USB_CONFIG_MAX) {
136357bed822SMarkus Pfeiffer 		DPRINTF("Configuration descriptor was truncated\n");
136457bed822SMarkus Pfeiffer 		len = USB_CONFIG_MAX;
136512bd3c8bSSascha Wildner 	}
136657bed822SMarkus Pfeiffer 	cdesc = usbd_alloc_config_desc(udev, len);
136757bed822SMarkus Pfeiffer 	if (cdesc == NULL)
136857bed822SMarkus Pfeiffer 		return (USB_ERR_NOMEM);
1369722d05c3SSascha Wildner 	err = usbd_req_get_desc(udev, lock, NULL, cdesc, len, len, 0,
137012bd3c8bSSascha Wildner 	    UDESC_CONFIG, index, 3);
137112bd3c8bSSascha Wildner 	if (err) {
137257bed822SMarkus Pfeiffer 		usbd_free_config_desc(udev, cdesc);
137312bd3c8bSSascha Wildner 		return (err);
137412bd3c8bSSascha Wildner 	}
137512bd3c8bSSascha Wildner 	/* make sure that the device is not fooling us: */
137612bd3c8bSSascha Wildner 	USETW(cdesc->wTotalLength, len);
137712bd3c8bSSascha Wildner 
137812bd3c8bSSascha Wildner 	*ppcd = cdesc;
137912bd3c8bSSascha Wildner 
138012bd3c8bSSascha Wildner 	return (0);			/* success */
138112bd3c8bSSascha Wildner }
138212bd3c8bSSascha Wildner 
138312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
138412bd3c8bSSascha Wildner  *	usbd_req_get_device_desc
138512bd3c8bSSascha Wildner  *
138612bd3c8bSSascha Wildner  * Returns:
138712bd3c8bSSascha Wildner  *    0: Success
138812bd3c8bSSascha Wildner  * Else: Failure
138912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
139012bd3c8bSSascha Wildner usb_error_t
1391722d05c3SSascha Wildner usbd_req_get_device_desc(struct usb_device *udev, struct lock *lock,
139212bd3c8bSSascha Wildner     struct usb_device_descriptor *d)
139312bd3c8bSSascha Wildner {
139412bd3c8bSSascha Wildner 	DPRINTFN(4, "\n");
1395722d05c3SSascha Wildner 	return (usbd_req_get_desc(udev, lock, NULL, d, sizeof(*d),
139612bd3c8bSSascha Wildner 	    sizeof(*d), 0, UDESC_DEVICE, 0, 3));
139712bd3c8bSSascha Wildner }
139812bd3c8bSSascha Wildner 
139912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
140012bd3c8bSSascha Wildner  *	usbd_req_get_alt_interface_no
140112bd3c8bSSascha Wildner  *
140212bd3c8bSSascha Wildner  * Returns:
140312bd3c8bSSascha Wildner  *    0: Success
140412bd3c8bSSascha Wildner  * Else: Failure
140512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
140612bd3c8bSSascha Wildner usb_error_t
1407722d05c3SSascha Wildner usbd_req_get_alt_interface_no(struct usb_device *udev, struct lock *lock,
140812bd3c8bSSascha Wildner     uint8_t *alt_iface_no, uint8_t iface_index)
140912bd3c8bSSascha Wildner {
141012bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
141112bd3c8bSSascha Wildner 	struct usb_device_request req;
141212bd3c8bSSascha Wildner 
141312bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL))
141412bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
141512bd3c8bSSascha Wildner 
141612bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_INTERFACE;
141712bd3c8bSSascha Wildner 	req.bRequest = UR_GET_INTERFACE;
141812bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
141912bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
142012bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
142112bd3c8bSSascha Wildner 	USETW(req.wLength, 1);
1422722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, alt_iface_no));
142312bd3c8bSSascha Wildner }
142412bd3c8bSSascha Wildner 
142512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
142612bd3c8bSSascha Wildner  *	usbd_req_set_alt_interface_no
142712bd3c8bSSascha Wildner  *
142812bd3c8bSSascha Wildner  * Returns:
142912bd3c8bSSascha Wildner  *    0: Success
143012bd3c8bSSascha Wildner  * Else: Failure
143112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
143212bd3c8bSSascha Wildner usb_error_t
1433722d05c3SSascha Wildner usbd_req_set_alt_interface_no(struct usb_device *udev, struct lock *lock,
143412bd3c8bSSascha Wildner     uint8_t iface_index, uint8_t alt_no)
143512bd3c8bSSascha Wildner {
143612bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
143712bd3c8bSSascha Wildner 	struct usb_device_request req;
143812bd3c8bSSascha Wildner 
143912bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL))
144012bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
144112bd3c8bSSascha Wildner 
144212bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_INTERFACE;
144312bd3c8bSSascha Wildner 	req.bRequest = UR_SET_INTERFACE;
144412bd3c8bSSascha Wildner 	req.wValue[0] = alt_no;
144512bd3c8bSSascha Wildner 	req.wValue[1] = 0;
144612bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
144712bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
144812bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1449722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
145012bd3c8bSSascha Wildner }
145112bd3c8bSSascha Wildner 
145212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
145312bd3c8bSSascha Wildner  *	usbd_req_get_device_status
145412bd3c8bSSascha Wildner  *
145512bd3c8bSSascha Wildner  * Returns:
145612bd3c8bSSascha Wildner  *    0: Success
145712bd3c8bSSascha Wildner  * Else: Failure
145812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
145912bd3c8bSSascha Wildner usb_error_t
1460722d05c3SSascha Wildner usbd_req_get_device_status(struct usb_device *udev, struct lock *lock,
146112bd3c8bSSascha Wildner     struct usb_status *st)
146212bd3c8bSSascha Wildner {
146312bd3c8bSSascha Wildner 	struct usb_device_request req;
146412bd3c8bSSascha Wildner 
146512bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_DEVICE;
146612bd3c8bSSascha Wildner 	req.bRequest = UR_GET_STATUS;
146712bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
146812bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
146912bd3c8bSSascha Wildner 	USETW(req.wLength, sizeof(*st));
1470722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, st));
147112bd3c8bSSascha Wildner }
147212bd3c8bSSascha Wildner 
147312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
147412bd3c8bSSascha Wildner  *	usbd_req_get_hub_descriptor
147512bd3c8bSSascha Wildner  *
147612bd3c8bSSascha Wildner  * Returns:
147712bd3c8bSSascha Wildner  *    0: Success
147812bd3c8bSSascha Wildner  * Else: Failure
147912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
148012bd3c8bSSascha Wildner usb_error_t
1481722d05c3SSascha Wildner usbd_req_get_hub_descriptor(struct usb_device *udev, struct lock *lock,
148212bd3c8bSSascha Wildner     struct usb_hub_descriptor *hd, uint8_t nports)
148312bd3c8bSSascha Wildner {
148412bd3c8bSSascha Wildner 	struct usb_device_request req;
148512bd3c8bSSascha Wildner 	uint16_t len = (nports + 7 + (8 * 8)) / 8;
148612bd3c8bSSascha Wildner 
148712bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_CLASS_DEVICE;
148812bd3c8bSSascha Wildner 	req.bRequest = UR_GET_DESCRIPTOR;
148912bd3c8bSSascha Wildner 	USETW2(req.wValue, UDESC_HUB, 0);
149012bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
149112bd3c8bSSascha Wildner 	USETW(req.wLength, len);
1492722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, hd));
149312bd3c8bSSascha Wildner }
149412bd3c8bSSascha Wildner 
149512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
149612bd3c8bSSascha Wildner  *	usbd_req_get_ss_hub_descriptor
149712bd3c8bSSascha Wildner  *
149812bd3c8bSSascha Wildner  * Returns:
149912bd3c8bSSascha Wildner  *    0: Success
150012bd3c8bSSascha Wildner  * Else: Failure
150112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
150212bd3c8bSSascha Wildner usb_error_t
1503722d05c3SSascha Wildner usbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct lock *lock,
150412bd3c8bSSascha Wildner     struct usb_hub_ss_descriptor *hd, uint8_t nports)
150512bd3c8bSSascha Wildner {
150612bd3c8bSSascha Wildner 	struct usb_device_request req;
150712bd3c8bSSascha Wildner 	uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8);
150812bd3c8bSSascha Wildner 
150912bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_CLASS_DEVICE;
151012bd3c8bSSascha Wildner 	req.bRequest = UR_GET_DESCRIPTOR;
151112bd3c8bSSascha Wildner 	USETW2(req.wValue, UDESC_SS_HUB, 0);
151212bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
151312bd3c8bSSascha Wildner 	USETW(req.wLength, len);
1514722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, hd));
151512bd3c8bSSascha Wildner }
151612bd3c8bSSascha Wildner 
151712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
151812bd3c8bSSascha Wildner  *	usbd_req_get_hub_status
151912bd3c8bSSascha Wildner  *
152012bd3c8bSSascha Wildner  * Returns:
152112bd3c8bSSascha Wildner  *    0: Success
152212bd3c8bSSascha Wildner  * Else: Failure
152312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
152412bd3c8bSSascha Wildner usb_error_t
1525722d05c3SSascha Wildner usbd_req_get_hub_status(struct usb_device *udev, struct lock *lock,
152612bd3c8bSSascha Wildner     struct usb_hub_status *st)
152712bd3c8bSSascha Wildner {
152812bd3c8bSSascha Wildner 	struct usb_device_request req;
152912bd3c8bSSascha Wildner 
153012bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_CLASS_DEVICE;
153112bd3c8bSSascha Wildner 	req.bRequest = UR_GET_STATUS;
153212bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
153312bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
153412bd3c8bSSascha Wildner 	USETW(req.wLength, sizeof(struct usb_hub_status));
1535722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, st));
153612bd3c8bSSascha Wildner }
153712bd3c8bSSascha Wildner 
153812bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
153912bd3c8bSSascha Wildner  *	usbd_req_set_address
154012bd3c8bSSascha Wildner  *
154112bd3c8bSSascha Wildner  * This function is used to set the address for an USB device. After
154212bd3c8bSSascha Wildner  * port reset the USB device will respond at address zero.
154312bd3c8bSSascha Wildner  *
154412bd3c8bSSascha Wildner  * Returns:
154512bd3c8bSSascha Wildner  *    0: Success
154612bd3c8bSSascha Wildner  * Else: Failure
154712bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
154812bd3c8bSSascha Wildner usb_error_t
1549722d05c3SSascha Wildner usbd_req_set_address(struct usb_device *udev, struct lock *lock, uint16_t addr)
155012bd3c8bSSascha Wildner {
155112bd3c8bSSascha Wildner 	struct usb_device_request req;
155212bd3c8bSSascha Wildner 	usb_error_t err;
155312bd3c8bSSascha Wildner 
155412bd3c8bSSascha Wildner 	DPRINTFN(6, "setting device address=%d\n", addr);
155512bd3c8bSSascha Wildner 
155612bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_DEVICE;
155712bd3c8bSSascha Wildner 	req.bRequest = UR_SET_ADDRESS;
155812bd3c8bSSascha Wildner 	USETW(req.wValue, addr);
155912bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
156012bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
156112bd3c8bSSascha Wildner 
156212bd3c8bSSascha Wildner 	err = USB_ERR_INVAL;
156312bd3c8bSSascha Wildner 
156412bd3c8bSSascha Wildner 	/* check if USB controller handles set address */
156512bd3c8bSSascha Wildner 	if (udev->bus->methods->set_address != NULL)
1566722d05c3SSascha Wildner 		err = (udev->bus->methods->set_address) (udev, lock, addr);
156712bd3c8bSSascha Wildner 
156812bd3c8bSSascha Wildner 	if (err != USB_ERR_INVAL)
156912bd3c8bSSascha Wildner 		goto done;
157012bd3c8bSSascha Wildner 
157112bd3c8bSSascha Wildner 	/* Setting the address should not take more than 1 second ! */
1572722d05c3SSascha Wildner 	err = usbd_do_request_flags(udev, lock, &req, NULL,
157312bd3c8bSSascha Wildner 	    USB_DELAY_STATUS_STAGE, NULL, 1000);
157412bd3c8bSSascha Wildner 
157512bd3c8bSSascha Wildner done:
157612bd3c8bSSascha Wildner 	/* allow device time to set new address */
1577722d05c3SSascha Wildner 	usb_pause_mtx(lock,
15785e41ab93SMarkus Pfeiffer 	    USB_MS_TO_TICKS(usb_set_address_settle));
157912bd3c8bSSascha Wildner 
158012bd3c8bSSascha Wildner 	return (err);
158112bd3c8bSSascha Wildner }
158212bd3c8bSSascha Wildner 
158312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
158412bd3c8bSSascha Wildner  *	usbd_req_get_port_status
158512bd3c8bSSascha Wildner  *
158612bd3c8bSSascha Wildner  * Returns:
158712bd3c8bSSascha Wildner  *    0: Success
158812bd3c8bSSascha Wildner  * Else: Failure
158912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
159012bd3c8bSSascha Wildner usb_error_t
1591722d05c3SSascha Wildner usbd_req_get_port_status(struct usb_device *udev, struct lock *lock,
159212bd3c8bSSascha Wildner     struct usb_port_status *ps, uint8_t port)
159312bd3c8bSSascha Wildner {
159412bd3c8bSSascha Wildner 	struct usb_device_request req;
159512bd3c8bSSascha Wildner 
159612bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_CLASS_OTHER;
159712bd3c8bSSascha Wildner 	req.bRequest = UR_GET_STATUS;
159812bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
159912bd3c8bSSascha Wildner 	req.wIndex[0] = port;
160012bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
160112bd3c8bSSascha Wildner 	USETW(req.wLength, sizeof *ps);
1602722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, ps));
160312bd3c8bSSascha Wildner }
160412bd3c8bSSascha Wildner 
160512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
160612bd3c8bSSascha Wildner  *	usbd_req_clear_hub_feature
160712bd3c8bSSascha Wildner  *
160812bd3c8bSSascha Wildner  * Returns:
160912bd3c8bSSascha Wildner  *    0: Success
161012bd3c8bSSascha Wildner  * Else: Failure
161112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
161212bd3c8bSSascha Wildner usb_error_t
1613722d05c3SSascha Wildner usbd_req_clear_hub_feature(struct usb_device *udev, struct lock *lock,
161412bd3c8bSSascha Wildner     uint16_t sel)
161512bd3c8bSSascha Wildner {
161612bd3c8bSSascha Wildner 	struct usb_device_request req;
161712bd3c8bSSascha Wildner 
161812bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
161912bd3c8bSSascha Wildner 	req.bRequest = UR_CLEAR_FEATURE;
162012bd3c8bSSascha Wildner 	USETW(req.wValue, sel);
162112bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
162212bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1623722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
162412bd3c8bSSascha Wildner }
162512bd3c8bSSascha Wildner 
162612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
162712bd3c8bSSascha Wildner  *	usbd_req_set_hub_feature
162812bd3c8bSSascha Wildner  *
162912bd3c8bSSascha Wildner  * Returns:
163012bd3c8bSSascha Wildner  *    0: Success
163112bd3c8bSSascha Wildner  * Else: Failure
163212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
163312bd3c8bSSascha Wildner usb_error_t
1634722d05c3SSascha Wildner usbd_req_set_hub_feature(struct usb_device *udev, struct lock *lock,
163512bd3c8bSSascha Wildner     uint16_t sel)
163612bd3c8bSSascha Wildner {
163712bd3c8bSSascha Wildner 	struct usb_device_request req;
163812bd3c8bSSascha Wildner 
163912bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
164012bd3c8bSSascha Wildner 	req.bRequest = UR_SET_FEATURE;
164112bd3c8bSSascha Wildner 	USETW(req.wValue, sel);
164212bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
164312bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1644722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
164512bd3c8bSSascha Wildner }
164612bd3c8bSSascha Wildner 
164712bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
164812bd3c8bSSascha Wildner  *	usbd_req_set_hub_u1_timeout
164912bd3c8bSSascha Wildner  *
165012bd3c8bSSascha Wildner  * Returns:
165112bd3c8bSSascha Wildner  *    0: Success
165212bd3c8bSSascha Wildner  * Else: Failure
165312bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
165412bd3c8bSSascha Wildner usb_error_t
1655722d05c3SSascha Wildner usbd_req_set_hub_u1_timeout(struct usb_device *udev, struct lock *lock,
165612bd3c8bSSascha Wildner     uint8_t port, uint8_t timeout)
165712bd3c8bSSascha Wildner {
165812bd3c8bSSascha Wildner 	struct usb_device_request req;
165912bd3c8bSSascha Wildner 
166012bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
166112bd3c8bSSascha Wildner 	req.bRequest = UR_SET_FEATURE;
166212bd3c8bSSascha Wildner 	USETW(req.wValue, UHF_PORT_U1_TIMEOUT);
166312bd3c8bSSascha Wildner 	req.wIndex[0] = port;
166412bd3c8bSSascha Wildner 	req.wIndex[1] = timeout;
166512bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1666722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
166712bd3c8bSSascha Wildner }
166812bd3c8bSSascha Wildner 
166912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
167012bd3c8bSSascha Wildner  *	usbd_req_set_hub_u2_timeout
167112bd3c8bSSascha Wildner  *
167212bd3c8bSSascha Wildner  * Returns:
167312bd3c8bSSascha Wildner  *    0: Success
167412bd3c8bSSascha Wildner  * Else: Failure
167512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
167612bd3c8bSSascha Wildner usb_error_t
1677722d05c3SSascha Wildner usbd_req_set_hub_u2_timeout(struct usb_device *udev, struct lock *lock,
167812bd3c8bSSascha Wildner     uint8_t port, uint8_t timeout)
167912bd3c8bSSascha Wildner {
168012bd3c8bSSascha Wildner 	struct usb_device_request req;
168112bd3c8bSSascha Wildner 
168212bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
168312bd3c8bSSascha Wildner 	req.bRequest = UR_SET_FEATURE;
168412bd3c8bSSascha Wildner 	USETW(req.wValue, UHF_PORT_U2_TIMEOUT);
168512bd3c8bSSascha Wildner 	req.wIndex[0] = port;
168612bd3c8bSSascha Wildner 	req.wIndex[1] = timeout;
168712bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1688722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
168912bd3c8bSSascha Wildner }
169012bd3c8bSSascha Wildner 
169112bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
169212bd3c8bSSascha Wildner  *	usbd_req_set_hub_depth
169312bd3c8bSSascha Wildner  *
169412bd3c8bSSascha Wildner  * Returns:
169512bd3c8bSSascha Wildner  *    0: Success
169612bd3c8bSSascha Wildner  * Else: Failure
169712bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
169812bd3c8bSSascha Wildner usb_error_t
1699722d05c3SSascha Wildner usbd_req_set_hub_depth(struct usb_device *udev, struct lock *lock,
170012bd3c8bSSascha Wildner     uint16_t depth)
170112bd3c8bSSascha Wildner {
170212bd3c8bSSascha Wildner 	struct usb_device_request req;
170312bd3c8bSSascha Wildner 
170412bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
170512bd3c8bSSascha Wildner 	req.bRequest = UR_SET_HUB_DEPTH;
170612bd3c8bSSascha Wildner 	USETW(req.wValue, depth);
170712bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
170812bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1709722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
171012bd3c8bSSascha Wildner }
171112bd3c8bSSascha Wildner 
171212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
171312bd3c8bSSascha Wildner  *	usbd_req_clear_port_feature
171412bd3c8bSSascha Wildner  *
171512bd3c8bSSascha Wildner  * Returns:
171612bd3c8bSSascha Wildner  *    0: Success
171712bd3c8bSSascha Wildner  * Else: Failure
171812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
171912bd3c8bSSascha Wildner usb_error_t
1720722d05c3SSascha Wildner usbd_req_clear_port_feature(struct usb_device *udev, struct lock *lock,
172112bd3c8bSSascha Wildner     uint8_t port, uint16_t sel)
172212bd3c8bSSascha Wildner {
172312bd3c8bSSascha Wildner 	struct usb_device_request req;
172412bd3c8bSSascha Wildner 
172512bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
172612bd3c8bSSascha Wildner 	req.bRequest = UR_CLEAR_FEATURE;
172712bd3c8bSSascha Wildner 	USETW(req.wValue, sel);
172812bd3c8bSSascha Wildner 	req.wIndex[0] = port;
172912bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
173012bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1731722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
173212bd3c8bSSascha Wildner }
173312bd3c8bSSascha Wildner 
173412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
173512bd3c8bSSascha Wildner  *	usbd_req_set_port_feature
173612bd3c8bSSascha Wildner  *
173712bd3c8bSSascha Wildner  * Returns:
173812bd3c8bSSascha Wildner  *    0: Success
173912bd3c8bSSascha Wildner  * Else: Failure
174012bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
174112bd3c8bSSascha Wildner usb_error_t
1742722d05c3SSascha Wildner usbd_req_set_port_feature(struct usb_device *udev, struct lock *lock,
174312bd3c8bSSascha Wildner     uint8_t port, uint16_t sel)
174412bd3c8bSSascha Wildner {
174512bd3c8bSSascha Wildner 	struct usb_device_request req;
174612bd3c8bSSascha Wildner 
174712bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
174812bd3c8bSSascha Wildner 	req.bRequest = UR_SET_FEATURE;
174912bd3c8bSSascha Wildner 	USETW(req.wValue, sel);
175012bd3c8bSSascha Wildner 	req.wIndex[0] = port;
175112bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
175212bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1753722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
175412bd3c8bSSascha Wildner }
175512bd3c8bSSascha Wildner 
175612bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
175712bd3c8bSSascha Wildner  *	usbd_req_set_protocol
175812bd3c8bSSascha Wildner  *
175912bd3c8bSSascha Wildner  * Returns:
176012bd3c8bSSascha Wildner  *    0: Success
176112bd3c8bSSascha Wildner  * Else: Failure
176212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
176312bd3c8bSSascha Wildner usb_error_t
1764722d05c3SSascha Wildner usbd_req_set_protocol(struct usb_device *udev, struct lock *lock,
176512bd3c8bSSascha Wildner     uint8_t iface_index, uint16_t report)
176612bd3c8bSSascha Wildner {
176712bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
176812bd3c8bSSascha Wildner 	struct usb_device_request req;
176912bd3c8bSSascha Wildner 
177012bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL)) {
177112bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
177212bd3c8bSSascha Wildner 	}
177312bd3c8bSSascha Wildner 	DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n",
177412bd3c8bSSascha Wildner 	    iface, report, iface->idesc->bInterfaceNumber);
177512bd3c8bSSascha Wildner 
177612bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
177712bd3c8bSSascha Wildner 	req.bRequest = UR_SET_PROTOCOL;
177812bd3c8bSSascha Wildner 	USETW(req.wValue, report);
177912bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
178012bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
178112bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1782722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
178312bd3c8bSSascha Wildner }
178412bd3c8bSSascha Wildner 
178512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
178612bd3c8bSSascha Wildner  *	usbd_req_set_report
178712bd3c8bSSascha Wildner  *
178812bd3c8bSSascha Wildner  * Returns:
178912bd3c8bSSascha Wildner  *    0: Success
179012bd3c8bSSascha Wildner  * Else: Failure
179112bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
179212bd3c8bSSascha Wildner usb_error_t
1793722d05c3SSascha Wildner usbd_req_set_report(struct usb_device *udev, struct lock *lock, void *data, uint16_t len,
179412bd3c8bSSascha Wildner     uint8_t iface_index, uint8_t type, uint8_t id)
179512bd3c8bSSascha Wildner {
179612bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
179712bd3c8bSSascha Wildner 	struct usb_device_request req;
179812bd3c8bSSascha Wildner 
179912bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL)) {
180012bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
180112bd3c8bSSascha Wildner 	}
180212bd3c8bSSascha Wildner 	DPRINTFN(5, "len=%d\n", len);
180312bd3c8bSSascha Wildner 
180412bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
180512bd3c8bSSascha Wildner 	req.bRequest = UR_SET_REPORT;
180612bd3c8bSSascha Wildner 	USETW2(req.wValue, type, id);
180712bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
180812bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
180912bd3c8bSSascha Wildner 	USETW(req.wLength, len);
1810722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, data));
181112bd3c8bSSascha Wildner }
181212bd3c8bSSascha Wildner 
181312bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
181412bd3c8bSSascha Wildner  *	usbd_req_get_report
181512bd3c8bSSascha Wildner  *
181612bd3c8bSSascha Wildner  * Returns:
181712bd3c8bSSascha Wildner  *    0: Success
181812bd3c8bSSascha Wildner  * Else: Failure
181912bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
182012bd3c8bSSascha Wildner usb_error_t
1821722d05c3SSascha Wildner usbd_req_get_report(struct usb_device *udev, struct lock *lock, void *data,
182212bd3c8bSSascha Wildner     uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
182312bd3c8bSSascha Wildner {
182412bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
182512bd3c8bSSascha Wildner 	struct usb_device_request req;
182612bd3c8bSSascha Wildner 
182712bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL)) {
182812bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
182912bd3c8bSSascha Wildner 	}
183012bd3c8bSSascha Wildner 	DPRINTFN(5, "len=%d\n", len);
183112bd3c8bSSascha Wildner 
183212bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_CLASS_INTERFACE;
183312bd3c8bSSascha Wildner 	req.bRequest = UR_GET_REPORT;
183412bd3c8bSSascha Wildner 	USETW2(req.wValue, type, id);
183512bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
183612bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
183712bd3c8bSSascha Wildner 	USETW(req.wLength, len);
1838722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, data));
183912bd3c8bSSascha Wildner }
184012bd3c8bSSascha Wildner 
184112bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
184212bd3c8bSSascha Wildner  *	usbd_req_set_idle
184312bd3c8bSSascha Wildner  *
184412bd3c8bSSascha Wildner  * Returns:
184512bd3c8bSSascha Wildner  *    0: Success
184612bd3c8bSSascha Wildner  * Else: Failure
184712bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
184812bd3c8bSSascha Wildner usb_error_t
1849722d05c3SSascha Wildner usbd_req_set_idle(struct usb_device *udev, struct lock *lock,
185012bd3c8bSSascha Wildner     uint8_t iface_index, uint8_t duration, uint8_t id)
185112bd3c8bSSascha Wildner {
185212bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
185312bd3c8bSSascha Wildner 	struct usb_device_request req;
185412bd3c8bSSascha Wildner 
185512bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL)) {
185612bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
185712bd3c8bSSascha Wildner 	}
185812bd3c8bSSascha Wildner 	DPRINTFN(5, "%d %d\n", duration, id);
185912bd3c8bSSascha Wildner 
186012bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
186112bd3c8bSSascha Wildner 	req.bRequest = UR_SET_IDLE;
186212bd3c8bSSascha Wildner 	USETW2(req.wValue, duration, id);
186312bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
186412bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
186512bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1866722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
186712bd3c8bSSascha Wildner }
186812bd3c8bSSascha Wildner 
186912bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
187012bd3c8bSSascha Wildner  *	usbd_req_get_report_descriptor
187112bd3c8bSSascha Wildner  *
187212bd3c8bSSascha Wildner  * Returns:
187312bd3c8bSSascha Wildner  *    0: Success
187412bd3c8bSSascha Wildner  * Else: Failure
187512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
187612bd3c8bSSascha Wildner usb_error_t
1877722d05c3SSascha Wildner usbd_req_get_report_descriptor(struct usb_device *udev, struct lock *lock,
187812bd3c8bSSascha Wildner     void *d, uint16_t size, uint8_t iface_index)
187912bd3c8bSSascha Wildner {
188012bd3c8bSSascha Wildner 	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
188112bd3c8bSSascha Wildner 	struct usb_device_request req;
188212bd3c8bSSascha Wildner 
188312bd3c8bSSascha Wildner 	if ((iface == NULL) || (iface->idesc == NULL)) {
188412bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
188512bd3c8bSSascha Wildner 	}
188612bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_INTERFACE;
188712bd3c8bSSascha Wildner 	req.bRequest = UR_GET_DESCRIPTOR;
188812bd3c8bSSascha Wildner 	USETW2(req.wValue, UDESC_REPORT, 0);	/* report id should be 0 */
188912bd3c8bSSascha Wildner 	req.wIndex[0] = iface->idesc->bInterfaceNumber;
189012bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
189112bd3c8bSSascha Wildner 	USETW(req.wLength, size);
1892722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, d));
189312bd3c8bSSascha Wildner }
189412bd3c8bSSascha Wildner 
189512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
189612bd3c8bSSascha Wildner  *	usbd_req_set_config
189712bd3c8bSSascha Wildner  *
189812bd3c8bSSascha Wildner  * This function is used to select the current configuration number in
189912bd3c8bSSascha Wildner  * both USB device side mode and USB host side mode. When setting the
190012bd3c8bSSascha Wildner  * configuration the function of the interfaces can change.
190112bd3c8bSSascha Wildner  *
190212bd3c8bSSascha Wildner  * Returns:
190312bd3c8bSSascha Wildner  *    0: Success
190412bd3c8bSSascha Wildner  * Else: Failure
190512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
190612bd3c8bSSascha Wildner usb_error_t
1907722d05c3SSascha Wildner usbd_req_set_config(struct usb_device *udev, struct lock *lock, uint8_t conf)
190812bd3c8bSSascha Wildner {
190912bd3c8bSSascha Wildner 	struct usb_device_request req;
191012bd3c8bSSascha Wildner 
191112bd3c8bSSascha Wildner 	DPRINTF("setting config %d\n", conf);
191212bd3c8bSSascha Wildner 
191312bd3c8bSSascha Wildner 	/* do "set configuration" request */
191412bd3c8bSSascha Wildner 
191512bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_DEVICE;
191612bd3c8bSSascha Wildner 	req.bRequest = UR_SET_CONFIG;
191712bd3c8bSSascha Wildner 	req.wValue[0] = conf;
191812bd3c8bSSascha Wildner 	req.wValue[1] = 0;
191912bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
192012bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
1921722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
192212bd3c8bSSascha Wildner }
192312bd3c8bSSascha Wildner 
192412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
192512bd3c8bSSascha Wildner  *	usbd_req_get_config
192612bd3c8bSSascha Wildner  *
192712bd3c8bSSascha Wildner  * Returns:
192812bd3c8bSSascha Wildner  *    0: Success
192912bd3c8bSSascha Wildner  * Else: Failure
193012bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
193112bd3c8bSSascha Wildner usb_error_t
1932722d05c3SSascha Wildner usbd_req_get_config(struct usb_device *udev, struct lock *lock, uint8_t *pconf)
193312bd3c8bSSascha Wildner {
193412bd3c8bSSascha Wildner 	struct usb_device_request req;
193512bd3c8bSSascha Wildner 
193612bd3c8bSSascha Wildner 	req.bmRequestType = UT_READ_DEVICE;
193712bd3c8bSSascha Wildner 	req.bRequest = UR_GET_CONFIG;
193812bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
193912bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
194012bd3c8bSSascha Wildner 	USETW(req.wLength, 1);
1941722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, pconf));
194212bd3c8bSSascha Wildner }
194312bd3c8bSSascha Wildner 
194412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
194512bd3c8bSSascha Wildner  *	usbd_setup_device_desc
194612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
194712bd3c8bSSascha Wildner usb_error_t
1948722d05c3SSascha Wildner usbd_setup_device_desc(struct usb_device *udev, struct lock *lock)
194912bd3c8bSSascha Wildner {
195012bd3c8bSSascha Wildner 	usb_error_t err;
195112bd3c8bSSascha Wildner 
195212bd3c8bSSascha Wildner 	/*
195312bd3c8bSSascha Wildner 	 * Get the first 8 bytes of the device descriptor !
195412bd3c8bSSascha Wildner 	 *
195512bd3c8bSSascha Wildner 	 * NOTE: "usbd_do_request()" will check the device descriptor
195612bd3c8bSSascha Wildner 	 * next time we do a request to see if the maximum packet size
195712bd3c8bSSascha Wildner 	 * changed! The 8 first bytes of the device descriptor
195812bd3c8bSSascha Wildner 	 * contains the maximum packet size to use on control endpoint
195912bd3c8bSSascha Wildner 	 * 0. If this value is different from "USB_MAX_IPACKET" a new
196012bd3c8bSSascha Wildner 	 * USB control request will be setup!
196112bd3c8bSSascha Wildner 	 */
196212bd3c8bSSascha Wildner 	switch (udev->speed) {
196312bd3c8bSSascha Wildner 	case USB_SPEED_FULL:
196457bed822SMarkus Pfeiffer 		if (usb_full_ddesc != 0) {
196557bed822SMarkus Pfeiffer 			/* get full device descriptor */
196657bed822SMarkus Pfeiffer 			err = usbd_req_get_device_desc(udev, lock, &udev->ddesc);
196757bed822SMarkus Pfeiffer 			if (err == 0)
196857bed822SMarkus Pfeiffer 				break;
196957bed822SMarkus Pfeiffer 		}
197057bed822SMarkus Pfeiffer 
197157bed822SMarkus Pfeiffer 		/* get partial device descriptor, some devices crash on this */
1972722d05c3SSascha Wildner 		err = usbd_req_get_desc(udev, lock, NULL, &udev->ddesc,
197312bd3c8bSSascha Wildner 		    USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0);
197457bed822SMarkus Pfeiffer 		if (err != 0)
197512bd3c8bSSascha Wildner 			break;
197657bed822SMarkus Pfeiffer 
197757bed822SMarkus Pfeiffer 		/* get the full device descriptor */
197857bed822SMarkus Pfeiffer 		err = usbd_req_get_device_desc(udev, lock, &udev->ddesc);
197957bed822SMarkus Pfeiffer 		break;
198057bed822SMarkus Pfeiffer 
198112bd3c8bSSascha Wildner 	default:
198257bed822SMarkus Pfeiffer 		DPRINTF("Minimum bMaxPacketSize is large enough "
198357bed822SMarkus Pfeiffer 		    "to hold the complete device descriptor or "
198457bed822SMarkus Pfeiffer 		    "only one bMaxPacketSize choice\n");
198512bd3c8bSSascha Wildner 
198612bd3c8bSSascha Wildner 		/* get the full device descriptor */
1987722d05c3SSascha Wildner 		err = usbd_req_get_device_desc(udev, lock, &udev->ddesc);
198812bd3c8bSSascha Wildner 
198912bd3c8bSSascha Wildner 		/* try one more time, if error */
199057bed822SMarkus Pfeiffer 		if (err != 0)
1991722d05c3SSascha Wildner 			err = usbd_req_get_device_desc(udev, lock, &udev->ddesc);
199257bed822SMarkus Pfeiffer 		break;
199357bed822SMarkus Pfeiffer 	}
199412bd3c8bSSascha Wildner 
199557bed822SMarkus Pfeiffer 	if (err != 0) {
199657bed822SMarkus Pfeiffer 		DPRINTFN(0, "getting device descriptor "
199757bed822SMarkus Pfeiffer 		    "at addr %d failed, %s\n", udev->address,
199857bed822SMarkus Pfeiffer 		    usbd_errstr(err));
199912bd3c8bSSascha Wildner 		return (err);
200012bd3c8bSSascha Wildner 	}
200112bd3c8bSSascha Wildner 
200212bd3c8bSSascha Wildner 	DPRINTF("adding unit addr=%d, rev=%02x, class=%d, "
200312bd3c8bSSascha Wildner 	    "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
200412bd3c8bSSascha Wildner 	    udev->address, UGETW(udev->ddesc.bcdUSB),
200512bd3c8bSSascha Wildner 	    udev->ddesc.bDeviceClass,
200612bd3c8bSSascha Wildner 	    udev->ddesc.bDeviceSubClass,
200712bd3c8bSSascha Wildner 	    udev->ddesc.bDeviceProtocol,
200812bd3c8bSSascha Wildner 	    udev->ddesc.bMaxPacketSize,
200912bd3c8bSSascha Wildner 	    udev->ddesc.bLength,
201012bd3c8bSSascha Wildner 	    udev->speed);
201112bd3c8bSSascha Wildner 
201212bd3c8bSSascha Wildner 	return (err);
201312bd3c8bSSascha Wildner }
201412bd3c8bSSascha Wildner 
201512bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
201612bd3c8bSSascha Wildner  *	usbd_req_re_enumerate
201712bd3c8bSSascha Wildner  *
201812bd3c8bSSascha Wildner  * NOTE: After this function returns the hardware is in the
201912bd3c8bSSascha Wildner  * unconfigured state! The application is responsible for setting a
202012bd3c8bSSascha Wildner  * new configuration.
202112bd3c8bSSascha Wildner  *
202212bd3c8bSSascha Wildner  * Returns:
202312bd3c8bSSascha Wildner  *    0: Success
202412bd3c8bSSascha Wildner  * Else: Failure
202512bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
202612bd3c8bSSascha Wildner usb_error_t
2027722d05c3SSascha Wildner usbd_req_re_enumerate(struct usb_device *udev, struct lock *lock)
202812bd3c8bSSascha Wildner {
202912bd3c8bSSascha Wildner 	struct usb_device *parent_hub;
203012bd3c8bSSascha Wildner 	usb_error_t err;
203112bd3c8bSSascha Wildner 	uint8_t old_addr;
203212bd3c8bSSascha Wildner 	uint8_t do_retry = 1;
203312bd3c8bSSascha Wildner 
203412bd3c8bSSascha Wildner 	if (udev->flags.usb_mode != USB_MODE_HOST) {
203512bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
203612bd3c8bSSascha Wildner 	}
203712bd3c8bSSascha Wildner 	old_addr = udev->address;
203812bd3c8bSSascha Wildner 	parent_hub = udev->parent_hub;
203912bd3c8bSSascha Wildner 	if (parent_hub == NULL) {
204012bd3c8bSSascha Wildner 		return (USB_ERR_INVAL);
204112bd3c8bSSascha Wildner 	}
204212bd3c8bSSascha Wildner retry:
2043b86003c4SMarkus Pfeiffer #if USB_HAVE_TT_SUPPORT
204412bd3c8bSSascha Wildner 	/*
204512bd3c8bSSascha Wildner 	 * Try to reset the High Speed parent HUB of a LOW- or FULL-
204612bd3c8bSSascha Wildner 	 * speed device, if any.
204712bd3c8bSSascha Wildner 	 */
204812bd3c8bSSascha Wildner 	if (udev->parent_hs_hub != NULL &&
204912bd3c8bSSascha Wildner 	    udev->speed != USB_SPEED_HIGH) {
205012bd3c8bSSascha Wildner 		DPRINTF("Trying to reset parent High Speed TT.\n");
2051b86003c4SMarkus Pfeiffer 		if (udev->parent_hs_hub == parent_hub &&
2052b86003c4SMarkus Pfeiffer 		    (uhub_count_active_host_ports(parent_hub, USB_SPEED_LOW) +
2053b86003c4SMarkus Pfeiffer 		     uhub_count_active_host_ports(parent_hub, USB_SPEED_FULL)) == 1) {
2054b86003c4SMarkus Pfeiffer 			/* we can reset the whole TT */
2055b86003c4SMarkus Pfeiffer 			err = usbd_req_reset_tt(parent_hub, NULL,
205612bd3c8bSSascha Wildner 			    udev->hs_port_no);
2057b86003c4SMarkus Pfeiffer 		} else {
2058b86003c4SMarkus Pfeiffer 			/* only reset a particular device and endpoint */
2059b86003c4SMarkus Pfeiffer 			err = usbd_req_clear_tt_buffer(udev->parent_hs_hub, NULL,
2060b86003c4SMarkus Pfeiffer 			    udev->hs_port_no, old_addr, UE_CONTROL, 0);
2061b86003c4SMarkus Pfeiffer 		}
206212bd3c8bSSascha Wildner 		if (err) {
206312bd3c8bSSascha Wildner 			DPRINTF("Resetting parent High "
206412bd3c8bSSascha Wildner 			    "Speed TT failed (%s).\n",
206512bd3c8bSSascha Wildner 			    usbd_errstr(err));
206612bd3c8bSSascha Wildner 		}
206712bd3c8bSSascha Wildner 	}
2068b86003c4SMarkus Pfeiffer #endif
206912bd3c8bSSascha Wildner 	/* Try to warm reset first */
207012bd3c8bSSascha Wildner 	if (parent_hub->speed == USB_SPEED_SUPER)
2071722d05c3SSascha Wildner 		usbd_req_warm_reset_port(parent_hub, lock, udev->port_no);
207212bd3c8bSSascha Wildner 
207312bd3c8bSSascha Wildner 	/* Try to reset the parent HUB port. */
2074722d05c3SSascha Wildner 	err = usbd_req_reset_port(parent_hub, lock, udev->port_no);
207512bd3c8bSSascha Wildner 	if (err) {
207612bd3c8bSSascha Wildner 		DPRINTFN(0, "addr=%d, port reset failed, %s\n",
207712bd3c8bSSascha Wildner 		    old_addr, usbd_errstr(err));
207812bd3c8bSSascha Wildner 		goto done;
207912bd3c8bSSascha Wildner 	}
208012bd3c8bSSascha Wildner 
208112bd3c8bSSascha Wildner 	/*
208212bd3c8bSSascha Wildner 	 * After that the port has been reset our device should be at
208312bd3c8bSSascha Wildner 	 * address zero:
208412bd3c8bSSascha Wildner 	 */
208512bd3c8bSSascha Wildner 	udev->address = USB_START_ADDR;
208612bd3c8bSSascha Wildner 
208712bd3c8bSSascha Wildner 	/* reset "bMaxPacketSize" */
208812bd3c8bSSascha Wildner 	udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET;
208912bd3c8bSSascha Wildner 
209012bd3c8bSSascha Wildner 	/* reset USB state */
209112bd3c8bSSascha Wildner 	usb_set_device_state(udev, USB_STATE_POWERED);
209212bd3c8bSSascha Wildner 
209312bd3c8bSSascha Wildner 	/*
209412bd3c8bSSascha Wildner 	 * Restore device address:
209512bd3c8bSSascha Wildner 	 */
2096722d05c3SSascha Wildner 	err = usbd_req_set_address(udev, lock, old_addr);
209712bd3c8bSSascha Wildner 	if (err) {
209812bd3c8bSSascha Wildner 		/* XXX ignore any errors! */
209912bd3c8bSSascha Wildner 		DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n",
210012bd3c8bSSascha Wildner 		    old_addr, usbd_errstr(err));
210112bd3c8bSSascha Wildner 	}
210212bd3c8bSSascha Wildner 	/*
210312bd3c8bSSascha Wildner 	 * Restore device address, if the controller driver did not
210412bd3c8bSSascha Wildner 	 * set a new one:
210512bd3c8bSSascha Wildner 	 */
210612bd3c8bSSascha Wildner 	if (udev->address == USB_START_ADDR)
210712bd3c8bSSascha Wildner 		udev->address = old_addr;
210812bd3c8bSSascha Wildner 
210912bd3c8bSSascha Wildner 	/* setup the device descriptor and the initial "wMaxPacketSize" */
2110722d05c3SSascha Wildner 	err = usbd_setup_device_desc(udev, lock);
211112bd3c8bSSascha Wildner 
211212bd3c8bSSascha Wildner done:
211312bd3c8bSSascha Wildner 	if (err && do_retry) {
211412bd3c8bSSascha Wildner 		/* give the USB firmware some time to load */
2115722d05c3SSascha Wildner 		usb_pause_mtx(lock, hz / 2);
211612bd3c8bSSascha Wildner 		/* no more retries after this retry */
211712bd3c8bSSascha Wildner 		do_retry = 0;
211812bd3c8bSSascha Wildner 		/* try again */
211912bd3c8bSSascha Wildner 		goto retry;
212012bd3c8bSSascha Wildner 	}
212112bd3c8bSSascha Wildner 	/* restore address */
212212bd3c8bSSascha Wildner 	if (udev->address == USB_START_ADDR)
212312bd3c8bSSascha Wildner 		udev->address = old_addr;
212412bd3c8bSSascha Wildner 	/* update state, if successful */
212512bd3c8bSSascha Wildner 	if (err == 0)
212612bd3c8bSSascha Wildner 		usb_set_device_state(udev, USB_STATE_ADDRESSED);
212712bd3c8bSSascha Wildner 	return (err);
212812bd3c8bSSascha Wildner }
212912bd3c8bSSascha Wildner 
213012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
213112bd3c8bSSascha Wildner  *	usbd_req_clear_device_feature
213212bd3c8bSSascha Wildner  *
213312bd3c8bSSascha Wildner  * Returns:
213412bd3c8bSSascha Wildner  *    0: Success
213512bd3c8bSSascha Wildner  * Else: Failure
213612bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
213712bd3c8bSSascha Wildner usb_error_t
2138722d05c3SSascha Wildner usbd_req_clear_device_feature(struct usb_device *udev, struct lock *lock,
213912bd3c8bSSascha Wildner     uint16_t sel)
214012bd3c8bSSascha Wildner {
214112bd3c8bSSascha Wildner 	struct usb_device_request req;
214212bd3c8bSSascha Wildner 
214312bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_DEVICE;
214412bd3c8bSSascha Wildner 	req.bRequest = UR_CLEAR_FEATURE;
214512bd3c8bSSascha Wildner 	USETW(req.wValue, sel);
214612bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
214712bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
2148722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
214912bd3c8bSSascha Wildner }
215012bd3c8bSSascha Wildner 
215112bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
215212bd3c8bSSascha Wildner  *	usbd_req_set_device_feature
215312bd3c8bSSascha Wildner  *
215412bd3c8bSSascha Wildner  * Returns:
215512bd3c8bSSascha Wildner  *    0: Success
215612bd3c8bSSascha Wildner  * Else: Failure
215712bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
215812bd3c8bSSascha Wildner usb_error_t
2159722d05c3SSascha Wildner usbd_req_set_device_feature(struct usb_device *udev, struct lock *lock,
216012bd3c8bSSascha Wildner     uint16_t sel)
216112bd3c8bSSascha Wildner {
216212bd3c8bSSascha Wildner 	struct usb_device_request req;
216312bd3c8bSSascha Wildner 
216412bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_DEVICE;
216512bd3c8bSSascha Wildner 	req.bRequest = UR_SET_FEATURE;
216612bd3c8bSSascha Wildner 	USETW(req.wValue, sel);
216712bd3c8bSSascha Wildner 	USETW(req.wIndex, 0);
216812bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
2169722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
217012bd3c8bSSascha Wildner }
217112bd3c8bSSascha Wildner 
217212bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
217312bd3c8bSSascha Wildner  *	usbd_req_reset_tt
217412bd3c8bSSascha Wildner  *
217512bd3c8bSSascha Wildner  * Returns:
217612bd3c8bSSascha Wildner  *    0: Success
217712bd3c8bSSascha Wildner  * Else: Failure
217812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
217912bd3c8bSSascha Wildner usb_error_t
2180722d05c3SSascha Wildner usbd_req_reset_tt(struct usb_device *udev, struct lock *lock,
218112bd3c8bSSascha Wildner     uint8_t port)
218212bd3c8bSSascha Wildner {
218312bd3c8bSSascha Wildner 	struct usb_device_request req;
218412bd3c8bSSascha Wildner 
218512bd3c8bSSascha Wildner 	/* For single TT HUBs the port should be 1 */
218612bd3c8bSSascha Wildner 
218712bd3c8bSSascha Wildner 	if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
218812bd3c8bSSascha Wildner 	    udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
218912bd3c8bSSascha Wildner 		port = 1;
219012bd3c8bSSascha Wildner 
219112bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
219212bd3c8bSSascha Wildner 	req.bRequest = UR_RESET_TT;
219312bd3c8bSSascha Wildner 	USETW(req.wValue, 0);
219412bd3c8bSSascha Wildner 	req.wIndex[0] = port;
219512bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
219612bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
2197722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
219812bd3c8bSSascha Wildner }
219912bd3c8bSSascha Wildner 
220012bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
220112bd3c8bSSascha Wildner  *	usbd_req_clear_tt_buffer
220212bd3c8bSSascha Wildner  *
220312bd3c8bSSascha Wildner  * For single TT HUBs the port should be 1.
220412bd3c8bSSascha Wildner  *
220512bd3c8bSSascha Wildner  * Returns:
220612bd3c8bSSascha Wildner  *    0: Success
220712bd3c8bSSascha Wildner  * Else: Failure
220812bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
220912bd3c8bSSascha Wildner usb_error_t
2210722d05c3SSascha Wildner usbd_req_clear_tt_buffer(struct usb_device *udev, struct lock *lock,
221112bd3c8bSSascha Wildner     uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint)
221212bd3c8bSSascha Wildner {
221312bd3c8bSSascha Wildner 	struct usb_device_request req;
221412bd3c8bSSascha Wildner 	uint16_t wValue;
221512bd3c8bSSascha Wildner 
221612bd3c8bSSascha Wildner 	/* For single TT HUBs the port should be 1 */
221712bd3c8bSSascha Wildner 
221812bd3c8bSSascha Wildner 	if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
221912bd3c8bSSascha Wildner 	    udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
222012bd3c8bSSascha Wildner 		port = 1;
222112bd3c8bSSascha Wildner 
222212bd3c8bSSascha Wildner 	wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) |
222312bd3c8bSSascha Wildner 	    ((endpoint & 0x80) << 8) | ((type & 3) << 12);
222412bd3c8bSSascha Wildner 
222512bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
222612bd3c8bSSascha Wildner 	req.bRequest = UR_CLEAR_TT_BUFFER;
222712bd3c8bSSascha Wildner 	USETW(req.wValue, wValue);
222812bd3c8bSSascha Wildner 	req.wIndex[0] = port;
222912bd3c8bSSascha Wildner 	req.wIndex[1] = 0;
223012bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
2231722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
223212bd3c8bSSascha Wildner }
223312bd3c8bSSascha Wildner 
223412bd3c8bSSascha Wildner /*------------------------------------------------------------------------*
223512bd3c8bSSascha Wildner  *	usbd_req_set_port_link_state
223612bd3c8bSSascha Wildner  *
223712bd3c8bSSascha Wildner  * USB 3.0 specific request
223812bd3c8bSSascha Wildner  *
223912bd3c8bSSascha Wildner  * Returns:
224012bd3c8bSSascha Wildner  *    0: Success
224112bd3c8bSSascha Wildner  * Else: Failure
224212bd3c8bSSascha Wildner  *------------------------------------------------------------------------*/
224312bd3c8bSSascha Wildner usb_error_t
2244722d05c3SSascha Wildner usbd_req_set_port_link_state(struct usb_device *udev, struct lock *lock,
224512bd3c8bSSascha Wildner     uint8_t port, uint8_t link_state)
224612bd3c8bSSascha Wildner {
224712bd3c8bSSascha Wildner 	struct usb_device_request req;
224812bd3c8bSSascha Wildner 
224912bd3c8bSSascha Wildner 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
225012bd3c8bSSascha Wildner 	req.bRequest = UR_SET_FEATURE;
225112bd3c8bSSascha Wildner 	USETW(req.wValue, UHF_PORT_LINK_STATE);
225212bd3c8bSSascha Wildner 	req.wIndex[0] = port;
225312bd3c8bSSascha Wildner 	req.wIndex[1] = link_state;
225412bd3c8bSSascha Wildner 	USETW(req.wLength, 0);
2255722d05c3SSascha Wildner 	return (usbd_do_request(udev, lock, &req, 0));
225612bd3c8bSSascha Wildner }
22575e41ab93SMarkus Pfeiffer 
22585e41ab93SMarkus Pfeiffer /*------------------------------------------------------------------------*
22595e41ab93SMarkus Pfeiffer  *		usbd_req_set_lpm_info
22605e41ab93SMarkus Pfeiffer  *
22615e41ab93SMarkus Pfeiffer  * USB 2.0 specific request for Link Power Management.
22625e41ab93SMarkus Pfeiffer  *
22635e41ab93SMarkus Pfeiffer  * Returns:
22645e41ab93SMarkus Pfeiffer  * 0:				Success
22655e41ab93SMarkus Pfeiffer  * USB_ERR_PENDING_REQUESTS:	NYET
22665e41ab93SMarkus Pfeiffer  * USB_ERR_TIMEOUT:		TIMEOUT
22675e41ab93SMarkus Pfeiffer  * USB_ERR_STALL:		STALL
22685e41ab93SMarkus Pfeiffer  * Else:			Failure
22695e41ab93SMarkus Pfeiffer  *------------------------------------------------------------------------*/
22705e41ab93SMarkus Pfeiffer usb_error_t
22715e41ab93SMarkus Pfeiffer usbd_req_set_lpm_info(struct usb_device *udev, struct lock *lock,
22725e41ab93SMarkus Pfeiffer     uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe)
22735e41ab93SMarkus Pfeiffer {
22745e41ab93SMarkus Pfeiffer 	struct usb_device_request req;
22755e41ab93SMarkus Pfeiffer 	usb_error_t err;
22765e41ab93SMarkus Pfeiffer 	uint8_t buf[1];
22775e41ab93SMarkus Pfeiffer 
22785e41ab93SMarkus Pfeiffer 	req.bmRequestType = UT_WRITE_CLASS_OTHER;
22795e41ab93SMarkus Pfeiffer 	req.bRequest = UR_SET_AND_TEST;
22805e41ab93SMarkus Pfeiffer 	USETW(req.wValue, UHF_PORT_L1);
22815e41ab93SMarkus Pfeiffer 	req.wIndex[0] = (port & 0xF) | ((besl & 0xF) << 4);
22825e41ab93SMarkus Pfeiffer 	req.wIndex[1] = (addr & 0x7F) | (rwe ? 0x80 : 0x00);
22835e41ab93SMarkus Pfeiffer 	USETW(req.wLength, sizeof(buf));
22845e41ab93SMarkus Pfeiffer 
22855e41ab93SMarkus Pfeiffer 	/* set default value in case of short transfer */
22865e41ab93SMarkus Pfeiffer 	buf[0] = 0x00;
22875e41ab93SMarkus Pfeiffer 
22885e41ab93SMarkus Pfeiffer 	err = usbd_do_request(udev, lock, &req, buf);
22895e41ab93SMarkus Pfeiffer 	if (err)
22905e41ab93SMarkus Pfeiffer 		return (err);
22915e41ab93SMarkus Pfeiffer 
22925e41ab93SMarkus Pfeiffer 	switch (buf[0]) {
22935e41ab93SMarkus Pfeiffer 	case 0x00:	/* SUCCESS */
22945e41ab93SMarkus Pfeiffer 		break;
22955e41ab93SMarkus Pfeiffer 	case 0x10:	/* NYET */
22965e41ab93SMarkus Pfeiffer 		err = USB_ERR_PENDING_REQUESTS;
22975e41ab93SMarkus Pfeiffer 		break;
22985e41ab93SMarkus Pfeiffer 	case 0x11:	/* TIMEOUT */
22995e41ab93SMarkus Pfeiffer 		err = USB_ERR_TIMEOUT;
23005e41ab93SMarkus Pfeiffer 		break;
23015e41ab93SMarkus Pfeiffer 	case 0x30:	/* STALL */
23025e41ab93SMarkus Pfeiffer 		err = USB_ERR_STALLED;
23035e41ab93SMarkus Pfeiffer 		break;
23045e41ab93SMarkus Pfeiffer 	default:	/* reserved */
23055e41ab93SMarkus Pfeiffer 		err = USB_ERR_IOERROR;
23065e41ab93SMarkus Pfeiffer 		break;
23075e41ab93SMarkus Pfeiffer 	}
23085e41ab93SMarkus Pfeiffer 	return (err);
23095e41ab93SMarkus Pfeiffer }
23105e41ab93SMarkus Pfeiffer 
2311