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