usb_request.c revision 185290
1184610Salfred/* $FreeBSD: head/sys/dev/usb2/core/usb2_request.c 185290 2008-11-25 08:04:40Z alfred $ */
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.
27184610Salfred */
28184610Salfred
29184610Salfred#include <dev/usb2/include/usb2_defs.h>
30184610Salfred#include <dev/usb2/include/usb2_mfunc.h>
31184610Salfred#include <dev/usb2/include/usb2_error.h>
32184610Salfred#include <dev/usb2/include/usb2_standard.h>
33184610Salfred#include <dev/usb2/include/usb2_ioctl.h>
34184610Salfred#include <dev/usb2/include/usb2_hid.h>
35184610Salfred
36184610Salfred#define	USB_DEBUG_VAR usb2_debug
37184610Salfred
38184610Salfred#include <dev/usb2/core/usb2_core.h>
39184610Salfred#include <dev/usb2/core/usb2_busdma.h>
40184610Salfred#include <dev/usb2/core/usb2_request.h>
41184610Salfred#include <dev/usb2/core/usb2_process.h>
42184610Salfred#include <dev/usb2/core/usb2_transfer.h>
43184610Salfred#include <dev/usb2/core/usb2_debug.h>
44184610Salfred#include <dev/usb2/core/usb2_device.h>
45184610Salfred#include <dev/usb2/core/usb2_util.h>
46184610Salfred#include <dev/usb2/core/usb2_dynamic.h>
47184610Salfred
48184824Sthompsa#include <dev/usb2/controller/usb2_controller.h>
49184824Sthompsa#include <dev/usb2/controller/usb2_bus.h>
50184610Salfred#include <sys/ctype.h>
51184610Salfred
52184610Salfred#if USB_DEBUG
53184610Salfredstatic int usb2_pr_poll_delay = USB_PORT_RESET_DELAY;
54184610Salfredstatic int usb2_pr_recovery_delay = USB_PORT_RESET_RECOVERY;
55184610Salfredstatic int usb2_ss_delay = 0;
56184610Salfred
57184610SalfredSYSCTL_INT(_hw_usb2, OID_AUTO, pr_poll_delay, CTLFLAG_RW,
58184610Salfred    &usb2_pr_poll_delay, 0, "USB port reset poll delay in ms");
59184610SalfredSYSCTL_INT(_hw_usb2, OID_AUTO, pr_recovery_delay, CTLFLAG_RW,
60184610Salfred    &usb2_pr_recovery_delay, 0, "USB port reset recovery delay in ms");
61184610SalfredSYSCTL_INT(_hw_usb2, OID_AUTO, ss_delay, CTLFLAG_RW,
62184610Salfred    &usb2_ss_delay, 0, "USB status stage delay in ms");
63184610Salfred#endif
64184610Salfred
65184610Salfred/*------------------------------------------------------------------------*
66184610Salfred *	usb2_do_request_callback
67184610Salfred *
68184610Salfred * This function is the USB callback for generic USB Host control
69184610Salfred * transfers.
70184610Salfred *------------------------------------------------------------------------*/
71184610Salfredvoid
72184610Salfredusb2_do_request_callback(struct usb2_xfer *xfer)
73184610Salfred{
74184610Salfred	;				/* workaround for a bug in "indent" */
75184610Salfred
76184610Salfred	DPRINTF("st=%u\n", USB_GET_STATE(xfer));
77184610Salfred
78184610Salfred	switch (USB_GET_STATE(xfer)) {
79184610Salfred	case USB_ST_SETUP:
80184610Salfred		usb2_start_hardware(xfer);
81184610Salfred		break;
82184610Salfred	default:
83184610Salfred		usb2_cv_signal(xfer->udev->default_cv);
84184610Salfred		break;
85184610Salfred	}
86184610Salfred	return;
87184610Salfred}
88184610Salfred
89184610Salfred/*------------------------------------------------------------------------*
90184610Salfred *	usb2_do_clear_stall_callback
91184610Salfred *
92184610Salfred * This function is the USB callback for generic clear stall requests.
93184610Salfred *------------------------------------------------------------------------*/
94184610Salfredvoid
95184610Salfredusb2_do_clear_stall_callback(struct usb2_xfer *xfer)
96184610Salfred{
97184610Salfred	struct usb2_device_request req;
98184610Salfred	struct usb2_pipe *pipe;
99184610Salfred	struct usb2_pipe *pipe_end;
100184610Salfred	struct usb2_pipe *pipe_first;
101184610Salfred	uint8_t to = USB_EP_MAX;
102184610Salfred
103184824Sthompsa	USB_BUS_LOCK(xfer->udev->bus);
104184610Salfred
105184610Salfred	/* round robin pipe clear stall */
106184610Salfred
107184610Salfred	pipe = xfer->udev->pipe_curr;
108184610Salfred	pipe_end = xfer->udev->pipes + USB_EP_MAX;
109184610Salfred	pipe_first = xfer->udev->pipes;
110184610Salfred	if (pipe == NULL) {
111184610Salfred		pipe = pipe_first;
112184610Salfred	}
113184610Salfred	switch (USB_GET_STATE(xfer)) {
114184610Salfred	case USB_ST_TRANSFERRED:
115184610Salfred		if (pipe->edesc &&
116184610Salfred		    pipe->is_stalled) {
117184610Salfred			pipe->toggle_next = 0;
118184610Salfred			pipe->is_stalled = 0;
119184610Salfred			/* start up the current or next transfer, if any */
120184610Salfred			usb2_command_wrapper(&pipe->pipe_q,
121184610Salfred			    pipe->pipe_q.curr);
122184610Salfred		}
123184610Salfred		pipe++;
124184610Salfred
125184610Salfred	case USB_ST_SETUP:
126184610Salfredtr_setup:
127184610Salfred		if (pipe == pipe_end) {
128184610Salfred			pipe = pipe_first;
129184610Salfred		}
130184610Salfred		if (pipe->edesc &&
131184610Salfred		    pipe->is_stalled) {
132184610Salfred
133184610Salfred			/* setup a clear-stall packet */
134184610Salfred
135184610Salfred			req.bmRequestType = UT_WRITE_ENDPOINT;
136184610Salfred			req.bRequest = UR_CLEAR_FEATURE;
137184610Salfred			USETW(req.wValue, UF_ENDPOINT_HALT);
138184610Salfred			req.wIndex[0] = pipe->edesc->bEndpointAddress;
139184610Salfred			req.wIndex[1] = 0;
140184610Salfred			USETW(req.wLength, 0);
141184610Salfred
142184610Salfred			/* copy in the transfer */
143184610Salfred
144184610Salfred			usb2_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
145184610Salfred
146184610Salfred			/* set length */
147184610Salfred			xfer->frlengths[0] = sizeof(req);
148184610Salfred			xfer->nframes = 1;
149184824Sthompsa			USB_BUS_UNLOCK(xfer->udev->bus);
150184610Salfred
151184610Salfred			usb2_start_hardware(xfer);
152184610Salfred
153184824Sthompsa			USB_BUS_LOCK(xfer->udev->bus);
154184610Salfred			break;
155184610Salfred		}
156184610Salfred		pipe++;
157184610Salfred		if (--to)
158184610Salfred			goto tr_setup;
159184610Salfred		break;
160184610Salfred
161184610Salfred	default:
162184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
163184610Salfred			break;
164184610Salfred		}
165184610Salfred		goto tr_setup;
166184610Salfred	}
167184610Salfred
168184610Salfred	/* store current pipe */
169184610Salfred	xfer->udev->pipe_curr = pipe;
170184824Sthompsa	USB_BUS_UNLOCK(xfer->udev->bus);
171184610Salfred	return;
172184610Salfred}
173184610Salfred
174184610Salfred/*------------------------------------------------------------------------*
175184610Salfred *	usb2_do_request_flags and usb2_do_request
176184610Salfred *
177184610Salfred * Description of arguments passed to these functions:
178184610Salfred *
179184610Salfred * "udev" - this is the "usb2_device" structure pointer on which the
180184610Salfred * request should be performed. It is possible to call this function
181184610Salfred * in both Host Side mode and Device Side mode.
182184610Salfred *
183184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it
184184610Salfred * will get dropped and picked up during the execution of this
185184610Salfred * function, hence this function sometimes needs to sleep. If this
186184610Salfred * argument is NULL it has no effect.
187184610Salfred *
188184610Salfred * "req" - this argument must always be non-NULL and points to an
189184610Salfred * 8-byte structure holding the USB request to be done. The USB
190184610Salfred * request structure has a bit telling the direction of the USB
191184610Salfred * request, if it is a read or a write.
192184610Salfred *
193184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req"
194184610Salfred * is non-zero this argument must point to a valid kernel buffer which
195184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can
196184610Salfred * be NULL.
197184610Salfred *
198184610Salfred * "flags" - here is a list of valid flags:
199184610Salfred *
200184610Salfred *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
201184610Salfred *  specified
202184610Salfred *
203184610Salfred *  o USB_USE_POLLING: forces the transfer to complete from the
204184610Salfred *  current context by polling the interrupt handler. This flag can be
205184610Salfred *  used to perform USB transfers after that the kernel has crashed.
206184610Salfred *
207184610Salfred *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
208184610Salfred *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
209184610Salfred *  sysctl. This flag is mostly useful for debugging.
210184610Salfred *
211184610Salfred *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
212184610Salfred *  pointer.
213184610Salfred *
214184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in
215184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This
216184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
217184610Salfred * used.
218184610Salfred *
219184610Salfred * "timeout" - gives the timeout for the control transfer in
220184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is
221184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater
222184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack
223184610Salfred * does not allow control requests without a timeout.
224184610Salfred *
225184610Salfred * NOTE: This function is thread safe. All calls to
226184610Salfred * "usb2_do_request_flags" will be serialised by the use of an
227184610Salfred * internal "sx_lock".
228184610Salfred *
229184610Salfred * Returns:
230184610Salfred *    0: Success
231184610Salfred * Else: Failure
232184610Salfred *------------------------------------------------------------------------*/
233184610Salfredusb2_error_t
234184610Salfredusb2_do_request_flags(struct usb2_device *udev, struct mtx *mtx,
235184610Salfred    struct usb2_device_request *req, void *data, uint32_t flags,
236184610Salfred    uint16_t *actlen, uint32_t timeout)
237184610Salfred{
238184610Salfred	struct usb2_xfer *xfer;
239184610Salfred	const void *desc;
240184610Salfred	int err = 0;
241184610Salfred	uint32_t start_ticks;
242184610Salfred	uint32_t delta_ticks;
243184610Salfred	uint32_t max_ticks;
244184610Salfred	uint16_t length;
245184610Salfred	uint16_t temp;
246184610Salfred
247184610Salfred	if (timeout < 50) {
248184610Salfred		/* timeout is too small */
249184610Salfred		timeout = 50;
250184610Salfred	}
251184610Salfred	if (timeout > 30000) {
252184610Salfred		/* timeout is too big */
253184610Salfred		timeout = 30000;
254184610Salfred	}
255184610Salfred	length = UGETW(req->wLength);
256184610Salfred
257184610Salfred	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
258184610Salfred	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
259184610Salfred	    udev, req->bmRequestType, req->bRequest,
260184610Salfred	    req->wValue[1], req->wValue[0],
261184610Salfred	    req->wIndex[1], req->wIndex[0],
262184610Salfred	    req->wLength[1], req->wLength[0]);
263184610Salfred
264184610Salfred	/*
265184610Salfred	 * Set "actlen" to a known value in case the caller does not
266184610Salfred	 * check the return value:
267184610Salfred	 */
268184610Salfred	if (actlen) {
269184610Salfred		*actlen = 0;
270184610Salfred	}
271184610Salfred	if (udev->flags.usb2_mode == USB_MODE_DEVICE) {
272184610Salfred		DPRINTF("USB device mode\n");
273184610Salfred		(usb2_temp_get_desc_p) (udev, req, &desc, &temp);
274184610Salfred		if (length > temp) {
275184610Salfred			if (!(flags & USB_SHORT_XFER_OK)) {
276184610Salfred				return (USB_ERR_SHORT_XFER);
277184610Salfred			}
278184610Salfred			length = temp;
279184610Salfred		}
280184610Salfred		if (actlen) {
281184610Salfred			*actlen = length;
282184610Salfred		}
283184610Salfred		if (length > 0) {
284184610Salfred			if (flags & USB_USER_DATA_PTR) {
285184610Salfred				if (copyout(desc, data, length)) {
286184610Salfred					return (USB_ERR_INVAL);
287184610Salfred				}
288184610Salfred			} else {
289184610Salfred				bcopy(desc, data, length);
290184610Salfred			}
291184610Salfred		}
292184610Salfred		return (0);		/* success */
293184610Salfred	}
294184610Salfred	if (mtx) {
295184610Salfred		mtx_unlock(mtx);
296184610Salfred		if (mtx != &Giant) {
297184610Salfred			mtx_assert(mtx, MA_NOTOWNED);
298184610Salfred		}
299184610Salfred	}
300184610Salfred	/*
301184610Salfred	 * Grab the default sx-lock so that serialisation
302184610Salfred	 * is achieved when multiple threads are involved:
303184610Salfred	 */
304184610Salfred
305184610Salfred	sx_xlock(udev->default_sx);
306184610Salfred
307184610Salfred	/*
308184610Salfred	 * Setup a new USB transfer or use the existing one, if any:
309184610Salfred	 */
310184610Salfred	usb2_default_transfer_setup(udev);
311184610Salfred
312184610Salfred	xfer = udev->default_xfer[0];
313184610Salfred	if (xfer == NULL) {
314184610Salfred		/* most likely out of memory */
315184610Salfred		err = USB_ERR_NOMEM;
316184610Salfred		goto done;
317184610Salfred	}
318184824Sthompsa	USB_XFER_LOCK(xfer);
319184610Salfred
320184610Salfred	if (flags & USB_DELAY_STATUS_STAGE) {
321184610Salfred		xfer->flags.manual_status = 1;
322184610Salfred	} else {
323184610Salfred		xfer->flags.manual_status = 0;
324184610Salfred	}
325184610Salfred
326184610Salfred	xfer->timeout = timeout;
327184610Salfred
328184610Salfred	start_ticks = ticks;
329184610Salfred
330184610Salfred	max_ticks = USB_MS_TO_TICKS(timeout);
331184610Salfred
332184610Salfred	usb2_copy_in(xfer->frbuffers, 0, req, sizeof(*req));
333184610Salfred
334184610Salfred	xfer->frlengths[0] = sizeof(*req);
335184610Salfred	xfer->nframes = 2;
336184610Salfred
337184610Salfred	while (1) {
338184610Salfred		temp = length;
339184610Salfred		if (temp > xfer->max_data_length) {
340184610Salfred			temp = xfer->max_data_length;
341184610Salfred		}
342184610Salfred		xfer->frlengths[1] = temp;
343184610Salfred
344184610Salfred		if (temp > 0) {
345184610Salfred			if (!(req->bmRequestType & UT_READ)) {
346184610Salfred				if (flags & USB_USER_DATA_PTR) {
347184824Sthompsa					USB_XFER_UNLOCK(xfer);
348184610Salfred					err = usb2_copy_in_user(xfer->frbuffers + 1,
349184610Salfred					    0, data, temp);
350184824Sthompsa					USB_XFER_LOCK(xfer);
351184610Salfred					if (err) {
352184610Salfred						err = USB_ERR_INVAL;
353184610Salfred						break;
354184610Salfred					}
355184610Salfred				} else {
356184610Salfred					usb2_copy_in(xfer->frbuffers + 1, 0, data, temp);
357184610Salfred				}
358184610Salfred			}
359184610Salfred			xfer->nframes = 2;
360184610Salfred		} else {
361184610Salfred			if (xfer->frlengths[0] == 0) {
362184610Salfred				if (xfer->flags.manual_status) {
363184610Salfred#if USB_DEBUG
364184610Salfred					int temp;
365184610Salfred
366184610Salfred					temp = usb2_ss_delay;
367184610Salfred					if (temp > 5000) {
368184610Salfred						temp = 5000;
369184610Salfred					}
370184610Salfred					if (temp > 0) {
371184610Salfred						usb2_pause_mtx(
372184824Sthompsa						    xfer->xfer_mtx, temp);
373184610Salfred					}
374184610Salfred#endif
375184610Salfred					xfer->flags.manual_status = 0;
376184610Salfred				} else {
377184610Salfred					break;
378184610Salfred				}
379184610Salfred			}
380184610Salfred			xfer->nframes = 1;
381184610Salfred		}
382184610Salfred
383184610Salfred		usb2_transfer_start(xfer);
384184610Salfred
385184610Salfred		while (usb2_transfer_pending(xfer)) {
386184610Salfred			if ((flags & USB_USE_POLLING) || cold) {
387184610Salfred				usb2_do_poll(udev->default_xfer, USB_DEFAULT_XFER_MAX);
388184610Salfred			} else {
389184824Sthompsa				usb2_cv_wait(xfer->udev->default_cv,
390184824Sthompsa				    xfer->xfer_mtx);
391184610Salfred			}
392184610Salfred		}
393184610Salfred
394184610Salfred		err = xfer->error;
395184610Salfred
396184610Salfred		if (err) {
397184610Salfred			break;
398184610Salfred		}
399184610Salfred		/* subtract length of SETUP packet, if any */
400184610Salfred
401184610Salfred		if (xfer->aframes > 0) {
402184610Salfred			xfer->actlen -= xfer->frlengths[0];
403184610Salfred		} else {
404184610Salfred			xfer->actlen = 0;
405184610Salfred		}
406184610Salfred
407184610Salfred		/* check for short packet */
408184610Salfred
409184610Salfred		if (temp > xfer->actlen) {
410184610Salfred			temp = xfer->actlen;
411184610Salfred			if (!(flags & USB_SHORT_XFER_OK)) {
412184610Salfred				err = USB_ERR_SHORT_XFER;
413184610Salfred			}
414184610Salfred			length = temp;
415184610Salfred		}
416184610Salfred		if (temp > 0) {
417184610Salfred			if (req->bmRequestType & UT_READ) {
418184610Salfred				if (flags & USB_USER_DATA_PTR) {
419184824Sthompsa					USB_XFER_UNLOCK(xfer);
420184610Salfred					err = usb2_copy_out_user(xfer->frbuffers + 1,
421184610Salfred					    0, data, temp);
422184824Sthompsa					USB_XFER_LOCK(xfer);
423184610Salfred					if (err) {
424184610Salfred						err = USB_ERR_INVAL;
425184610Salfred						break;
426184610Salfred					}
427184610Salfred				} else {
428184610Salfred					usb2_copy_out(xfer->frbuffers + 1,
429184610Salfred					    0, data, temp);
430184610Salfred				}
431184610Salfred			}
432184610Salfred		}
433184610Salfred		/*
434184610Salfred		 * Clear "frlengths[0]" so that we don't send the setup
435184610Salfred		 * packet again:
436184610Salfred		 */
437184610Salfred		xfer->frlengths[0] = 0;
438184610Salfred
439184610Salfred		/* update length and data pointer */
440184610Salfred		length -= temp;
441184610Salfred		data = USB_ADD_BYTES(data, temp);
442184610Salfred
443184610Salfred		if (actlen) {
444184610Salfred			(*actlen) += temp;
445184610Salfred		}
446184610Salfred		/* check for timeout */
447184610Salfred
448184610Salfred		delta_ticks = ticks - start_ticks;
449184610Salfred		if (delta_ticks > max_ticks) {
450184610Salfred			if (!err) {
451184610Salfred				err = USB_ERR_TIMEOUT;
452184610Salfred			}
453184610Salfred		}
454184610Salfred		if (err) {
455184610Salfred			break;
456184610Salfred		}
457184610Salfred	}
458184610Salfred
459184610Salfred	if (err) {
460184610Salfred		/*
461184610Salfred		 * Make sure that the control endpoint is no longer
462184610Salfred		 * blocked in case of a non-transfer related error:
463184610Salfred		 */
464184610Salfred		usb2_transfer_stop(xfer);
465184610Salfred	}
466184824Sthompsa	USB_XFER_UNLOCK(xfer);
467184610Salfred
468184610Salfreddone:
469184610Salfred	sx_xunlock(udev->default_sx);
470184610Salfred
471184610Salfred	if (mtx) {
472184610Salfred		mtx_lock(mtx);
473184610Salfred	}
474184610Salfred	return ((usb2_error_t)err);
475184610Salfred}
476184610Salfred
477184610Salfred/*------------------------------------------------------------------------*
478184610Salfred *	usb2_req_reset_port
479184610Salfred *
480184610Salfred * This function will instruct an USB HUB to perform a reset sequence
481184610Salfred * on the specified port number.
482184610Salfred *
483184610Salfred * Returns:
484184610Salfred *    0: Success. The USB device should now be at address zero.
485184610Salfred * Else: Failure. No USB device is present and the USB port should be
486184610Salfred *       disabled.
487184610Salfred *------------------------------------------------------------------------*/
488184610Salfredusb2_error_t
489184610Salfredusb2_req_reset_port(struct usb2_device *udev, struct mtx *mtx, uint8_t port)
490184610Salfred{
491184610Salfred	struct usb2_port_status ps;
492184610Salfred	usb2_error_t err;
493184610Salfred	uint16_t n;
494184610Salfred
495184610Salfred#if USB_DEBUG
496184610Salfred	uint16_t pr_poll_delay;
497184610Salfred	uint16_t pr_recovery_delay;
498184610Salfred
499184610Salfred#endif
500184610Salfred	err = usb2_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
501184610Salfred	if (err) {
502184610Salfred		goto done;
503184610Salfred	}
504184610Salfred#if USB_DEBUG
505184610Salfred	/* range check input parameters */
506184610Salfred	pr_poll_delay = usb2_pr_poll_delay;
507184610Salfred	if (pr_poll_delay < 1) {
508184610Salfred		pr_poll_delay = 1;
509184610Salfred	} else if (pr_poll_delay > 1000) {
510184610Salfred		pr_poll_delay = 1000;
511184610Salfred	}
512184610Salfred	pr_recovery_delay = usb2_pr_recovery_delay;
513184610Salfred	if (pr_recovery_delay > 1000) {
514184610Salfred		pr_recovery_delay = 1000;
515184610Salfred	}
516184610Salfred#endif
517184610Salfred	n = 0;
518184610Salfred	while (1) {
519184610Salfred#if USB_DEBUG
520184610Salfred		/* wait for the device to recover from reset */
521184610Salfred		usb2_pause_mtx(mtx, pr_poll_delay);
522184610Salfred		n += pr_poll_delay;
523184610Salfred#else
524184610Salfred		/* wait for the device to recover from reset */
525184610Salfred		usb2_pause_mtx(mtx, USB_PORT_RESET_DELAY);
526184610Salfred		n += USB_PORT_RESET_DELAY;
527184610Salfred#endif
528184610Salfred		err = usb2_req_get_port_status(udev, mtx, &ps, port);
529184610Salfred		if (err) {
530184610Salfred			goto done;
531184610Salfred		}
532184610Salfred		/* if the device disappeared, just give up */
533184610Salfred		if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
534184610Salfred			goto done;
535184610Salfred		}
536184610Salfred		/* check if reset is complete */
537184610Salfred		if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
538184610Salfred			break;
539184610Salfred		}
540184610Salfred		/* check for timeout */
541184610Salfred		if (n > 1000) {
542184610Salfred			n = 0;
543184610Salfred			break;
544184610Salfred		}
545184610Salfred	}
546184610Salfred
547184610Salfred	/* clear port reset first */
548184610Salfred	err = usb2_req_clear_port_feature(
549184610Salfred	    udev, mtx, port, UHF_C_PORT_RESET);
550184610Salfred	if (err) {
551184610Salfred		goto done;
552184610Salfred	}
553184610Salfred	/* check for timeout */
554184610Salfred	if (n == 0) {
555184610Salfred		err = USB_ERR_TIMEOUT;
556184610Salfred		goto done;
557184610Salfred	}
558184610Salfred#if USB_DEBUG
559184610Salfred	/* wait for the device to recover from reset */
560184610Salfred	usb2_pause_mtx(mtx, pr_recovery_delay);
561184610Salfred#else
562184610Salfred	/* wait for the device to recover from reset */
563184610Salfred	usb2_pause_mtx(mtx, USB_PORT_RESET_RECOVERY);
564184610Salfred#endif
565184610Salfred
566184610Salfreddone:
567184610Salfred	DPRINTFN(2, "port %d reset returning error=%s\n",
568184610Salfred	    port, usb2_errstr(err));
569184610Salfred	return (err);
570184610Salfred}
571184610Salfred
572184610Salfred/*------------------------------------------------------------------------*
573184610Salfred *	usb2_req_get_desc
574184610Salfred *
575184610Salfred * This function can be used to retrieve USB descriptors. It contains
576184610Salfred * some additional logic like zeroing of missing descriptor bytes and
577184610Salfred * retrying an USB descriptor in case of failure. The "min_len"
578184610Salfred * argument specifies the minimum descriptor length. The "max_len"
579184610Salfred * argument specifies the maximum descriptor length. If the real
580184610Salfred * descriptor length is less than the minimum length the missing
581184610Salfred * byte(s) will be zeroed. The length field, first byte, of the USB
582184610Salfred * descriptor will get overwritten in case it indicates a length that
583184610Salfred * is too big. Also the type field, second byte, of the USB descriptor
584184610Salfred * will get forced to the correct type.
585184610Salfred *
586184610Salfred * Returns:
587184610Salfred *    0: Success
588184610Salfred * Else: Failure
589184610Salfred *------------------------------------------------------------------------*/
590184610Salfredusb2_error_t
591184610Salfredusb2_req_get_desc(struct usb2_device *udev, struct mtx *mtx, void *desc,
592184610Salfred    uint16_t min_len, uint16_t max_len,
593184610Salfred    uint16_t id, uint8_t type, uint8_t index,
594184610Salfred    uint8_t retries)
595184610Salfred{
596184610Salfred	struct usb2_device_request req;
597184610Salfred	uint8_t *buf;
598184610Salfred	usb2_error_t err;
599184610Salfred
600184610Salfred	DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n",
601184610Salfred	    id, type, index, max_len);
602184610Salfred
603184610Salfred	req.bmRequestType = UT_READ_DEVICE;
604184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
605184610Salfred	USETW2(req.wValue, type, index);
606184610Salfred	USETW(req.wIndex, id);
607184610Salfred
608184610Salfred	while (1) {
609184610Salfred
610184610Salfred		if ((min_len < 2) || (max_len < 2)) {
611184610Salfred			err = USB_ERR_INVAL;
612184610Salfred			goto done;
613184610Salfred		}
614184610Salfred		USETW(req.wLength, min_len);
615184610Salfred
616184610Salfred		err = usb2_do_request(udev, mtx, &req, desc);
617184610Salfred
618184610Salfred		if (err) {
619184610Salfred			if (!retries) {
620184610Salfred				goto done;
621184610Salfred			}
622184610Salfred			retries--;
623184610Salfred
624184610Salfred			usb2_pause_mtx(mtx, 200);
625184610Salfred
626184610Salfred			continue;
627184610Salfred		}
628184610Salfred		buf = desc;
629184610Salfred
630184610Salfred		if (min_len == max_len) {
631184610Salfred
632184610Salfred			/* enforce correct type and length */
633184610Salfred
634184610Salfred			if (buf[0] > min_len) {
635184610Salfred				buf[0] = min_len;
636184610Salfred			}
637184610Salfred			buf[1] = type;
638184610Salfred
639184610Salfred			goto done;
640184610Salfred		}
641184610Salfred		/* range check */
642184610Salfred
643184610Salfred		if (max_len > buf[0]) {
644184610Salfred			max_len = buf[0];
645184610Salfred		}
646184610Salfred		/* zero minimum data */
647184610Salfred
648184610Salfred		while (min_len > max_len) {
649184610Salfred			min_len--;
650184610Salfred			buf[min_len] = 0;
651184610Salfred		}
652184610Salfred
653184610Salfred		/* set new minimum length */
654184610Salfred
655184610Salfred		min_len = max_len;
656184610Salfred	}
657184610Salfreddone:
658184610Salfred	return (err);
659184610Salfred}
660184610Salfred
661184610Salfred/*------------------------------------------------------------------------*
662184610Salfred *	usb2_req_get_string_any
663184610Salfred *
664184610Salfred * This function will return the string given by "string_index"
665184610Salfred * using the first language ID. The maximum length "len" includes
666184610Salfred * the terminating zero. The "len" argument should be twice as
667184610Salfred * big pluss 2 bytes, compared with the actual maximum string length !
668184610Salfred *
669184610Salfred * Returns:
670184610Salfred *    0: Success
671184610Salfred * Else: Failure
672184610Salfred *------------------------------------------------------------------------*/
673184610Salfredusb2_error_t
674184610Salfredusb2_req_get_string_any(struct usb2_device *udev, struct mtx *mtx, char *buf,
675184610Salfred    uint16_t len, uint8_t string_index)
676184610Salfred{
677184610Salfred	char *s;
678184610Salfred	uint8_t *temp;
679184610Salfred	uint16_t i;
680184610Salfred	uint16_t n;
681184610Salfred	uint16_t c;
682184610Salfred	uint8_t swap;
683184610Salfred	usb2_error_t err;
684184610Salfred
685184610Salfred	if (len == 0) {
686184610Salfred		/* should not happen */
687184610Salfred		return (USB_ERR_NORMAL_COMPLETION);
688184610Salfred	}
689184610Salfred	if (string_index == 0) {
690184610Salfred		/* this is the language table */
691185087Salfred		buf[0] = 0;
692184610Salfred		return (USB_ERR_INVAL);
693184610Salfred	}
694184610Salfred	if (udev->flags.no_strings) {
695185087Salfred		buf[0] = 0;
696184610Salfred		return (USB_ERR_STALLED);
697184610Salfred	}
698184610Salfred	err = usb2_req_get_string_desc
699184610Salfred	    (udev, mtx, buf, len, udev->langid, string_index);
700184610Salfred	if (err) {
701185087Salfred		buf[0] = 0;
702184610Salfred		return (err);
703184610Salfred	}
704184610Salfred	temp = (uint8_t *)buf;
705184610Salfred
706184610Salfred	if (temp[0] < 2) {
707184610Salfred		/* string length is too short */
708185087Salfred		buf[0] = 0;
709184610Salfred		return (USB_ERR_INVAL);
710184610Salfred	}
711184610Salfred	/* reserve one byte for terminating zero */
712184610Salfred	len--;
713184610Salfred
714184610Salfred	/* find maximum length */
715184610Salfred	s = buf;
716184610Salfred	n = (temp[0] / 2) - 1;
717184610Salfred	if (n > len) {
718184610Salfred		n = len;
719184610Salfred	}
720184610Salfred	/* skip descriptor header */
721184610Salfred	temp += 2;
722184610Salfred
723184610Salfred	/* reset swap state */
724184610Salfred	swap = 3;
725184610Salfred
726184610Salfred	/* convert and filter */
727184610Salfred	for (i = 0; (i != n); i++) {
728184610Salfred		c = UGETW(temp + (2 * i));
729184610Salfred
730184610Salfred		/* convert from Unicode, handle buggy strings */
731184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
732184610Salfred			/* Little Endian, default */
733184610Salfred			*s = c;
734184610Salfred			swap = 1;
735184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
736184610Salfred			/* Big Endian */
737184610Salfred			*s = c >> 8;
738184610Salfred			swap = 2;
739184610Salfred		} else {
740185087Salfred			/* silently skip bad character */
741185087Salfred			continue;
742184610Salfred		}
743184610Salfred
744184610Salfred		/*
745184610Salfred		 * Filter by default - we don't allow greater and less than
746184610Salfred		 * signs because they might confuse the dmesg printouts!
747184610Salfred		 */
748184610Salfred		if ((*s == '<') || (*s == '>') || (!isprint(*s))) {
749185087Salfred			/* silently skip bad character */
750185087Salfred			continue;
751184610Salfred		}
752184610Salfred		s++;
753184610Salfred	}
754185087Salfred	*s = 0;				/* zero terminate resulting string */
755184610Salfred	return (USB_ERR_NORMAL_COMPLETION);
756184610Salfred}
757184610Salfred
758184610Salfred/*------------------------------------------------------------------------*
759184610Salfred *	usb2_req_get_string_desc
760184610Salfred *
761184610Salfred * If you don't know the language ID, consider using
762184610Salfred * "usb2_req_get_string_any()".
763184610Salfred *
764184610Salfred * Returns:
765184610Salfred *    0: Success
766184610Salfred * Else: Failure
767184610Salfred *------------------------------------------------------------------------*/
768184610Salfredusb2_error_t
769184610Salfredusb2_req_get_string_desc(struct usb2_device *udev, struct mtx *mtx, void *sdesc,
770184610Salfred    uint16_t max_len, uint16_t lang_id,
771184610Salfred    uint8_t string_index)
772184610Salfred{
773184610Salfred	return (usb2_req_get_desc(udev, mtx, sdesc, 2, max_len, lang_id,
774184610Salfred	    UDESC_STRING, string_index, 0));
775184610Salfred}
776184610Salfred
777184610Salfred/*------------------------------------------------------------------------*
778184610Salfred *	usb2_req_get_config_desc
779184610Salfred *
780184610Salfred * Returns:
781184610Salfred *    0: Success
782184610Salfred * Else: Failure
783184610Salfred *------------------------------------------------------------------------*/
784184610Salfredusb2_error_t
785184610Salfredusb2_req_get_config_desc(struct usb2_device *udev, struct mtx *mtx,
786184610Salfred    struct usb2_config_descriptor *d, uint8_t conf_index)
787184610Salfred{
788184610Salfred	usb2_error_t err;
789184610Salfred
790184610Salfred	DPRINTFN(4, "confidx=%d\n", conf_index);
791184610Salfred
792184610Salfred	err = usb2_req_get_desc(udev, mtx, d, sizeof(*d),
793184610Salfred	    sizeof(*d), 0, UDESC_CONFIG, conf_index, 0);
794184610Salfred	if (err) {
795184610Salfred		goto done;
796184610Salfred	}
797184610Salfred	/* Extra sanity checking */
798184610Salfred	if (UGETW(d->wTotalLength) < sizeof(*d)) {
799184610Salfred		err = USB_ERR_INVAL;
800184610Salfred	}
801184610Salfreddone:
802184610Salfred	return (err);
803184610Salfred}
804184610Salfred
805184610Salfred/*------------------------------------------------------------------------*
806184610Salfred *	usb2_req_get_config_desc_full
807184610Salfred *
808184610Salfred * This function gets the complete USB configuration descriptor and
809184610Salfred * ensures that "wTotalLength" is correct.
810184610Salfred *
811184610Salfred * Returns:
812184610Salfred *    0: Success
813184610Salfred * Else: Failure
814184610Salfred *------------------------------------------------------------------------*/
815184610Salfredusb2_error_t
816184610Salfredusb2_req_get_config_desc_full(struct usb2_device *udev, struct mtx *mtx,
817184610Salfred    struct usb2_config_descriptor **ppcd, struct malloc_type *mtype,
818184610Salfred    uint8_t index)
819184610Salfred{
820184610Salfred	struct usb2_config_descriptor cd;
821184610Salfred	struct usb2_config_descriptor *cdesc;
822184610Salfred	uint16_t len;
823184610Salfred	usb2_error_t err;
824184610Salfred
825184610Salfred	DPRINTFN(4, "index=%d\n", index);
826184610Salfred
827184610Salfred	*ppcd = NULL;
828184610Salfred
829184610Salfred	err = usb2_req_get_config_desc(udev, mtx, &cd, index);
830184610Salfred	if (err) {
831184610Salfred		return (err);
832184610Salfred	}
833184610Salfred	/* get full descriptor */
834184610Salfred	len = UGETW(cd.wTotalLength);
835184610Salfred	if (len < sizeof(*cdesc)) {
836184610Salfred		/* corrupt descriptor */
837184610Salfred		return (USB_ERR_INVAL);
838184610Salfred	}
839184610Salfred	cdesc = malloc(len, mtype, M_WAITOK);
840184610Salfred	if (cdesc == NULL) {
841184610Salfred		return (USB_ERR_NOMEM);
842184610Salfred	}
843184610Salfred	err = usb2_req_get_desc(udev, mtx, cdesc, len, len, 0,
844184610Salfred	    UDESC_CONFIG, index, 3);
845184610Salfred	if (err) {
846184610Salfred		free(cdesc, mtype);
847184610Salfred		return (err);
848184610Salfred	}
849184610Salfred	/* make sure that the device is not fooling us: */
850184610Salfred	USETW(cdesc->wTotalLength, len);
851184610Salfred
852184610Salfred	*ppcd = cdesc;
853184610Salfred
854184610Salfred	return (0);			/* success */
855184610Salfred}
856184610Salfred
857184610Salfred/*------------------------------------------------------------------------*
858184610Salfred *	usb2_req_get_device_desc
859184610Salfred *
860184610Salfred * Returns:
861184610Salfred *    0: Success
862184610Salfred * Else: Failure
863184610Salfred *------------------------------------------------------------------------*/
864184610Salfredusb2_error_t
865184610Salfredusb2_req_get_device_desc(struct usb2_device *udev, struct mtx *mtx,
866184610Salfred    struct usb2_device_descriptor *d)
867184610Salfred{
868184610Salfred	DPRINTFN(4, "\n");
869184610Salfred	return (usb2_req_get_desc(udev, mtx, d, sizeof(*d),
870184610Salfred	    sizeof(*d), 0, UDESC_DEVICE, 0, 3));
871184610Salfred}
872184610Salfred
873184610Salfred/*------------------------------------------------------------------------*
874184610Salfred *	usb2_req_get_alt_interface_no
875184610Salfred *
876184610Salfred * Returns:
877184610Salfred *    0: Success
878184610Salfred * Else: Failure
879184610Salfred *------------------------------------------------------------------------*/
880184610Salfredusb2_error_t
881184610Salfredusb2_req_get_alt_interface_no(struct usb2_device *udev, struct mtx *mtx,
882184610Salfred    uint8_t *alt_iface_no, uint8_t iface_index)
883184610Salfred{
884184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
885184610Salfred	struct usb2_device_request req;
886184610Salfred
887184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
888184610Salfred		return (USB_ERR_INVAL);
889184610Salfred	}
890184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
891184610Salfred	req.bRequest = UR_GET_INTERFACE;
892184610Salfred	USETW(req.wValue, 0);
893184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
894184610Salfred	req.wIndex[1] = 0;
895184610Salfred	USETW(req.wLength, 1);
896184610Salfred	return (usb2_do_request(udev, mtx, &req, alt_iface_no));
897184610Salfred}
898184610Salfred
899184610Salfred/*------------------------------------------------------------------------*
900184610Salfred *	usb2_req_set_alt_interface_no
901184610Salfred *
902184610Salfred * Returns:
903184610Salfred *    0: Success
904184610Salfred * Else: Failure
905184610Salfred *------------------------------------------------------------------------*/
906184610Salfredusb2_error_t
907184610Salfredusb2_req_set_alt_interface_no(struct usb2_device *udev, struct mtx *mtx,
908184610Salfred    uint8_t iface_index, uint8_t alt_no)
909184610Salfred{
910184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
911184610Salfred	struct usb2_device_request req;
912184610Salfred
913184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
914184610Salfred		return (USB_ERR_INVAL);
915184610Salfred	}
916184610Salfred	req.bmRequestType = UT_WRITE_INTERFACE;
917184610Salfred	req.bRequest = UR_SET_INTERFACE;
918184610Salfred	req.wValue[0] = alt_no;
919184610Salfred	req.wValue[1] = 0;
920184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
921184610Salfred	req.wIndex[1] = 0;
922184610Salfred	USETW(req.wLength, 0);
923184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
924184610Salfred}
925184610Salfred
926184610Salfred/*------------------------------------------------------------------------*
927184610Salfred *	usb2_req_get_device_status
928184610Salfred *
929184610Salfred * Returns:
930184610Salfred *    0: Success
931184610Salfred * Else: Failure
932184610Salfred *------------------------------------------------------------------------*/
933184610Salfredusb2_error_t
934184610Salfredusb2_req_get_device_status(struct usb2_device *udev, struct mtx *mtx,
935184610Salfred    struct usb2_status *st)
936184610Salfred{
937184610Salfred	struct usb2_device_request req;
938184610Salfred
939184610Salfred	req.bmRequestType = UT_READ_DEVICE;
940184610Salfred	req.bRequest = UR_GET_STATUS;
941184610Salfred	USETW(req.wValue, 0);
942184610Salfred	USETW(req.wIndex, 0);
943184610Salfred	USETW(req.wLength, sizeof(*st));
944184610Salfred	return (usb2_do_request(udev, mtx, &req, st));
945184610Salfred}
946184610Salfred
947184610Salfred/*------------------------------------------------------------------------*
948184610Salfred *	usb2_req_get_hub_descriptor
949184610Salfred *
950184610Salfred * Returns:
951184610Salfred *    0: Success
952184610Salfred * Else: Failure
953184610Salfred *------------------------------------------------------------------------*/
954184610Salfredusb2_error_t
955184610Salfredusb2_req_get_hub_descriptor(struct usb2_device *udev, struct mtx *mtx,
956184610Salfred    struct usb2_hub_descriptor *hd, uint8_t nports)
957184610Salfred{
958184610Salfred	struct usb2_device_request req;
959184610Salfred	uint16_t len = (nports + 7 + (8 * 8)) / 8;
960184610Salfred
961184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
962184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
963184610Salfred	USETW2(req.wValue, UDESC_HUB, 0);
964184610Salfred	USETW(req.wIndex, 0);
965184610Salfred	USETW(req.wLength, len);
966184610Salfred	return (usb2_do_request(udev, mtx, &req, hd));
967184610Salfred}
968184610Salfred
969184610Salfred/*------------------------------------------------------------------------*
970184610Salfred *	usb2_req_get_hub_status
971184610Salfred *
972184610Salfred * Returns:
973184610Salfred *    0: Success
974184610Salfred * Else: Failure
975184610Salfred *------------------------------------------------------------------------*/
976184610Salfredusb2_error_t
977184610Salfredusb2_req_get_hub_status(struct usb2_device *udev, struct mtx *mtx,
978184610Salfred    struct usb2_hub_status *st)
979184610Salfred{
980184610Salfred	struct usb2_device_request req;
981184610Salfred
982184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
983184610Salfred	req.bRequest = UR_GET_STATUS;
984184610Salfred	USETW(req.wValue, 0);
985184610Salfred	USETW(req.wIndex, 0);
986184610Salfred	USETW(req.wLength, sizeof(struct usb2_hub_status));
987184610Salfred	return (usb2_do_request(udev, mtx, &req, st));
988184610Salfred}
989184610Salfred
990184610Salfred/*------------------------------------------------------------------------*
991184610Salfred *	usb2_req_set_address
992184610Salfred *
993184610Salfred * This function is used to set the address for an USB device. After
994184610Salfred * port reset the USB device will respond at address zero.
995184610Salfred *
996184610Salfred * Returns:
997184610Salfred *    0: Success
998184610Salfred * Else: Failure
999184610Salfred *------------------------------------------------------------------------*/
1000184610Salfredusb2_error_t
1001184610Salfredusb2_req_set_address(struct usb2_device *udev, struct mtx *mtx, uint16_t addr)
1002184610Salfred{
1003184610Salfred	struct usb2_device_request req;
1004184610Salfred
1005184610Salfred	DPRINTFN(6, "setting device address=%d\n", addr);
1006184610Salfred
1007184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1008184610Salfred	req.bRequest = UR_SET_ADDRESS;
1009184610Salfred	USETW(req.wValue, addr);
1010184610Salfred	USETW(req.wIndex, 0);
1011184610Salfred	USETW(req.wLength, 0);
1012184610Salfred
1013184610Salfred	/* Setting the address should not take more than 1 second ! */
1014184610Salfred	return (usb2_do_request_flags(udev, mtx, &req, NULL,
1015184610Salfred	    USB_DELAY_STATUS_STAGE, NULL, 1000));
1016184610Salfred}
1017184610Salfred
1018184610Salfred/*------------------------------------------------------------------------*
1019184610Salfred *	usb2_req_get_port_status
1020184610Salfred *
1021184610Salfred * Returns:
1022184610Salfred *    0: Success
1023184610Salfred * Else: Failure
1024184610Salfred *------------------------------------------------------------------------*/
1025184610Salfredusb2_error_t
1026184610Salfredusb2_req_get_port_status(struct usb2_device *udev, struct mtx *mtx,
1027184610Salfred    struct usb2_port_status *ps, uint8_t port)
1028184610Salfred{
1029184610Salfred	struct usb2_device_request req;
1030184610Salfred
1031184610Salfred	req.bmRequestType = UT_READ_CLASS_OTHER;
1032184610Salfred	req.bRequest = UR_GET_STATUS;
1033184610Salfred	USETW(req.wValue, 0);
1034184610Salfred	req.wIndex[0] = port;
1035184610Salfred	req.wIndex[1] = 0;
1036184610Salfred	USETW(req.wLength, sizeof *ps);
1037184610Salfred	return (usb2_do_request(udev, mtx, &req, ps));
1038184610Salfred}
1039184610Salfred
1040184610Salfred/*------------------------------------------------------------------------*
1041184610Salfred *	usb2_req_clear_hub_feature
1042184610Salfred *
1043184610Salfred * Returns:
1044184610Salfred *    0: Success
1045184610Salfred * Else: Failure
1046184610Salfred *------------------------------------------------------------------------*/
1047184610Salfredusb2_error_t
1048184610Salfredusb2_req_clear_hub_feature(struct usb2_device *udev, struct mtx *mtx,
1049184610Salfred    uint16_t sel)
1050184610Salfred{
1051184610Salfred	struct usb2_device_request req;
1052184610Salfred
1053184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1054184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1055184610Salfred	USETW(req.wValue, sel);
1056184610Salfred	USETW(req.wIndex, 0);
1057184610Salfred	USETW(req.wLength, 0);
1058184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1059184610Salfred}
1060184610Salfred
1061184610Salfred/*------------------------------------------------------------------------*
1062184610Salfred *	usb2_req_set_hub_feature
1063184610Salfred *
1064184610Salfred * Returns:
1065184610Salfred *    0: Success
1066184610Salfred * Else: Failure
1067184610Salfred *------------------------------------------------------------------------*/
1068184610Salfredusb2_error_t
1069184610Salfredusb2_req_set_hub_feature(struct usb2_device *udev, struct mtx *mtx,
1070184610Salfred    uint16_t sel)
1071184610Salfred{
1072184610Salfred	struct usb2_device_request req;
1073184610Salfred
1074184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1075184610Salfred	req.bRequest = UR_SET_FEATURE;
1076184610Salfred	USETW(req.wValue, sel);
1077184610Salfred	USETW(req.wIndex, 0);
1078184610Salfred	USETW(req.wLength, 0);
1079184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1080184610Salfred}
1081184610Salfred
1082184610Salfred/*------------------------------------------------------------------------*
1083184610Salfred *	usb2_req_clear_port_feature
1084184610Salfred *
1085184610Salfred * Returns:
1086184610Salfred *    0: Success
1087184610Salfred * Else: Failure
1088184610Salfred *------------------------------------------------------------------------*/
1089184610Salfredusb2_error_t
1090184610Salfredusb2_req_clear_port_feature(struct usb2_device *udev, struct mtx *mtx,
1091184610Salfred    uint8_t port, uint16_t sel)
1092184610Salfred{
1093184610Salfred	struct usb2_device_request req;
1094184610Salfred
1095184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1096184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1097184610Salfred	USETW(req.wValue, sel);
1098184610Salfred	req.wIndex[0] = port;
1099184610Salfred	req.wIndex[1] = 0;
1100184610Salfred	USETW(req.wLength, 0);
1101184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1102184610Salfred}
1103184610Salfred
1104184610Salfred/*------------------------------------------------------------------------*
1105184610Salfred *	usb2_req_set_port_feature
1106184610Salfred *
1107184610Salfred * Returns:
1108184610Salfred *    0: Success
1109184610Salfred * Else: Failure
1110184610Salfred *------------------------------------------------------------------------*/
1111184610Salfredusb2_error_t
1112184610Salfredusb2_req_set_port_feature(struct usb2_device *udev, struct mtx *mtx,
1113184610Salfred    uint8_t port, uint16_t sel)
1114184610Salfred{
1115184610Salfred	struct usb2_device_request req;
1116184610Salfred
1117184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1118184610Salfred	req.bRequest = UR_SET_FEATURE;
1119184610Salfred	USETW(req.wValue, sel);
1120184610Salfred	req.wIndex[0] = port;
1121184610Salfred	req.wIndex[1] = 0;
1122184610Salfred	USETW(req.wLength, 0);
1123184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1124184610Salfred}
1125184610Salfred
1126184610Salfred/*------------------------------------------------------------------------*
1127184610Salfred *	usb2_req_set_protocol
1128184610Salfred *
1129184610Salfred * Returns:
1130184610Salfred *    0: Success
1131184610Salfred * Else: Failure
1132184610Salfred *------------------------------------------------------------------------*/
1133184610Salfredusb2_error_t
1134184610Salfredusb2_req_set_protocol(struct usb2_device *udev, struct mtx *mtx,
1135184610Salfred    uint8_t iface_index, uint16_t report)
1136184610Salfred{
1137184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1138184610Salfred	struct usb2_device_request req;
1139184610Salfred
1140184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1141184610Salfred		return (USB_ERR_INVAL);
1142184610Salfred	}
1143184610Salfred	DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n",
1144184610Salfred	    iface, report, iface->idesc->bInterfaceNumber);
1145184610Salfred
1146184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1147184610Salfred	req.bRequest = UR_SET_PROTOCOL;
1148184610Salfred	USETW(req.wValue, report);
1149184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1150184610Salfred	req.wIndex[1] = 0;
1151184610Salfred	USETW(req.wLength, 0);
1152184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1153184610Salfred}
1154184610Salfred
1155184610Salfred/*------------------------------------------------------------------------*
1156184610Salfred *	usb2_req_set_report
1157184610Salfred *
1158184610Salfred * Returns:
1159184610Salfred *    0: Success
1160184610Salfred * Else: Failure
1161184610Salfred *------------------------------------------------------------------------*/
1162184610Salfredusb2_error_t
1163184610Salfredusb2_req_set_report(struct usb2_device *udev, struct mtx *mtx, void *data, uint16_t len,
1164184610Salfred    uint8_t iface_index, uint8_t type, uint8_t id)
1165184610Salfred{
1166184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1167184610Salfred	struct usb2_device_request req;
1168184610Salfred
1169184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1170184610Salfred		return (USB_ERR_INVAL);
1171184610Salfred	}
1172184610Salfred	DPRINTFN(5, "len=%d\n", len);
1173184610Salfred
1174184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1175184610Salfred	req.bRequest = UR_SET_REPORT;
1176184610Salfred	USETW2(req.wValue, type, id);
1177184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1178184610Salfred	req.wIndex[1] = 0;
1179184610Salfred	USETW(req.wLength, len);
1180184610Salfred	return (usb2_do_request(udev, mtx, &req, data));
1181184610Salfred}
1182184610Salfred
1183184610Salfred/*------------------------------------------------------------------------*
1184184610Salfred *	usb2_req_get_report
1185184610Salfred *
1186184610Salfred * Returns:
1187184610Salfred *    0: Success
1188184610Salfred * Else: Failure
1189184610Salfred *------------------------------------------------------------------------*/
1190184610Salfredusb2_error_t
1191184610Salfredusb2_req_get_report(struct usb2_device *udev, struct mtx *mtx, void *data,
1192184610Salfred    uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
1193184610Salfred{
1194184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1195184610Salfred	struct usb2_device_request req;
1196184610Salfred
1197184610Salfred	if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) {
1198184610Salfred		return (USB_ERR_INVAL);
1199184610Salfred	}
1200184610Salfred	DPRINTFN(5, "len=%d\n", len);
1201184610Salfred
1202184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1203184610Salfred	req.bRequest = UR_GET_REPORT;
1204184610Salfred	USETW2(req.wValue, type, id);
1205184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1206184610Salfred	req.wIndex[1] = 0;
1207184610Salfred	USETW(req.wLength, len);
1208184610Salfred	return (usb2_do_request(udev, mtx, &req, data));
1209184610Salfred}
1210184610Salfred
1211184610Salfred/*------------------------------------------------------------------------*
1212184610Salfred *	usb2_req_set_idle
1213184610Salfred *
1214184610Salfred * Returns:
1215184610Salfred *    0: Success
1216184610Salfred * Else: Failure
1217184610Salfred *------------------------------------------------------------------------*/
1218184610Salfredusb2_error_t
1219184610Salfredusb2_req_set_idle(struct usb2_device *udev, struct mtx *mtx,
1220184610Salfred    uint8_t iface_index, uint8_t duration, uint8_t id)
1221184610Salfred{
1222184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1223184610Salfred	struct usb2_device_request req;
1224184610Salfred
1225184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1226184610Salfred		return (USB_ERR_INVAL);
1227184610Salfred	}
1228184610Salfred	DPRINTFN(5, "%d %d\n", duration, id);
1229184610Salfred
1230184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1231184610Salfred	req.bRequest = UR_SET_IDLE;
1232184610Salfred	USETW2(req.wValue, duration, id);
1233184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1234184610Salfred	req.wIndex[1] = 0;
1235184610Salfred	USETW(req.wLength, 0);
1236184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1237184610Salfred}
1238184610Salfred
1239184610Salfred/*------------------------------------------------------------------------*
1240184610Salfred *	usb2_req_get_report_descriptor
1241184610Salfred *
1242184610Salfred * Returns:
1243184610Salfred *    0: Success
1244184610Salfred * Else: Failure
1245184610Salfred *------------------------------------------------------------------------*/
1246184610Salfredusb2_error_t
1247184610Salfredusb2_req_get_report_descriptor(struct usb2_device *udev, struct mtx *mtx,
1248184610Salfred    void *d, uint16_t size, uint8_t iface_index)
1249184610Salfred{
1250184610Salfred	struct usb2_interface *iface = usb2_get_iface(udev, iface_index);
1251184610Salfred	struct usb2_device_request req;
1252184610Salfred
1253184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1254184610Salfred		return (USB_ERR_INVAL);
1255184610Salfred	}
1256184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1257184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1258184610Salfred	USETW2(req.wValue, UDESC_REPORT, 0);	/* report id should be 0 */
1259184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1260184610Salfred	req.wIndex[1] = 0;
1261184610Salfred	USETW(req.wLength, size);
1262184610Salfred	return (usb2_do_request(udev, mtx, &req, d));
1263184610Salfred}
1264184610Salfred
1265184610Salfred/*------------------------------------------------------------------------*
1266184610Salfred *	usb2_req_set_config
1267184610Salfred *
1268184610Salfred * This function is used to select the current configuration number in
1269184610Salfred * both USB device side mode and USB host side mode. When setting the
1270184610Salfred * configuration the function of the interfaces can change.
1271184610Salfred *
1272184610Salfred * Returns:
1273184610Salfred *    0: Success
1274184610Salfred * Else: Failure
1275184610Salfred *------------------------------------------------------------------------*/
1276184610Salfredusb2_error_t
1277184610Salfredusb2_req_set_config(struct usb2_device *udev, struct mtx *mtx, uint8_t conf)
1278184610Salfred{
1279184610Salfred	struct usb2_device_request req;
1280184610Salfred
1281184610Salfred	DPRINTF("setting config %d\n", conf);
1282184610Salfred
1283184610Salfred	/* do "set configuration" request */
1284184610Salfred
1285184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1286184610Salfred	req.bRequest = UR_SET_CONFIG;
1287184610Salfred	req.wValue[0] = conf;
1288184610Salfred	req.wValue[1] = 0;
1289184610Salfred	USETW(req.wIndex, 0);
1290184610Salfred	USETW(req.wLength, 0);
1291184610Salfred	return (usb2_do_request(udev, mtx, &req, 0));
1292184610Salfred}
1293184610Salfred
1294184610Salfred/*------------------------------------------------------------------------*
1295184610Salfred *	usb2_req_get_config
1296184610Salfred *
1297184610Salfred * Returns:
1298184610Salfred *    0: Success
1299184610Salfred * Else: Failure
1300184610Salfred *------------------------------------------------------------------------*/
1301184610Salfredusb2_error_t
1302184610Salfredusb2_req_get_config(struct usb2_device *udev, struct mtx *mtx, uint8_t *pconf)
1303184610Salfred{
1304184610Salfred	struct usb2_device_request req;
1305184610Salfred
1306184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1307184610Salfred	req.bRequest = UR_GET_CONFIG;
1308184610Salfred	USETW(req.wValue, 0);
1309184610Salfred	USETW(req.wIndex, 0);
1310184610Salfred	USETW(req.wLength, 1);
1311184610Salfred	return (usb2_do_request(udev, mtx, &req, pconf));
1312184610Salfred}
1313184610Salfred
1314184610Salfred/*------------------------------------------------------------------------*
1315184610Salfred *	usb2_req_re_enumerate
1316184610Salfred *
1317185087Salfred * NOTE: After this function returns the hardware is in the
1318185087Salfred * unconfigured state! The application is responsible for setting a
1319185087Salfred * new configuration.
1320185087Salfred *
1321184610Salfred * Returns:
1322184610Salfred *    0: Success
1323184610Salfred * Else: Failure
1324184610Salfred *------------------------------------------------------------------------*/
1325184610Salfredusb2_error_t
1326184610Salfredusb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx)
1327184610Salfred{
1328184610Salfred	struct usb2_device *parent_hub;
1329184610Salfred	usb2_error_t err;
1330184610Salfred	uint8_t old_addr;
1331184610Salfred
1332185290Salfred	if (udev->flags.usb2_mode != USB_MODE_HOST) {
1333185290Salfred		return (USB_ERR_INVAL);
1334185290Salfred	}
1335184610Salfred	old_addr = udev->address;
1336184610Salfred	parent_hub = udev->parent_hub;
1337184610Salfred	if (parent_hub == NULL) {
1338185290Salfred		return (USB_ERR_INVAL);
1339184610Salfred	}
1340184610Salfred	err = usb2_req_reset_port(parent_hub, mtx, udev->port_no);
1341184610Salfred	if (err) {
1342184610Salfred		DPRINTFN(0, "addr=%d, port reset failed\n", old_addr);
1343184610Salfred		goto done;
1344184610Salfred	}
1345184610Salfred	/*
1346184610Salfred	 * After that the port has been reset our device should be at
1347184610Salfred	 * address zero:
1348184610Salfred	 */
1349184610Salfred	udev->address = USB_START_ADDR;
1350184610Salfred
1351185290Salfred	/* reset "bMaxPacketSize" */
1352185290Salfred	udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET;
1353185290Salfred
1354184610Salfred	/*
1355184610Salfred	 * Restore device address:
1356184610Salfred	 */
1357184610Salfred	err = usb2_req_set_address(udev, mtx, old_addr);
1358184610Salfred	if (err) {
1359184610Salfred		/* XXX ignore any errors! */
1360184610Salfred		DPRINTFN(0, "addr=%d, set address failed\n",
1361184610Salfred		    old_addr);
1362184610Salfred		err = 0;
1363184610Salfred	}
1364184610Salfred	/* restore device address */
1365184610Salfred	udev->address = old_addr;
1366184610Salfred
1367184610Salfred	/* allow device time to set new address */
1368184610Salfred	usb2_pause_mtx(mtx, USB_SET_ADDRESS_SETTLE);
1369184610Salfred
1370184610Salfred	/* get the device descriptor */
1371185290Salfred	err = usb2_req_get_desc(udev, mtx, &udev->ddesc,
1372185290Salfred	    USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0);
1373184610Salfred	if (err) {
1374185290Salfred		DPRINTFN(0, "getting device descriptor "
1375185290Salfred		    "at addr %d failed!\n", udev->address);
1376185290Salfred		goto done;
1377185290Salfred	}
1378185290Salfred	/* get the full device descriptor */
1379185290Salfred	err = usb2_req_get_device_desc(udev, mtx, &udev->ddesc);
1380185290Salfred	if (err) {
1381184610Salfred		DPRINTFN(0, "addr=%d, getting device "
1382184610Salfred		    "descriptor failed!\n", old_addr);
1383184610Salfred		goto done;
1384184610Salfred	}
1385184610Salfreddone:
1386184610Salfred	/* restore address */
1387184610Salfred	udev->address = old_addr;
1388184610Salfred	return (err);
1389184610Salfred}
1390