usb_request.c revision 192499
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 192499 2009-05-21 00:04:17Z thompsa $ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
4184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved.
5184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer.
12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer in the
14184610Salfred *    documentation and/or other materials provided with the distribution.
15184610Salfred *
16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184610Salfred * SUCH DAMAGE.
27190754Sthompsa */
28184610Salfred
29188942Sthompsa#include <dev/usb/usb_mfunc.h>
30188942Sthompsa#include <dev/usb/usb_error.h>
31188942Sthompsa#include <dev/usb/usb.h>
32188942Sthompsa#include <dev/usb/usb_ioctl.h>
33188942Sthompsa#include <dev/usb/usbhid.h>
34184610Salfred
35184610Salfred#define	USB_DEBUG_VAR usb2_debug
36184610Salfred
37188942Sthompsa#include <dev/usb/usb_core.h>
38188942Sthompsa#include <dev/usb/usb_busdma.h>
39188942Sthompsa#include <dev/usb/usb_request.h>
40188942Sthompsa#include <dev/usb/usb_process.h>
41188942Sthompsa#include <dev/usb/usb_transfer.h>
42188942Sthompsa#include <dev/usb/usb_debug.h>
43188942Sthompsa#include <dev/usb/usb_device.h>
44188942Sthompsa#include <dev/usb/usb_util.h>
45188942Sthompsa#include <dev/usb/usb_dynamic.h>
46184610Salfred
47188942Sthompsa#include <dev/usb/usb_controller.h>
48188942Sthompsa#include <dev/usb/usb_bus.h>
49184610Salfred#include <sys/ctype.h>
50184610Salfred
51184610Salfred#if USB_DEBUG
52184610Salfredstatic int usb2_pr_poll_delay = USB_PORT_RESET_DELAY;
53184610Salfredstatic int usb2_pr_recovery_delay = USB_PORT_RESET_RECOVERY;
54184610Salfredstatic int usb2_ss_delay = 0;
55184610Salfred
56184610SalfredSYSCTL_INT(_hw_usb2, OID_AUTO, pr_poll_delay, CTLFLAG_RW,
57184610Salfred    &usb2_pr_poll_delay, 0, "USB port reset poll delay in ms");
58184610SalfredSYSCTL_INT(_hw_usb2, OID_AUTO, pr_recovery_delay, CTLFLAG_RW,
59184610Salfred    &usb2_pr_recovery_delay, 0, "USB port reset recovery delay in ms");
60184610SalfredSYSCTL_INT(_hw_usb2, OID_AUTO, ss_delay, CTLFLAG_RW,
61184610Salfred    &usb2_ss_delay, 0, "USB status stage delay in ms");
62184610Salfred#endif
63184610Salfred
64184610Salfred/*------------------------------------------------------------------------*
65184610Salfred *	usb2_do_request_callback
66184610Salfred *
67184610Salfred * This function is the USB callback for generic USB Host control
68184610Salfred * transfers.
69184610Salfred *------------------------------------------------------------------------*/
70184610Salfredvoid
71184610Salfredusb2_do_request_callback(struct usb2_xfer *xfer)
72184610Salfred{
73184610Salfred	;				/* workaround for a bug in "indent" */
74184610Salfred
75184610Salfred	DPRINTF("st=%u\n", USB_GET_STATE(xfer));
76184610Salfred
77184610Salfred	switch (USB_GET_STATE(xfer)) {
78184610Salfred	case USB_ST_SETUP:
79184610Salfred		usb2_start_hardware(xfer);
80184610Salfred		break;
81184610Salfred	default:
82187173Sthompsa		usb2_cv_signal(xfer->xroot->udev->default_cv);
83184610Salfred		break;
84184610Salfred	}
85184610Salfred}
86184610Salfred
87184610Salfred/*------------------------------------------------------------------------*
88184610Salfred *	usb2_do_clear_stall_callback
89184610Salfred *
90184610Salfred * This function is the USB callback for generic clear stall requests.
91184610Salfred *------------------------------------------------------------------------*/
92184610Salfredvoid
93184610Salfredusb2_do_clear_stall_callback(struct usb2_xfer *xfer)
94184610Salfred{
95184610Salfred	struct usb2_device_request req;
96187173Sthompsa	struct usb2_device *udev;
97184610Salfred	struct usb2_pipe *pipe;
98184610Salfred	struct usb2_pipe *pipe_end;
99184610Salfred	struct usb2_pipe *pipe_first;
100190731Sthompsa	uint8_t to;
101184610Salfred
102187173Sthompsa	udev = xfer->xroot->udev;
103184610Salfred
104187173Sthompsa	USB_BUS_LOCK(udev->bus);
105187173Sthompsa
106184610Salfred	/* round robin pipe clear stall */
107184610Salfred
108187173Sthompsa	pipe = udev->pipe_curr;
109190731Sthompsa	pipe_end = udev->pipes + udev->pipes_max;
110187173Sthompsa	pipe_first = udev->pipes;
111190731Sthompsa	to = udev->pipes_max;
112184610Salfred	if (pipe == NULL) {
113184610Salfred		pipe = pipe_first;
114184610Salfred	}
115184610Salfred	switch (USB_GET_STATE(xfer)) {
116184610Salfred	case USB_ST_TRANSFERRED:
117184610Salfred		if (pipe->edesc &&
118184610Salfred		    pipe->is_stalled) {
119184610Salfred			pipe->toggle_next = 0;
120184610Salfred			pipe->is_stalled = 0;
121184610Salfred			/* start up the current or next transfer, if any */
122184610Salfred			usb2_command_wrapper(&pipe->pipe_q,
123184610Salfred			    pipe->pipe_q.curr);
124184610Salfred		}
125184610Salfred		pipe++;
126184610Salfred
127184610Salfred	case USB_ST_SETUP:
128184610Salfredtr_setup:
129184610Salfred		if (pipe == pipe_end) {
130184610Salfred			pipe = pipe_first;
131184610Salfred		}
132184610Salfred		if (pipe->edesc &&
133184610Salfred		    pipe->is_stalled) {
134184610Salfred
135184610Salfred			/* setup a clear-stall packet */
136184610Salfred
137184610Salfred			req.bmRequestType = UT_WRITE_ENDPOINT;
138184610Salfred			req.bRequest = UR_CLEAR_FEATURE;
139184610Salfred			USETW(req.wValue, UF_ENDPOINT_HALT);
140184610Salfred			req.wIndex[0] = pipe->edesc->bEndpointAddress;
141184610Salfred			req.wIndex[1] = 0;
142184610Salfred			USETW(req.wLength, 0);
143184610Salfred
144184610Salfred			/* copy in the transfer */
145184610Salfred
146184610Salfred			usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
147184610Salfred
148184610Salfred			/* set length */
149184610Salfred			xfer->frlengths[0] = sizeof(req);
150184610Salfred			xfer->nframes = 1;
151187173Sthompsa			USB_BUS_UNLOCK(udev->bus);
152184610Salfred
153184610Salfred			usb2_start_hardware(xfer);
154184610Salfred
155187173Sthompsa			USB_BUS_LOCK(udev->bus);
156184610Salfred			break;
157184610Salfred		}
158184610Salfred		pipe++;
159184610Salfred		if (--to)
160184610Salfred			goto tr_setup;
161184610Salfred		break;
162184610Salfred
163184610Salfred	default:
164184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
165184610Salfred			break;
166184610Salfred		}
167184610Salfred		goto tr_setup;
168184610Salfred	}
169184610Salfred
170184610Salfred	/* store current pipe */
171187173Sthompsa	udev->pipe_curr = pipe;
172187173Sthompsa	USB_BUS_UNLOCK(udev->bus);
173184610Salfred}
174184610Salfred
175191402Sthompsastatic usb2_handle_request_t *
176191402Sthompsausb2_get_hr_func(struct usb2_device *udev)
177191402Sthompsa{
178191402Sthompsa	/* figure out if there is a Handle Request function */
179192499Sthompsa	if (udev->flags.usb_mode == USB_MODE_DEVICE)
180191402Sthompsa		return (usb2_temp_get_desc_p);
181191402Sthompsa	else if (udev->parent_hub == NULL)
182191402Sthompsa		return (udev->bus->methods->roothub_exec);
183191402Sthompsa	else
184191402Sthompsa		return (NULL);
185191402Sthompsa}
186191402Sthompsa
187184610Salfred/*------------------------------------------------------------------------*
188184610Salfred *	usb2_do_request_flags and usb2_do_request
189184610Salfred *
190184610Salfred * Description of arguments passed to these functions:
191184610Salfred *
192184610Salfred * "udev" - this is the "usb2_device" structure pointer on which the
193184610Salfred * request should be performed. It is possible to call this function
194184610Salfred * in both Host Side mode and Device Side mode.
195184610Salfred *
196184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it
197184610Salfred * will get dropped and picked up during the execution of this
198184610Salfred * function, hence this function sometimes needs to sleep. If this
199184610Salfred * argument is NULL it has no effect.
200184610Salfred *
201184610Salfred * "req" - this argument must always be non-NULL and points to an
202184610Salfred * 8-byte structure holding the USB request to be done. The USB
203184610Salfred * request structure has a bit telling the direction of the USB
204184610Salfred * request, if it is a read or a write.
205184610Salfred *
206184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req"
207184610Salfred * is non-zero this argument must point to a valid kernel buffer which
208184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can
209184610Salfred * be NULL.
210184610Salfred *
211184610Salfred * "flags" - here is a list of valid flags:
212184610Salfred *
213184610Salfred *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
214184610Salfred *  specified
215184610Salfred *
216184610Salfred *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
217184610Salfred *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
218184610Salfred *  sysctl. This flag is mostly useful for debugging.
219184610Salfred *
220184610Salfred *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
221184610Salfred *  pointer.
222184610Salfred *
223184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in
224184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This
225184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
226184610Salfred * used.
227184610Salfred *
228184610Salfred * "timeout" - gives the timeout for the control transfer in
229184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is
230184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater
231184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack
232184610Salfred * does not allow control requests without a timeout.
233184610Salfred *
234184610Salfred * NOTE: This function is thread safe. All calls to
235184610Salfred * "usb2_do_request_flags" will be serialised by the use of an
236184610Salfred * internal "sx_lock".
237184610Salfred *
238184610Salfred * Returns:
239184610Salfred *    0: Success
240184610Salfred * Else: Failure
241184610Salfred *------------------------------------------------------------------------*/
242184610Salfredusb2_error_t
243184610Salfredusb2_do_request_flags(struct usb2_device *udev, struct mtx *mtx,
244190181Sthompsa    struct usb2_device_request *req, void *data, uint16_t flags,
245190181Sthompsa    uint16_t *actlen, usb2_timeout_t timeout)
246184610Salfred{
247191402Sthompsa	usb2_handle_request_t *hr_func;
248184610Salfred	struct usb2_xfer *xfer;
249184610Salfred	const void *desc;
250184610Salfred	int err = 0;
251190181Sthompsa	usb2_ticks_t start_ticks;
252190181Sthompsa	usb2_ticks_t delta_ticks;
253190181Sthompsa	usb2_ticks_t max_ticks;
254184610Salfred	uint16_t length;
255184610Salfred	uint16_t temp;
256184610Salfred
257184610Salfred	if (timeout < 50) {
258184610Salfred		/* timeout is too small */
259184610Salfred		timeout = 50;
260184610Salfred	}
261184610Salfred	if (timeout > 30000) {
262184610Salfred		/* timeout is too big */
263184610Salfred		timeout = 30000;
264184610Salfred	}
265184610Salfred	length = UGETW(req->wLength);
266184610Salfred
267184610Salfred	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
268184610Salfred	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
269184610Salfred	    udev, req->bmRequestType, req->bRequest,
270184610Salfred	    req->wValue[1], req->wValue[0],
271184610Salfred	    req->wIndex[1], req->wIndex[0],
272184610Salfred	    req->wLength[1], req->wLength[0]);
273184610Salfred
274191494Sthompsa	/* Check if the device is still alive */
275191494Sthompsa	if (udev->state < USB_STATE_POWERED) {
276191494Sthompsa		DPRINTF("usb device has gone\n");
277191494Sthompsa		return (USB_ERR_NOT_CONFIGURED);
278191494Sthompsa	}
279191494Sthompsa
280184610Salfred	/*
281184610Salfred	 * Set "actlen" to a known value in case the caller does not
282184610Salfred	 * check the return value:
283184610Salfred	 */
284190735Sthompsa	if (actlen)
285184610Salfred		*actlen = 0;
286190735Sthompsa
287190180Sthompsa#if (USB_HAVE_USER_IO == 0)
288190180Sthompsa	if (flags & USB_USER_DATA_PTR)
289190180Sthompsa		return (USB_ERR_INVAL);
290190180Sthompsa#endif
291184610Salfred	if (mtx) {
292184610Salfred		mtx_unlock(mtx);
293184610Salfred		if (mtx != &Giant) {
294184610Salfred			mtx_assert(mtx, MA_NOTOWNED);
295184610Salfred		}
296184610Salfred	}
297184610Salfred	/*
298184610Salfred	 * Grab the default sx-lock so that serialisation
299184610Salfred	 * is achieved when multiple threads are involved:
300184610Salfred	 */
301184610Salfred
302184610Salfred	sx_xlock(udev->default_sx);
303184610Salfred
304191402Sthompsa	hr_func = usb2_get_hr_func(udev);
305190735Sthompsa
306191402Sthompsa	if (hr_func != NULL) {
307191402Sthompsa		DPRINTF("Handle Request function is set\n");
308190735Sthompsa
309191402Sthompsa		desc = NULL;
310191402Sthompsa		temp = 0;
311191402Sthompsa
312191402Sthompsa		if (!(req->bmRequestType & UT_READ)) {
313190735Sthompsa			if (length != 0) {
314191402Sthompsa				DPRINTFN(1, "The handle request function "
315191402Sthompsa				    "does not support writing data!\n");
316191402Sthompsa				err = USB_ERR_INVAL;
317191402Sthompsa				goto done;
318190735Sthompsa			}
319190735Sthompsa		}
320190735Sthompsa
321191402Sthompsa		/* The root HUB code needs the BUS lock locked */
322191402Sthompsa
323190735Sthompsa		USB_BUS_LOCK(udev->bus);
324191402Sthompsa		err = (hr_func) (udev, req, &desc, &temp);
325190735Sthompsa		USB_BUS_UNLOCK(udev->bus);
326190735Sthompsa
327190735Sthompsa		if (err)
328190735Sthompsa			goto done;
329190735Sthompsa
330191402Sthompsa		if (length > temp) {
331190735Sthompsa			if (!(flags & USB_SHORT_XFER_OK)) {
332190735Sthompsa				err = USB_ERR_SHORT_XFER;
333190735Sthompsa				goto done;
334190735Sthompsa			}
335191402Sthompsa			length = temp;
336190735Sthompsa		}
337190735Sthompsa		if (actlen)
338190735Sthompsa			*actlen = length;
339190735Sthompsa
340190735Sthompsa		if (length > 0) {
341190735Sthompsa#if USB_HAVE_USER_IO
342190735Sthompsa			if (flags & USB_USER_DATA_PTR) {
343191402Sthompsa				if (copyout(desc, data, length)) {
344190735Sthompsa					err = USB_ERR_INVAL;
345190735Sthompsa					goto done;
346190735Sthompsa				}
347190735Sthompsa			} else
348190735Sthompsa#endif
349191402Sthompsa				bcopy(desc, data, length);
350190735Sthompsa		}
351191402Sthompsa		goto done;		/* success */
352190735Sthompsa	}
353190735Sthompsa
354184610Salfred	/*
355184610Salfred	 * Setup a new USB transfer or use the existing one, if any:
356184610Salfred	 */
357184610Salfred	usb2_default_transfer_setup(udev);
358184610Salfred
359184610Salfred	xfer = udev->default_xfer[0];
360184610Salfred	if (xfer == NULL) {
361184610Salfred		/* most likely out of memory */
362184610Salfred		err = USB_ERR_NOMEM;
363184610Salfred		goto done;
364184610Salfred	}
365184824Sthompsa	USB_XFER_LOCK(xfer);
366184610Salfred
367190734Sthompsa	if (flags & USB_DELAY_STATUS_STAGE)
368184610Salfred		xfer->flags.manual_status = 1;
369190734Sthompsa	else
370184610Salfred		xfer->flags.manual_status = 0;
371184610Salfred
372190734Sthompsa	if (flags & USB_SHORT_XFER_OK)
373190734Sthompsa		xfer->flags.short_xfer_ok = 1;
374190734Sthompsa	else
375190734Sthompsa		xfer->flags.short_xfer_ok = 0;
376190734Sthompsa
377184610Salfred	xfer->timeout = timeout;
378184610Salfred
379184610Salfred	start_ticks = ticks;
380184610Salfred
381184610Salfred	max_ticks = USB_MS_TO_TICKS(timeout);
382184610Salfred
383184610Salfred	usb2_copy_in(xfer->frbuffers, 0, req, sizeof(*req));
384184610Salfred
385184610Salfred	xfer->frlengths[0] = sizeof(*req);
386184610Salfred	xfer->nframes = 2;
387184610Salfred
388184610Salfred	while (1) {
389184610Salfred		temp = length;
390184610Salfred		if (temp > xfer->max_data_length) {
391184610Salfred			temp = xfer->max_data_length;
392184610Salfred		}
393184610Salfred		xfer->frlengths[1] = temp;
394184610Salfred
395184610Salfred		if (temp > 0) {
396184610Salfred			if (!(req->bmRequestType & UT_READ)) {
397190180Sthompsa#if USB_HAVE_USER_IO
398184610Salfred				if (flags & USB_USER_DATA_PTR) {
399184824Sthompsa					USB_XFER_UNLOCK(xfer);
400184610Salfred					err = usb2_copy_in_user(xfer->frbuffers + 1,
401184610Salfred					    0, data, temp);
402184824Sthompsa					USB_XFER_LOCK(xfer);
403184610Salfred					if (err) {
404184610Salfred						err = USB_ERR_INVAL;
405184610Salfred						break;
406184610Salfred					}
407190180Sthompsa				} else
408190180Sthompsa#endif
409190180Sthompsa					usb2_copy_in(xfer->frbuffers + 1,
410190180Sthompsa					    0, data, temp);
411184610Salfred			}
412184610Salfred			xfer->nframes = 2;
413184610Salfred		} else {
414184610Salfred			if (xfer->frlengths[0] == 0) {
415184610Salfred				if (xfer->flags.manual_status) {
416184610Salfred#if USB_DEBUG
417184610Salfred					int temp;
418184610Salfred
419184610Salfred					temp = usb2_ss_delay;
420184610Salfred					if (temp > 5000) {
421184610Salfred						temp = 5000;
422184610Salfred					}
423184610Salfred					if (temp > 0) {
424184610Salfred						usb2_pause_mtx(
425187173Sthompsa						    xfer->xroot->xfer_mtx,
426188411Sthompsa						    USB_MS_TO_TICKS(temp));
427184610Salfred					}
428184610Salfred#endif
429184610Salfred					xfer->flags.manual_status = 0;
430184610Salfred				} else {
431184610Salfred					break;
432184610Salfred				}
433184610Salfred			}
434184610Salfred			xfer->nframes = 1;
435184610Salfred		}
436184610Salfred
437184610Salfred		usb2_transfer_start(xfer);
438184610Salfred
439184610Salfred		while (usb2_transfer_pending(xfer)) {
440188983Sthompsa			usb2_cv_wait(udev->default_cv,
441188983Sthompsa			    xfer->xroot->xfer_mtx);
442184610Salfred		}
443184610Salfred
444184610Salfred		err = xfer->error;
445184610Salfred
446184610Salfred		if (err) {
447184610Salfred			break;
448184610Salfred		}
449184610Salfred		/* subtract length of SETUP packet, if any */
450184610Salfred
451184610Salfred		if (xfer->aframes > 0) {
452184610Salfred			xfer->actlen -= xfer->frlengths[0];
453184610Salfred		} else {
454184610Salfred			xfer->actlen = 0;
455184610Salfred		}
456184610Salfred
457184610Salfred		/* check for short packet */
458184610Salfred
459184610Salfred		if (temp > xfer->actlen) {
460184610Salfred			temp = xfer->actlen;
461184610Salfred			length = temp;
462184610Salfred		}
463184610Salfred		if (temp > 0) {
464184610Salfred			if (req->bmRequestType & UT_READ) {
465190180Sthompsa#if USB_HAVE_USER_IO
466184610Salfred				if (flags & USB_USER_DATA_PTR) {
467184824Sthompsa					USB_XFER_UNLOCK(xfer);
468184610Salfred					err = usb2_copy_out_user(xfer->frbuffers + 1,
469184610Salfred					    0, data, temp);
470184824Sthompsa					USB_XFER_LOCK(xfer);
471184610Salfred					if (err) {
472184610Salfred						err = USB_ERR_INVAL;
473184610Salfred						break;
474184610Salfred					}
475190180Sthompsa				} else
476190180Sthompsa#endif
477184610Salfred					usb2_copy_out(xfer->frbuffers + 1,
478184610Salfred					    0, data, temp);
479184610Salfred			}
480184610Salfred		}
481184610Salfred		/*
482184610Salfred		 * Clear "frlengths[0]" so that we don't send the setup
483184610Salfred		 * packet again:
484184610Salfred		 */
485184610Salfred		xfer->frlengths[0] = 0;
486184610Salfred
487184610Salfred		/* update length and data pointer */
488184610Salfred		length -= temp;
489184610Salfred		data = USB_ADD_BYTES(data, temp);
490184610Salfred
491184610Salfred		if (actlen) {
492184610Salfred			(*actlen) += temp;
493184610Salfred		}
494184610Salfred		/* check for timeout */
495184610Salfred
496184610Salfred		delta_ticks = ticks - start_ticks;
497184610Salfred		if (delta_ticks > max_ticks) {
498184610Salfred			if (!err) {
499184610Salfred				err = USB_ERR_TIMEOUT;
500184610Salfred			}
501184610Salfred		}
502184610Salfred		if (err) {
503184610Salfred			break;
504184610Salfred		}
505184610Salfred	}
506184610Salfred
507184610Salfred	if (err) {
508184610Salfred		/*
509184610Salfred		 * Make sure that the control endpoint is no longer
510184610Salfred		 * blocked in case of a non-transfer related error:
511184610Salfred		 */
512184610Salfred		usb2_transfer_stop(xfer);
513184610Salfred	}
514184824Sthompsa	USB_XFER_UNLOCK(xfer);
515184610Salfred
516184610Salfreddone:
517184610Salfred	sx_xunlock(udev->default_sx);
518184610Salfred
519184610Salfred	if (mtx) {
520184610Salfred		mtx_lock(mtx);
521184610Salfred	}
522184610Salfred	return ((usb2_error_t)err);
523184610Salfred}
524184610Salfred
525184610Salfred/*------------------------------------------------------------------------*
526188411Sthompsa *	usb2_do_request_proc - factored out code
527188411Sthompsa *
528188411Sthompsa * This function is factored out code. It does basically the same like
529188411Sthompsa * usb2_do_request_flags, except it will check the status of the
530188411Sthompsa * passed process argument before doing the USB request. If the
531188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It
532188411Sthompsa * is assumed that the mutex associated with the process is locked
533188411Sthompsa * when calling this function.
534188411Sthompsa *------------------------------------------------------------------------*/
535188411Sthompsausb2_error_t
536188411Sthompsausb2_do_request_proc(struct usb2_device *udev, struct usb2_process *pproc,
537190181Sthompsa    struct usb2_device_request *req, void *data, uint16_t flags,
538190181Sthompsa    uint16_t *actlen, usb2_timeout_t timeout)
539188411Sthompsa{
540188411Sthompsa	usb2_error_t err;
541188411Sthompsa	uint16_t len;
542188411Sthompsa
543188411Sthompsa	/* get request data length */
544188411Sthompsa	len = UGETW(req->wLength);
545188411Sthompsa
546188411Sthompsa	/* check if the device is being detached */
547188411Sthompsa	if (usb2_proc_is_gone(pproc)) {
548188411Sthompsa		err = USB_ERR_IOERROR;
549188411Sthompsa		goto done;
550188411Sthompsa	}
551188411Sthompsa
552188411Sthompsa	/* forward the USB request */
553188411Sthompsa	err = usb2_do_request_flags(udev, pproc->up_mtx,
554188411Sthompsa	    req, data, flags, actlen, timeout);
555188411Sthompsa
556188411Sthompsadone:
557188411Sthompsa	/* on failure we zero the data */
558188411Sthompsa	/* on short packet we zero the unused data */
559188411Sthompsa	if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) {
560188411Sthompsa		if (err)
561188411Sthompsa			memset(data, 0, len);
562188411Sthompsa		else if (actlen && *actlen != len)
563188411Sthompsa			memset(((uint8_t *)data) + *actlen, 0, len - *actlen);
564188411Sthompsa	}
565188411Sthompsa	return (err);
566188411Sthompsa}
567188411Sthompsa
568188411Sthompsa/*------------------------------------------------------------------------*
569184610Salfred *	usb2_req_reset_port
570184610Salfred *
571184610Salfred * This function will instruct an USB HUB to perform a reset sequence
572184610Salfred * on the specified port number.
573184610Salfred *
574184610Salfred * Returns:
575184610Salfred *    0: Success. The USB device should now be at address zero.
576184610Salfred * Else: Failure. No USB device is present and the USB port should be
577184610Salfred *       disabled.
578184610Salfred *------------------------------------------------------------------------*/
579184610Salfredusb2_error_t
580184610Salfredusb2_req_reset_port(struct usb2_device *udev, struct mtx *mtx, uint8_t port)
581184610Salfred{
582184610Salfred	struct usb2_port_status ps;
583184610Salfred	usb2_error_t err;
584184610Salfred	uint16_t n;
585184610Salfred
586184610Salfred#if USB_DEBUG
587184610Salfred	uint16_t pr_poll_delay;
588184610Salfred	uint16_t pr_recovery_delay;
589184610Salfred
590184610Salfred#endif
591184610Salfred	err = usb2_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
592184610Salfred	if (err) {
593184610Salfred		goto done;
594184610Salfred	}
595184610Salfred#if USB_DEBUG
596184610Salfred	/* range check input parameters */
597184610Salfred	pr_poll_delay = usb2_pr_poll_delay;
598184610Salfred	if (pr_poll_delay < 1) {
599184610Salfred		pr_poll_delay = 1;
600184610Salfred	} else if (pr_poll_delay > 1000) {
601184610Salfred		pr_poll_delay = 1000;
602184610Salfred	}
603184610Salfred	pr_recovery_delay = usb2_pr_recovery_delay;
604184610Salfred	if (pr_recovery_delay > 1000) {
605184610Salfred		pr_recovery_delay = 1000;
606184610Salfred	}
607184610Salfred#endif
608184610Salfred	n = 0;
609184610Salfred	while (1) {
610184610Salfred#if USB_DEBUG
611184610Salfred		/* wait for the device to recover from reset */
612188411Sthompsa		usb2_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
613184610Salfred		n += pr_poll_delay;
614184610Salfred#else
615184610Salfred		/* wait for the device to recover from reset */
616188411Sthompsa		usb2_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
617184610Salfred		n += USB_PORT_RESET_DELAY;
618184610Salfred#endif
619184610Salfred		err = usb2_req_get_port_status(udev, mtx, &ps, port);
620184610Salfred		if (err) {
621184610Salfred			goto done;
622184610Salfred		}
623184610Salfred		/* if the device disappeared, just give up */
624184610Salfred		if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
625184610Salfred			goto done;
626184610Salfred		}
627184610Salfred		/* check if reset is complete */
628184610Salfred		if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
629184610Salfred			break;
630184610Salfred		}
631184610Salfred		/* check for timeout */
632184610Salfred		if (n > 1000) {
633184610Salfred			n = 0;
634184610Salfred			break;
635184610Salfred		}
636184610Salfred	}
637184610Salfred
638184610Salfred	/* clear port reset first */
639184610Salfred	err = usb2_req_clear_port_feature(
640184610Salfred	    udev, mtx, port, UHF_C_PORT_RESET);
641184610Salfred	if (err) {
642184610Salfred		goto done;
643184610Salfred	}
644184610Salfred	/* check for timeout */
645184610Salfred	if (n == 0) {
646184610Salfred		err = USB_ERR_TIMEOUT;
647184610Salfred		goto done;
648184610Salfred	}
649184610Salfred#if USB_DEBUG
650184610Salfred	/* wait for the device to recover from reset */
651188411Sthompsa	usb2_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
652184610Salfred#else
653184610Salfred	/* wait for the device to recover from reset */
654188411Sthompsa	usb2_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
655184610Salfred#endif
656184610Salfred
657184610Salfreddone:
658184610Salfred	DPRINTFN(2, "port %d reset returning error=%s\n",
659184610Salfred	    port, usb2_errstr(err));
660184610Salfred	return (err);
661184610Salfred}
662184610Salfred
663184610Salfred/*------------------------------------------------------------------------*
664184610Salfred *	usb2_req_get_desc
665184610Salfred *
666184610Salfred * This function can be used to retrieve USB descriptors. It contains
667184610Salfred * some additional logic like zeroing of missing descriptor bytes and
668184610Salfred * retrying an USB descriptor in case of failure. The "min_len"
669184610Salfred * argument specifies the minimum descriptor length. The "max_len"
670184610Salfred * argument specifies the maximum descriptor length. If the real
671184610Salfred * descriptor length is less than the minimum length the missing
672188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB
673188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen"
674188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get
675188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The
676188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen"
677188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated
678188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to
679188985Sthompsa * "max_len" then this function will try to retrive the beginning of
680188985Sthompsa * the descriptor and base the maximum length on the first byte of the
681188985Sthompsa * descriptor.
682184610Salfred *
683184610Salfred * Returns:
684184610Salfred *    0: Success
685184610Salfred * Else: Failure
686184610Salfred *------------------------------------------------------------------------*/
687184610Salfredusb2_error_t
688188985Sthompsausb2_req_get_desc(struct usb2_device *udev,
689188985Sthompsa    struct mtx *mtx, uint16_t *actlen, void *desc,
690184610Salfred    uint16_t min_len, uint16_t max_len,
691184610Salfred    uint16_t id, uint8_t type, uint8_t index,
692184610Salfred    uint8_t retries)
693184610Salfred{
694184610Salfred	struct usb2_device_request req;
695184610Salfred	uint8_t *buf;
696184610Salfred	usb2_error_t err;
697184610Salfred
698184610Salfred	DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n",
699184610Salfred	    id, type, index, max_len);
700184610Salfred
701184610Salfred	req.bmRequestType = UT_READ_DEVICE;
702184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
703184610Salfred	USETW2(req.wValue, type, index);
704184610Salfred	USETW(req.wIndex, id);
705184610Salfred
706184610Salfred	while (1) {
707184610Salfred
708184610Salfred		if ((min_len < 2) || (max_len < 2)) {
709184610Salfred			err = USB_ERR_INVAL;
710184610Salfred			goto done;
711184610Salfred		}
712184610Salfred		USETW(req.wLength, min_len);
713184610Salfred
714186730Salfred		err = usb2_do_request_flags(udev, mtx, &req,
715186730Salfred		    desc, 0, NULL, 1000);
716184610Salfred
717184610Salfred		if (err) {
718184610Salfred			if (!retries) {
719184610Salfred				goto done;
720184610Salfred			}
721184610Salfred			retries--;
722184610Salfred
723188411Sthompsa			usb2_pause_mtx(mtx, hz / 5);
724184610Salfred
725184610Salfred			continue;
726184610Salfred		}
727184610Salfred		buf = desc;
728184610Salfred
729184610Salfred		if (min_len == max_len) {
730184610Salfred
731188985Sthompsa			/* enforce correct length */
732188985Sthompsa			if ((buf[0] > min_len) && (actlen == NULL))
733188985Sthompsa				buf[0] = min_len;
734184610Salfred
735188985Sthompsa			/* enforce correct type */
736184610Salfred			buf[1] = type;
737184610Salfred
738184610Salfred			goto done;
739184610Salfred		}
740184610Salfred		/* range check */
741184610Salfred
742184610Salfred		if (max_len > buf[0]) {
743184610Salfred			max_len = buf[0];
744184610Salfred		}
745184610Salfred		/* zero minimum data */
746184610Salfred
747184610Salfred		while (min_len > max_len) {
748184610Salfred			min_len--;
749184610Salfred			buf[min_len] = 0;
750184610Salfred		}
751184610Salfred
752184610Salfred		/* set new minimum length */
753184610Salfred
754184610Salfred		min_len = max_len;
755184610Salfred	}
756184610Salfreddone:
757188985Sthompsa	if (actlen != NULL) {
758188985Sthompsa		if (err)
759188985Sthompsa			*actlen = 0;
760188985Sthompsa		else
761188985Sthompsa			*actlen = min_len;
762188985Sthompsa	}
763184610Salfred	return (err);
764184610Salfred}
765184610Salfred
766184610Salfred/*------------------------------------------------------------------------*
767184610Salfred *	usb2_req_get_string_any
768184610Salfred *
769184610Salfred * This function will return the string given by "string_index"
770184610Salfred * using the first language ID. The maximum length "len" includes
771184610Salfred * the terminating zero. The "len" argument should be twice as
772184610Salfred * big pluss 2 bytes, compared with the actual maximum string length !
773184610Salfred *
774184610Salfred * Returns:
775184610Salfred *    0: Success
776184610Salfred * Else: Failure
777184610Salfred *------------------------------------------------------------------------*/
778184610Salfredusb2_error_t
779184610Salfredusb2_req_get_string_any(struct usb2_device *udev, struct mtx *mtx, char *buf,
780184610Salfred    uint16_t len, uint8_t string_index)
781184610Salfred{
782184610Salfred	char *s;
783184610Salfred	uint8_t *temp;
784184610Salfred	uint16_t i;
785184610Salfred	uint16_t n;
786184610Salfred	uint16_t c;
787184610Salfred	uint8_t swap;
788184610Salfred	usb2_error_t err;
789184610Salfred
790184610Salfred	if (len == 0) {
791184610Salfred		/* should not happen */
792184610Salfred		return (USB_ERR_NORMAL_COMPLETION);
793184610Salfred	}
794184610Salfred	if (string_index == 0) {
795184610Salfred		/* this is the language table */
796185087Salfred		buf[0] = 0;
797184610Salfred		return (USB_ERR_INVAL);
798184610Salfred	}
799184610Salfred	if (udev->flags.no_strings) {
800185087Salfred		buf[0] = 0;
801184610Salfred		return (USB_ERR_STALLED);
802184610Salfred	}
803184610Salfred	err = usb2_req_get_string_desc
804184610Salfred	    (udev, mtx, buf, len, udev->langid, string_index);
805184610Salfred	if (err) {
806185087Salfred		buf[0] = 0;
807184610Salfred		return (err);
808184610Salfred	}
809184610Salfred	temp = (uint8_t *)buf;
810184610Salfred
811184610Salfred	if (temp[0] < 2) {
812184610Salfred		/* string length is too short */
813185087Salfred		buf[0] = 0;
814184610Salfred		return (USB_ERR_INVAL);
815184610Salfred	}
816184610Salfred	/* reserve one byte for terminating zero */
817184610Salfred	len--;
818184610Salfred
819184610Salfred	/* find maximum length */
820184610Salfred	s = buf;
821184610Salfred	n = (temp[0] / 2) - 1;
822184610Salfred	if (n > len) {
823184610Salfred		n = len;
824184610Salfred	}
825184610Salfred	/* skip descriptor header */
826184610Salfred	temp += 2;
827184610Salfred
828184610Salfred	/* reset swap state */
829184610Salfred	swap = 3;
830184610Salfred
831184610Salfred	/* convert and filter */
832184610Salfred	for (i = 0; (i != n); i++) {
833184610Salfred		c = UGETW(temp + (2 * i));
834184610Salfred
835184610Salfred		/* convert from Unicode, handle buggy strings */
836184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
837184610Salfred			/* Little Endian, default */
838184610Salfred			*s = c;
839184610Salfred			swap = 1;
840184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
841184610Salfred			/* Big Endian */
842184610Salfred			*s = c >> 8;
843184610Salfred			swap = 2;
844184610Salfred		} else {
845185087Salfred			/* silently skip bad character */
846185087Salfred			continue;
847184610Salfred		}
848184610Salfred
849184610Salfred		/*
850184610Salfred		 * Filter by default - we don't allow greater and less than
851184610Salfred		 * signs because they might confuse the dmesg printouts!
852184610Salfred		 */
853184610Salfred		if ((*s == '<') || (*s == '>') || (!isprint(*s))) {
854185087Salfred			/* silently skip bad character */
855185087Salfred			continue;
856184610Salfred		}
857184610Salfred		s++;
858184610Salfred	}
859185087Salfred	*s = 0;				/* zero terminate resulting string */
860184610Salfred	return (USB_ERR_NORMAL_COMPLETION);
861184610Salfred}
862184610Salfred
863184610Salfred/*------------------------------------------------------------------------*
864184610Salfred *	usb2_req_get_string_desc
865184610Salfred *
866184610Salfred * If you don't know the language ID, consider using
867184610Salfred * "usb2_req_get_string_any()".
868184610Salfred *
869184610Salfred * Returns:
870184610Salfred *    0: Success
871184610Salfred * Else: Failure
872184610Salfred *------------------------------------------------------------------------*/
873184610Salfredusb2_error_t
874184610Salfredusb2_req_get_string_desc(struct usb2_device *udev, struct mtx *mtx, void *sdesc,
875184610Salfred    uint16_t max_len, uint16_t lang_id,
876184610Salfred    uint8_t string_index)
877184610Salfred{
878188985Sthompsa	return (usb2_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id,
879184610Salfred	    UDESC_STRING, string_index, 0));
880184610Salfred}
881184610Salfred
882184610Salfred/*------------------------------------------------------------------------*
883190727Sthompsa *	usb2_req_get_config_desc_ptr
884190727Sthompsa *
885190727Sthompsa * This function is used in device side mode to retrieve the pointer
886190727Sthompsa * to the generated config descriptor. This saves allocating space for
887190727Sthompsa * an additional config descriptor when setting the configuration.
888190727Sthompsa *
889190727Sthompsa * Returns:
890190727Sthompsa *    0: Success
891190727Sthompsa * Else: Failure
892190727Sthompsa *------------------------------------------------------------------------*/
893190727Sthompsausb2_error_t
894191402Sthompsausb2_req_get_descriptor_ptr(struct usb2_device *udev,
895191402Sthompsa    struct usb2_config_descriptor **ppcd, uint16_t wValue)
896190727Sthompsa{
897191402Sthompsa	struct usb2_device_request req;
898191402Sthompsa	usb2_handle_request_t *hr_func;
899191402Sthompsa	const void *ptr;
900190727Sthompsa	uint16_t len;
901191402Sthompsa	usb2_error_t err;
902190727Sthompsa
903190731Sthompsa	req.bmRequestType = UT_READ_DEVICE;
904190727Sthompsa	req.bRequest = UR_GET_DESCRIPTOR;
905191402Sthompsa	USETW(req.wValue, wValue);
906190727Sthompsa	USETW(req.wIndex, 0);
907190727Sthompsa	USETW(req.wLength, 0);
908190727Sthompsa
909191402Sthompsa	ptr = NULL;
910191402Sthompsa	len = 0;
911190727Sthompsa
912191402Sthompsa	hr_func = usb2_get_hr_func(udev);
913191402Sthompsa
914191402Sthompsa	if (hr_func == NULL)
915191402Sthompsa		err = USB_ERR_INVAL;
916191402Sthompsa	else {
917191402Sthompsa		USB_BUS_LOCK(udev->bus);
918191402Sthompsa		err = (hr_func) (udev, &req, &ptr, &len);
919191402Sthompsa		USB_BUS_UNLOCK(udev->bus);
920191402Sthompsa	}
921191402Sthompsa
922191402Sthompsa	if (err)
923191402Sthompsa		ptr = NULL;
924191402Sthompsa	else if (ptr == NULL)
925191402Sthompsa		err = USB_ERR_INVAL;
926191402Sthompsa
927191402Sthompsa	*ppcd = __DECONST(struct usb2_config_descriptor *, ptr);
928191402Sthompsa
929191402Sthompsa	return (err);
930190727Sthompsa}
931190727Sthompsa
932190727Sthompsa/*------------------------------------------------------------------------*
933184610Salfred *	usb2_req_get_config_desc
934184610Salfred *
935184610Salfred * Returns:
936184610Salfred *    0: Success
937184610Salfred * Else: Failure
938184610Salfred *------------------------------------------------------------------------*/
939184610Salfredusb2_error_t
940184610Salfredusb2_req_get_config_desc(struct usb2_device *udev, struct mtx *mtx,
941184610Salfred    struct usb2_config_descriptor *d, uint8_t conf_index)
942184610Salfred{
943184610Salfred	usb2_error_t err;
944184610Salfred
945184610Salfred	DPRINTFN(4, "confidx=%d\n", conf_index);
946184610Salfred
947188985Sthompsa	err = usb2_req_get_desc(udev, mtx, NULL, d, sizeof(*d),
948184610Salfred	    sizeof(*d), 0, UDESC_CONFIG, conf_index, 0);
949184610Salfred	if (err) {
950184610Salfred		goto done;
951184610Salfred	}
952184610Salfred	/* Extra sanity checking */
953184610Salfred	if (UGETW(d->wTotalLength) < sizeof(*d)) {
954184610Salfred		err = USB_ERR_INVAL;
955184610Salfred	}
956184610Salfreddone:
957184610Salfred	return (err);
958184610Salfred}
959184610Salfred
960184610Salfred/*------------------------------------------------------------------------*
961184610Salfred *	usb2_req_get_config_desc_full
962184610Salfred *
963184610Salfred * This function gets the complete USB configuration descriptor and
964184610Salfred * ensures that "wTotalLength" is correct.
965184610Salfred *
966184610Salfred * Returns:
967184610Salfred *    0: Success
968184610Salfred * Else: Failure
969184610Salfred *------------------------------------------------------------------------*/
970184610Salfredusb2_error_t
971184610Salfredusb2_req_get_config_desc_full(struct usb2_device *udev, struct mtx *mtx,
972184610Salfred    struct usb2_config_descriptor **ppcd, struct malloc_type *mtype,
973184610Salfred    uint8_t index)
974184610Salfred{
975184610Salfred	struct usb2_config_descriptor cd;
976184610Salfred	struct usb2_config_descriptor *cdesc;
977184610Salfred	uint16_t len;
978184610Salfred	usb2_error_t err;
979184610Salfred
980184610Salfred	DPRINTFN(4, "index=%d\n", index);
981184610Salfred
982184610Salfred	*ppcd = NULL;
983184610Salfred
984184610Salfred	err = usb2_req_get_config_desc(udev, mtx, &cd, index);
985184610Salfred	if (err) {
986184610Salfred		return (err);
987184610Salfred	}
988184610Salfred	/* get full descriptor */
989184610Salfred	len = UGETW(cd.wTotalLength);
990184610Salfred	if (len < sizeof(*cdesc)) {
991184610Salfred		/* corrupt descriptor */
992184610Salfred		return (USB_ERR_INVAL);
993184610Salfred	}
994184610Salfred	cdesc = malloc(len, mtype, M_WAITOK);
995184610Salfred	if (cdesc == NULL) {
996184610Salfred		return (USB_ERR_NOMEM);
997184610Salfred	}
998188985Sthompsa	err = usb2_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0,
999184610Salfred	    UDESC_CONFIG, index, 3);
1000184610Salfred	if (err) {
1001184610Salfred		free(cdesc, mtype);
1002184610Salfred		return (err);
1003184610Salfred	}
1004184610Salfred	/* make sure that the device is not fooling us: */
1005184610Salfred	USETW(cdesc->wTotalLength, len);
1006184610Salfred
1007184610Salfred	*ppcd = cdesc;
1008184610Salfred
1009184610Salfred	return (0);			/* success */
1010184610Salfred}
1011184610Salfred
1012184610Salfred/*------------------------------------------------------------------------*
1013184610Salfred *	usb2_req_get_device_desc
1014184610Salfred *
1015184610Salfred * Returns:
1016184610Salfred *    0: Success
1017184610Salfred * Else: Failure
1018184610Salfred *------------------------------------------------------------------------*/
1019184610Salfredusb2_error_t
1020184610Salfredusb2_req_get_device_desc(struct usb2_device *udev, struct mtx *mtx,
1021184610Salfred    struct usb2_device_descriptor *d)
1022184610Salfred{
1023184610Salfred	DPRINTFN(4, "\n");
1024188985Sthompsa	return (usb2_req_get_desc(udev, mtx, NULL, d, sizeof(*d),
1025184610Salfred	    sizeof(*d), 0, UDESC_DEVICE, 0, 3));
1026184610Salfred}
1027184610Salfred
1028184610Salfred/*------------------------------------------------------------------------*
1029184610Salfred *	usb2_req_get_alt_interface_no
1030184610Salfred *
1031184610Salfred * Returns:
1032184610Salfred *    0: Success
1033184610Salfred * Else: Failure
1034184610Salfred *------------------------------------------------------------------------*/
1035184610Salfredusb2_error_t
1036184610Salfredusb2_req_get_alt_interface_no(struct usb2_device *udev, struct mtx *mtx,
1037184610Salfred    uint8_t *alt_iface_no, uint8_t iface_index)
1038184610Salfred{
1039184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1040184610Salfred	struct usb2_device_request req;
1041184610Salfred
1042184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1043184610Salfred		return (USB_ERR_INVAL);
1044184610Salfred	}
1045184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1046184610Salfred	req.bRequest = UR_GET_INTERFACE;
1047184610Salfred	USETW(req.wValue, 0);
1048184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1049184610Salfred	req.wIndex[1] = 0;
1050184610Salfred	USETW(req.wLength, 1);
1051184610Salfred	return (usb2_do_request(udev, mtx, &req, alt_iface_no));
1052184610Salfred}
1053184610Salfred
1054184610Salfred/*------------------------------------------------------------------------*
1055184610Salfred *	usb2_req_set_alt_interface_no
1056184610Salfred *
1057184610Salfred * Returns:
1058184610Salfred *    0: Success
1059184610Salfred * Else: Failure
1060184610Salfred *------------------------------------------------------------------------*/
1061184610Salfredusb2_error_t
1062184610Salfredusb2_req_set_alt_interface_no(struct usb2_device *udev, struct mtx *mtx,
1063184610Salfred    uint8_t iface_index, uint8_t alt_no)
1064184610Salfred{
1065184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1066184610Salfred	struct usb2_device_request req;
1067184610Salfred
1068184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1069184610Salfred		return (USB_ERR_INVAL);
1070184610Salfred	}
1071184610Salfred	req.bmRequestType = UT_WRITE_INTERFACE;
1072184610Salfred	req.bRequest = UR_SET_INTERFACE;
1073184610Salfred	req.wValue[0] = alt_no;
1074184610Salfred	req.wValue[1] = 0;
1075184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1076184610Salfred	req.wIndex[1] = 0;
1077184610Salfred	USETW(req.wLength, 0);
1078184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1079184610Salfred}
1080184610Salfred
1081184610Salfred/*------------------------------------------------------------------------*
1082184610Salfred *	usb2_req_get_device_status
1083184610Salfred *
1084184610Salfred * Returns:
1085184610Salfred *    0: Success
1086184610Salfred * Else: Failure
1087184610Salfred *------------------------------------------------------------------------*/
1088184610Salfredusb2_error_t
1089184610Salfredusb2_req_get_device_status(struct usb2_device *udev, struct mtx *mtx,
1090184610Salfred    struct usb2_status *st)
1091184610Salfred{
1092184610Salfred	struct usb2_device_request req;
1093184610Salfred
1094184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1095184610Salfred	req.bRequest = UR_GET_STATUS;
1096184610Salfred	USETW(req.wValue, 0);
1097184610Salfred	USETW(req.wIndex, 0);
1098184610Salfred	USETW(req.wLength, sizeof(*st));
1099184610Salfred	return (usb2_do_request(udev, mtx, &req, st));
1100184610Salfred}
1101184610Salfred
1102184610Salfred/*------------------------------------------------------------------------*
1103184610Salfred *	usb2_req_get_hub_descriptor
1104184610Salfred *
1105184610Salfred * Returns:
1106184610Salfred *    0: Success
1107184610Salfred * Else: Failure
1108184610Salfred *------------------------------------------------------------------------*/
1109184610Salfredusb2_error_t
1110184610Salfredusb2_req_get_hub_descriptor(struct usb2_device *udev, struct mtx *mtx,
1111184610Salfred    struct usb2_hub_descriptor *hd, uint8_t nports)
1112184610Salfred{
1113184610Salfred	struct usb2_device_request req;
1114184610Salfred	uint16_t len = (nports + 7 + (8 * 8)) / 8;
1115184610Salfred
1116184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
1117184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1118184610Salfred	USETW2(req.wValue, UDESC_HUB, 0);
1119184610Salfred	USETW(req.wIndex, 0);
1120184610Salfred	USETW(req.wLength, len);
1121184610Salfred	return (usb2_do_request(udev, mtx, &req, hd));
1122184610Salfred}
1123184610Salfred
1124184610Salfred/*------------------------------------------------------------------------*
1125184610Salfred *	usb2_req_get_hub_status
1126184610Salfred *
1127184610Salfred * Returns:
1128184610Salfred *    0: Success
1129184610Salfred * Else: Failure
1130184610Salfred *------------------------------------------------------------------------*/
1131184610Salfredusb2_error_t
1132184610Salfredusb2_req_get_hub_status(struct usb2_device *udev, struct mtx *mtx,
1133184610Salfred    struct usb2_hub_status *st)
1134184610Salfred{
1135184610Salfred	struct usb2_device_request req;
1136184610Salfred
1137184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
1138184610Salfred	req.bRequest = UR_GET_STATUS;
1139184610Salfred	USETW(req.wValue, 0);
1140184610Salfred	USETW(req.wIndex, 0);
1141184610Salfred	USETW(req.wLength, sizeof(struct usb2_hub_status));
1142184610Salfred	return (usb2_do_request(udev, mtx, &req, st));
1143184610Salfred}
1144184610Salfred
1145184610Salfred/*------------------------------------------------------------------------*
1146184610Salfred *	usb2_req_set_address
1147184610Salfred *
1148184610Salfred * This function is used to set the address for an USB device. After
1149184610Salfred * port reset the USB device will respond at address zero.
1150184610Salfred *
1151184610Salfred * Returns:
1152184610Salfred *    0: Success
1153184610Salfred * Else: Failure
1154184610Salfred *------------------------------------------------------------------------*/
1155184610Salfredusb2_error_t
1156184610Salfredusb2_req_set_address(struct usb2_device *udev, struct mtx *mtx, uint16_t addr)
1157184610Salfred{
1158184610Salfred	struct usb2_device_request req;
1159184610Salfred
1160184610Salfred	DPRINTFN(6, "setting device address=%d\n", addr);
1161184610Salfred
1162184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1163184610Salfred	req.bRequest = UR_SET_ADDRESS;
1164184610Salfred	USETW(req.wValue, addr);
1165184610Salfred	USETW(req.wIndex, 0);
1166184610Salfred	USETW(req.wLength, 0);
1167184610Salfred
1168184610Salfred	/* Setting the address should not take more than 1 second ! */
1169184610Salfred	return (usb2_do_request_flags(udev, mtx, &req, NULL,
1170184610Salfred	    USB_DELAY_STATUS_STAGE, NULL, 1000));
1171184610Salfred}
1172184610Salfred
1173184610Salfred/*------------------------------------------------------------------------*
1174184610Salfred *	usb2_req_get_port_status
1175184610Salfred *
1176184610Salfred * Returns:
1177184610Salfred *    0: Success
1178184610Salfred * Else: Failure
1179184610Salfred *------------------------------------------------------------------------*/
1180184610Salfredusb2_error_t
1181184610Salfredusb2_req_get_port_status(struct usb2_device *udev, struct mtx *mtx,
1182184610Salfred    struct usb2_port_status *ps, uint8_t port)
1183184610Salfred{
1184184610Salfred	struct usb2_device_request req;
1185184610Salfred
1186184610Salfred	req.bmRequestType = UT_READ_CLASS_OTHER;
1187184610Salfred	req.bRequest = UR_GET_STATUS;
1188184610Salfred	USETW(req.wValue, 0);
1189184610Salfred	req.wIndex[0] = port;
1190184610Salfred	req.wIndex[1] = 0;
1191184610Salfred	USETW(req.wLength, sizeof *ps);
1192184610Salfred	return (usb2_do_request(udev, mtx, &req, ps));
1193184610Salfred}
1194184610Salfred
1195184610Salfred/*------------------------------------------------------------------------*
1196184610Salfred *	usb2_req_clear_hub_feature
1197184610Salfred *
1198184610Salfred * Returns:
1199184610Salfred *    0: Success
1200184610Salfred * Else: Failure
1201184610Salfred *------------------------------------------------------------------------*/
1202184610Salfredusb2_error_t
1203184610Salfredusb2_req_clear_hub_feature(struct usb2_device *udev, struct mtx *mtx,
1204184610Salfred    uint16_t sel)
1205184610Salfred{
1206184610Salfred	struct usb2_device_request req;
1207184610Salfred
1208184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1209184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1210184610Salfred	USETW(req.wValue, sel);
1211184610Salfred	USETW(req.wIndex, 0);
1212184610Salfred	USETW(req.wLength, 0);
1213184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1214184610Salfred}
1215184610Salfred
1216184610Salfred/*------------------------------------------------------------------------*
1217184610Salfred *	usb2_req_set_hub_feature
1218184610Salfred *
1219184610Salfred * Returns:
1220184610Salfred *    0: Success
1221184610Salfred * Else: Failure
1222184610Salfred *------------------------------------------------------------------------*/
1223184610Salfredusb2_error_t
1224184610Salfredusb2_req_set_hub_feature(struct usb2_device *udev, struct mtx *mtx,
1225184610Salfred    uint16_t sel)
1226184610Salfred{
1227184610Salfred	struct usb2_device_request req;
1228184610Salfred
1229184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1230184610Salfred	req.bRequest = UR_SET_FEATURE;
1231184610Salfred	USETW(req.wValue, sel);
1232184610Salfred	USETW(req.wIndex, 0);
1233184610Salfred	USETW(req.wLength, 0);
1234184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1235184610Salfred}
1236184610Salfred
1237184610Salfred/*------------------------------------------------------------------------*
1238184610Salfred *	usb2_req_clear_port_feature
1239184610Salfred *
1240184610Salfred * Returns:
1241184610Salfred *    0: Success
1242184610Salfred * Else: Failure
1243184610Salfred *------------------------------------------------------------------------*/
1244184610Salfredusb2_error_t
1245184610Salfredusb2_req_clear_port_feature(struct usb2_device *udev, struct mtx *mtx,
1246184610Salfred    uint8_t port, uint16_t sel)
1247184610Salfred{
1248184610Salfred	struct usb2_device_request req;
1249184610Salfred
1250184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1251184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1252184610Salfred	USETW(req.wValue, sel);
1253184610Salfred	req.wIndex[0] = port;
1254184610Salfred	req.wIndex[1] = 0;
1255184610Salfred	USETW(req.wLength, 0);
1256184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1257184610Salfred}
1258184610Salfred
1259184610Salfred/*------------------------------------------------------------------------*
1260184610Salfred *	usb2_req_set_port_feature
1261184610Salfred *
1262184610Salfred * Returns:
1263184610Salfred *    0: Success
1264184610Salfred * Else: Failure
1265184610Salfred *------------------------------------------------------------------------*/
1266184610Salfredusb2_error_t
1267184610Salfredusb2_req_set_port_feature(struct usb2_device *udev, struct mtx *mtx,
1268184610Salfred    uint8_t port, uint16_t sel)
1269184610Salfred{
1270184610Salfred	struct usb2_device_request req;
1271184610Salfred
1272184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1273184610Salfred	req.bRequest = UR_SET_FEATURE;
1274184610Salfred	USETW(req.wValue, sel);
1275184610Salfred	req.wIndex[0] = port;
1276184610Salfred	req.wIndex[1] = 0;
1277184610Salfred	USETW(req.wLength, 0);
1278184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1279184610Salfred}
1280184610Salfred
1281184610Salfred/*------------------------------------------------------------------------*
1282184610Salfred *	usb2_req_set_protocol
1283184610Salfred *
1284184610Salfred * Returns:
1285184610Salfred *    0: Success
1286184610Salfred * Else: Failure
1287184610Salfred *------------------------------------------------------------------------*/
1288184610Salfredusb2_error_t
1289184610Salfredusb2_req_set_protocol(struct usb2_device *udev, struct mtx *mtx,
1290184610Salfred    uint8_t iface_index, uint16_t report)
1291184610Salfred{
1292184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1293184610Salfred	struct usb2_device_request req;
1294184610Salfred
1295184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1296184610Salfred		return (USB_ERR_INVAL);
1297184610Salfred	}
1298184610Salfred	DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n",
1299184610Salfred	    iface, report, iface->idesc->bInterfaceNumber);
1300184610Salfred
1301184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1302184610Salfred	req.bRequest = UR_SET_PROTOCOL;
1303184610Salfred	USETW(req.wValue, report);
1304184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1305184610Salfred	req.wIndex[1] = 0;
1306184610Salfred	USETW(req.wLength, 0);
1307184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1308184610Salfred}
1309184610Salfred
1310184610Salfred/*------------------------------------------------------------------------*
1311184610Salfred *	usb2_req_set_report
1312184610Salfred *
1313184610Salfred * Returns:
1314184610Salfred *    0: Success
1315184610Salfred * Else: Failure
1316184610Salfred *------------------------------------------------------------------------*/
1317184610Salfredusb2_error_t
1318184610Salfredusb2_req_set_report(struct usb2_device *udev, struct mtx *mtx, void *data, uint16_t len,
1319184610Salfred    uint8_t iface_index, uint8_t type, uint8_t id)
1320184610Salfred{
1321184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1322184610Salfred	struct usb2_device_request req;
1323184610Salfred
1324184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1325184610Salfred		return (USB_ERR_INVAL);
1326184610Salfred	}
1327184610Salfred	DPRINTFN(5, "len=%d\n", len);
1328184610Salfred
1329184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1330184610Salfred	req.bRequest = UR_SET_REPORT;
1331184610Salfred	USETW2(req.wValue, type, id);
1332184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1333184610Salfred	req.wIndex[1] = 0;
1334184610Salfred	USETW(req.wLength, len);
1335184610Salfred	return (usb2_do_request(udev, mtx, &req, data));
1336184610Salfred}
1337184610Salfred
1338184610Salfred/*------------------------------------------------------------------------*
1339184610Salfred *	usb2_req_get_report
1340184610Salfred *
1341184610Salfred * Returns:
1342184610Salfred *    0: Success
1343184610Salfred * Else: Failure
1344184610Salfred *------------------------------------------------------------------------*/
1345184610Salfredusb2_error_t
1346184610Salfredusb2_req_get_report(struct usb2_device *udev, struct mtx *mtx, void *data,
1347184610Salfred    uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
1348184610Salfred{
1349184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1350184610Salfred	struct usb2_device_request req;
1351184610Salfred
1352184610Salfred	if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) {
1353184610Salfred		return (USB_ERR_INVAL);
1354184610Salfred	}
1355184610Salfred	DPRINTFN(5, "len=%d\n", len);
1356184610Salfred
1357184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1358184610Salfred	req.bRequest = UR_GET_REPORT;
1359184610Salfred	USETW2(req.wValue, type, id);
1360184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1361184610Salfred	req.wIndex[1] = 0;
1362184610Salfred	USETW(req.wLength, len);
1363184610Salfred	return (usb2_do_request(udev, mtx, &req, data));
1364184610Salfred}
1365184610Salfred
1366184610Salfred/*------------------------------------------------------------------------*
1367184610Salfred *	usb2_req_set_idle
1368184610Salfred *
1369184610Salfred * Returns:
1370184610Salfred *    0: Success
1371184610Salfred * Else: Failure
1372184610Salfred *------------------------------------------------------------------------*/
1373184610Salfredusb2_error_t
1374184610Salfredusb2_req_set_idle(struct usb2_device *udev, struct mtx *mtx,
1375184610Salfred    uint8_t iface_index, uint8_t duration, uint8_t id)
1376184610Salfred{
1377184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1378184610Salfred	struct usb2_device_request req;
1379184610Salfred
1380184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1381184610Salfred		return (USB_ERR_INVAL);
1382184610Salfred	}
1383184610Salfred	DPRINTFN(5, "%d %d\n", duration, id);
1384184610Salfred
1385184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1386184610Salfred	req.bRequest = UR_SET_IDLE;
1387184610Salfred	USETW2(req.wValue, duration, id);
1388184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1389184610Salfred	req.wIndex[1] = 0;
1390184610Salfred	USETW(req.wLength, 0);
1391184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1392184610Salfred}
1393184610Salfred
1394184610Salfred/*------------------------------------------------------------------------*
1395184610Salfred *	usb2_req_get_report_descriptor
1396184610Salfred *
1397184610Salfred * Returns:
1398184610Salfred *    0: Success
1399184610Salfred * Else: Failure
1400184610Salfred *------------------------------------------------------------------------*/
1401184610Salfredusb2_error_t
1402184610Salfredusb2_req_get_report_descriptor(struct usb2_device *udev, struct mtx *mtx,
1403184610Salfred    void *d, uint16_t size, uint8_t iface_index)
1404184610Salfred{
1405184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1406184610Salfred	struct usb2_device_request req;
1407184610Salfred
1408184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1409184610Salfred		return (USB_ERR_INVAL);
1410184610Salfred	}
1411184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1412184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1413184610Salfred	USETW2(req.wValue, UDESC_REPORT, 0);	/* report id should be 0 */
1414184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1415184610Salfred	req.wIndex[1] = 0;
1416184610Salfred	USETW(req.wLength, size);
1417184610Salfred	return (usb2_do_request(udev, mtx, &req, d));
1418184610Salfred}
1419184610Salfred
1420184610Salfred/*------------------------------------------------------------------------*
1421184610Salfred *	usb2_req_set_config
1422184610Salfred *
1423184610Salfred * This function is used to select the current configuration number in
1424184610Salfred * both USB device side mode and USB host side mode. When setting the
1425184610Salfred * configuration the function of the interfaces can change.
1426184610Salfred *
1427184610Salfred * Returns:
1428184610Salfred *    0: Success
1429184610Salfred * Else: Failure
1430184610Salfred *------------------------------------------------------------------------*/
1431184610Salfredusb2_error_t
1432184610Salfredusb2_req_set_config(struct usb2_device *udev, struct mtx *mtx, uint8_t conf)
1433184610Salfred{
1434184610Salfred	struct usb2_device_request req;
1435184610Salfred
1436184610Salfred	DPRINTF("setting config %d\n", conf);
1437184610Salfred
1438184610Salfred	/* do "set configuration" request */
1439184610Salfred
1440184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1441184610Salfred	req.bRequest = UR_SET_CONFIG;
1442184610Salfred	req.wValue[0] = conf;
1443184610Salfred	req.wValue[1] = 0;
1444184610Salfred	USETW(req.wIndex, 0);
1445184610Salfred	USETW(req.wLength, 0);
1446184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1447184610Salfred}
1448184610Salfred
1449184610Salfred/*------------------------------------------------------------------------*
1450184610Salfred *	usb2_req_get_config
1451184610Salfred *
1452184610Salfred * Returns:
1453184610Salfred *    0: Success
1454184610Salfred * Else: Failure
1455184610Salfred *------------------------------------------------------------------------*/
1456184610Salfredusb2_error_t
1457184610Salfredusb2_req_get_config(struct usb2_device *udev, struct mtx *mtx, uint8_t *pconf)
1458184610Salfred{
1459184610Salfred	struct usb2_device_request req;
1460184610Salfred
1461184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1462184610Salfred	req.bRequest = UR_GET_CONFIG;
1463184610Salfred	USETW(req.wValue, 0);
1464184610Salfred	USETW(req.wIndex, 0);
1465184610Salfred	USETW(req.wLength, 1);
1466184610Salfred	return (usb2_do_request(udev, mtx, &req, pconf));
1467184610Salfred}
1468184610Salfred
1469184610Salfred/*------------------------------------------------------------------------*
1470184610Salfred *	usb2_req_re_enumerate
1471184610Salfred *
1472185087Salfred * NOTE: After this function returns the hardware is in the
1473185087Salfred * unconfigured state! The application is responsible for setting a
1474185087Salfred * new configuration.
1475185087Salfred *
1476184610Salfred * Returns:
1477184610Salfred *    0: Success
1478184610Salfred * Else: Failure
1479184610Salfred *------------------------------------------------------------------------*/
1480184610Salfredusb2_error_t
1481184610Salfredusb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx)
1482184610Salfred{
1483184610Salfred	struct usb2_device *parent_hub;
1484184610Salfred	usb2_error_t err;
1485184610Salfred	uint8_t old_addr;
1486186730Salfred	uint8_t do_retry = 1;
1487184610Salfred
1488192499Sthompsa	if (udev->flags.usb_mode != USB_MODE_HOST) {
1489185290Salfred		return (USB_ERR_INVAL);
1490185290Salfred	}
1491184610Salfred	old_addr = udev->address;
1492184610Salfred	parent_hub = udev->parent_hub;
1493184610Salfred	if (parent_hub == NULL) {
1494185290Salfred		return (USB_ERR_INVAL);
1495184610Salfred	}
1496186730Salfredretry:
1497184610Salfred	err = usb2_req_reset_port(parent_hub, mtx, udev->port_no);
1498184610Salfred	if (err) {
1499190739Sthompsa		DPRINTFN(0, "addr=%d, port reset failed, %s\n",
1500190739Sthompsa		    old_addr, usb2_errstr(err));
1501184610Salfred		goto done;
1502184610Salfred	}
1503184610Salfred	/*
1504184610Salfred	 * After that the port has been reset our device should be at
1505184610Salfred	 * address zero:
1506184610Salfred	 */
1507184610Salfred	udev->address = USB_START_ADDR;
1508184610Salfred
1509185290Salfred	/* reset "bMaxPacketSize" */
1510185290Salfred	udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET;
1511185290Salfred
1512184610Salfred	/*
1513184610Salfred	 * Restore device address:
1514184610Salfred	 */
1515184610Salfred	err = usb2_req_set_address(udev, mtx, old_addr);
1516184610Salfred	if (err) {
1517184610Salfred		/* XXX ignore any errors! */
1518190739Sthompsa		DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n",
1519190739Sthompsa		    old_addr, usb2_errstr(err));
1520184610Salfred	}
1521184610Salfred	/* restore device address */
1522184610Salfred	udev->address = old_addr;
1523184610Salfred
1524184610Salfred	/* allow device time to set new address */
1525188411Sthompsa	usb2_pause_mtx(mtx, USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE));
1526184610Salfred
1527184610Salfred	/* get the device descriptor */
1528188985Sthompsa	err = usb2_req_get_desc(udev, mtx, NULL, &udev->ddesc,
1529185290Salfred	    USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0);
1530184610Salfred	if (err) {
1531185290Salfred		DPRINTFN(0, "getting device descriptor "
1532190739Sthompsa		    "at addr %d failed, %s!\n", udev->address,
1533190739Sthompsa		    usb2_errstr(err));
1534185290Salfred		goto done;
1535185290Salfred	}
1536185290Salfred	/* get the full device descriptor */
1537185290Salfred	err = usb2_req_get_device_desc(udev, mtx, &udev->ddesc);
1538185290Salfred	if (err) {
1539184610Salfred		DPRINTFN(0, "addr=%d, getting device "
1540190739Sthompsa		    "descriptor failed, %s!\n", old_addr,
1541190739Sthompsa		    usb2_errstr(err));
1542184610Salfred		goto done;
1543184610Salfred	}
1544184610Salfreddone:
1545186730Salfred	if (err && do_retry) {
1546186730Salfred		/* give the USB firmware some time to load */
1547188411Sthompsa		usb2_pause_mtx(mtx, hz / 2);
1548186730Salfred		/* no more retries after this retry */
1549186730Salfred		do_retry = 0;
1550186730Salfred		/* try again */
1551186730Salfred		goto retry;
1552186730Salfred	}
1553184610Salfred	/* restore address */
1554184610Salfred	udev->address = old_addr;
1555184610Salfred	return (err);
1556184610Salfred}
1557186730Salfred
1558186730Salfred/*------------------------------------------------------------------------*
1559186730Salfred *	usb2_req_clear_device_feature
1560186730Salfred *
1561186730Salfred * Returns:
1562186730Salfred *    0: Success
1563186730Salfred * Else: Failure
1564186730Salfred *------------------------------------------------------------------------*/
1565186730Salfredusb2_error_t
1566186730Salfredusb2_req_clear_device_feature(struct usb2_device *udev, struct mtx *mtx,
1567186730Salfred    uint16_t sel)
1568186730Salfred{
1569186730Salfred	struct usb2_device_request req;
1570186730Salfred
1571186730Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1572186730Salfred	req.bRequest = UR_CLEAR_FEATURE;
1573186730Salfred	USETW(req.wValue, sel);
1574186730Salfred	USETW(req.wIndex, 0);
1575186730Salfred	USETW(req.wLength, 0);
1576186730Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1577186730Salfred}
1578186730Salfred
1579186730Salfred/*------------------------------------------------------------------------*
1580186730Salfred *	usb2_req_set_device_feature
1581186730Salfred *
1582186730Salfred * Returns:
1583186730Salfred *    0: Success
1584186730Salfred * Else: Failure
1585186730Salfred *------------------------------------------------------------------------*/
1586186730Salfredusb2_error_t
1587186730Salfredusb2_req_set_device_feature(struct usb2_device *udev, struct mtx *mtx,
1588186730Salfred    uint16_t sel)
1589186730Salfred{
1590186730Salfred	struct usb2_device_request req;
1591186730Salfred
1592186730Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1593186730Salfred	req.bRequest = UR_SET_FEATURE;
1594186730Salfred	USETW(req.wValue, sel);
1595186730Salfred	USETW(req.wIndex, 0);
1596186730Salfred	USETW(req.wLength, 0);
1597186730Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1598186730Salfred}
1599