usb_request.c revision 248247
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 248247 2013-03-13 15:42:04Z hselasky $ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
4184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved.
5184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
6184610Salfred *
7184610Salfred * Redistribution and use in source and binary forms, with or without
8184610Salfred * modification, are permitted provided that the following conditions
9184610Salfred * are met:
10184610Salfred * 1. Redistributions of source code must retain the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer.
12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
13184610Salfred *    notice, this list of conditions and the following disclaimer in the
14184610Salfred *    documentation and/or other materials provided with the distribution.
15184610Salfred *
16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184610Salfred * SUCH DAMAGE.
27190754Sthompsa */
28184610Salfred
29246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE
30246122Shselasky#include USB_GLOBAL_INCLUDE_FILE
31246122Shselasky#else
32194677Sthompsa#include <sys/stdint.h>
33194677Sthompsa#include <sys/stddef.h>
34194677Sthompsa#include <sys/param.h>
35194677Sthompsa#include <sys/queue.h>
36194677Sthompsa#include <sys/types.h>
37194677Sthompsa#include <sys/systm.h>
38194677Sthompsa#include <sys/kernel.h>
39194677Sthompsa#include <sys/bus.h>
40194677Sthompsa#include <sys/module.h>
41194677Sthompsa#include <sys/lock.h>
42194677Sthompsa#include <sys/mutex.h>
43194677Sthompsa#include <sys/condvar.h>
44194677Sthompsa#include <sys/sysctl.h>
45194677Sthompsa#include <sys/sx.h>
46194677Sthompsa#include <sys/unistd.h>
47194677Sthompsa#include <sys/callout.h>
48194677Sthompsa#include <sys/malloc.h>
49194677Sthompsa#include <sys/priv.h>
50194677Sthompsa
51188942Sthompsa#include <dev/usb/usb.h>
52194677Sthompsa#include <dev/usb/usbdi.h>
53194677Sthompsa#include <dev/usb/usbdi_util.h>
54188942Sthompsa#include <dev/usb/usb_ioctl.h>
55188942Sthompsa#include <dev/usb/usbhid.h>
56184610Salfred
57194228Sthompsa#define	USB_DEBUG_VAR usb_debug
58184610Salfred
59188942Sthompsa#include <dev/usb/usb_core.h>
60188942Sthompsa#include <dev/usb/usb_busdma.h>
61188942Sthompsa#include <dev/usb/usb_request.h>
62188942Sthompsa#include <dev/usb/usb_process.h>
63188942Sthompsa#include <dev/usb/usb_transfer.h>
64188942Sthompsa#include <dev/usb/usb_debug.h>
65188942Sthompsa#include <dev/usb/usb_device.h>
66188942Sthompsa#include <dev/usb/usb_util.h>
67188942Sthompsa#include <dev/usb/usb_dynamic.h>
68184610Salfred
69188942Sthompsa#include <dev/usb/usb_controller.h>
70188942Sthompsa#include <dev/usb/usb_bus.h>
71184610Salfred#include <sys/ctype.h>
72246122Shselasky#endif			/* USB_GLOBAL_INCLUDE_FILE */
73184610Salfred
74225000Shselaskystatic int usb_no_cs_fail;
75225000Shselasky
76225000ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW,
77225000Shselasky    &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set");
78225000Shselasky
79248246Shselaskystatic int usb_full_ddesc;
80248246Shselasky
81248246ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, full_ddesc, CTLFLAG_RW,
82248246Shselasky    &usb_full_ddesc, 0, "USB always read complete device descriptor, if set");
83248246Shselasky
84207077Sthompsa#ifdef USB_DEBUG
85208018Sthompsa#ifdef USB_REQ_DEBUG
86208018Sthompsa/* The following structures are used in connection to fault injection. */
87208018Sthompsastruct usb_ctrl_debug {
88208018Sthompsa	int bus_index;		/* target bus */
89208018Sthompsa	int dev_index;		/* target address */
90208018Sthompsa	int ds_fail;		/* fail data stage */
91240750Shselasky	int ss_fail;		/* fail status stage */
92208018Sthompsa	int ds_delay;		/* data stage delay in ms */
93208018Sthompsa	int ss_delay;		/* status stage delay in ms */
94208018Sthompsa	int bmRequestType_value;
95208018Sthompsa	int bRequest_value;
96208018Sthompsa};
97208018Sthompsa
98208018Sthompsastruct usb_ctrl_debug_bits {
99208018Sthompsa	uint16_t ds_delay;
100208018Sthompsa	uint16_t ss_delay;
101208018Sthompsa	uint8_t ds_fail:1;
102208018Sthompsa	uint8_t ss_fail:1;
103208018Sthompsa	uint8_t enabled:1;
104208018Sthompsa};
105208018Sthompsa
106208018Sthompsa/* The default is to disable fault injection. */
107208018Sthompsa
108208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = {
109208018Sthompsa	.bus_index = -1,
110208018Sthompsa	.dev_index = -1,
111208018Sthompsa	.bmRequestType_value = -1,
112208018Sthompsa	.bRequest_value = -1,
113208018Sthompsa};
114208018Sthompsa
115208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW,
116208018Sthompsa    &usb_ctrl_debug.bus_index, 0, "USB controller index to fail");
117208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW,
118208018Sthompsa    &usb_ctrl_debug.dev_index, 0, "USB device address to fail");
119208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW,
120208018Sthompsa    &usb_ctrl_debug.ds_fail, 0, "USB fail data stage");
121208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW,
122208018Sthompsa    &usb_ctrl_debug.ss_fail, 0, "USB fail status stage");
123208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW,
124208018Sthompsa    &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms");
125208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW,
126208018Sthompsa    &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms");
127208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW,
128208018Sthompsa    &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail");
129208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW,
130208018Sthompsa    &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail");
131208018Sthompsa
132184610Salfred/*------------------------------------------------------------------------*
133208018Sthompsa *	usbd_get_debug_bits
134208018Sthompsa *
135208018Sthompsa * This function is only useful in USB host mode.
136208018Sthompsa *------------------------------------------------------------------------*/
137208018Sthompsastatic void
138208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req,
139208018Sthompsa    struct usb_ctrl_debug_bits *dbg)
140208018Sthompsa{
141208018Sthompsa	int temp;
142208018Sthompsa
143208018Sthompsa	memset(dbg, 0, sizeof(*dbg));
144208018Sthompsa
145208018Sthompsa	/* Compute data stage delay */
146208018Sthompsa
147208018Sthompsa	temp = usb_ctrl_debug.ds_delay;
148208018Sthompsa	if (temp < 0)
149208018Sthompsa		temp = 0;
150208018Sthompsa	else if (temp > (16*1024))
151208018Sthompsa		temp = (16*1024);
152208018Sthompsa
153208018Sthompsa	dbg->ds_delay = temp;
154208018Sthompsa
155208018Sthompsa	/* Compute status stage delay */
156208018Sthompsa
157208018Sthompsa	temp = usb_ctrl_debug.ss_delay;
158208018Sthompsa	if (temp < 0)
159208018Sthompsa		temp = 0;
160208018Sthompsa	else if (temp > (16*1024))
161208018Sthompsa		temp = (16*1024);
162208018Sthompsa
163208018Sthompsa	dbg->ss_delay = temp;
164208018Sthompsa
165208018Sthompsa	/* Check if this control request should be failed */
166208018Sthompsa
167208018Sthompsa	if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index)
168208018Sthompsa		return;
169208018Sthompsa
170208018Sthompsa	if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index)
171208018Sthompsa		return;
172208018Sthompsa
173208018Sthompsa	temp = usb_ctrl_debug.bmRequestType_value;
174208018Sthompsa
175208018Sthompsa	if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255))
176208018Sthompsa		return;
177208018Sthompsa
178208018Sthompsa	temp = usb_ctrl_debug.bRequest_value;
179208018Sthompsa
180208018Sthompsa	if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255))
181208018Sthompsa		return;
182208018Sthompsa
183208018Sthompsa	temp = usb_ctrl_debug.ds_fail;
184208018Sthompsa	if (temp)
185208018Sthompsa		dbg->ds_fail = 1;
186208018Sthompsa
187208018Sthompsa	temp = usb_ctrl_debug.ss_fail;
188208018Sthompsa	if (temp)
189208018Sthompsa		dbg->ss_fail = 1;
190208018Sthompsa
191208018Sthompsa	dbg->enabled = 1;
192208018Sthompsa}
193208018Sthompsa#endif	/* USB_REQ_DEBUG */
194208018Sthompsa#endif	/* USB_DEBUG */
195208018Sthompsa
196208018Sthompsa/*------------------------------------------------------------------------*
197194228Sthompsa *	usbd_do_request_callback
198184610Salfred *
199184610Salfred * This function is the USB callback for generic USB Host control
200184610Salfred * transfers.
201184610Salfred *------------------------------------------------------------------------*/
202184610Salfredvoid
203194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error)
204184610Salfred{
205184610Salfred	;				/* workaround for a bug in "indent" */
206184610Salfred
207184610Salfred	DPRINTF("st=%u\n", USB_GET_STATE(xfer));
208184610Salfred
209184610Salfred	switch (USB_GET_STATE(xfer)) {
210184610Salfred	case USB_ST_SETUP:
211194228Sthompsa		usbd_transfer_submit(xfer);
212184610Salfred		break;
213184610Salfred	default:
214207079Sthompsa		cv_signal(&xfer->xroot->udev->ctrlreq_cv);
215184610Salfred		break;
216184610Salfred	}
217184610Salfred}
218184610Salfred
219184610Salfred/*------------------------------------------------------------------------*
220194228Sthompsa *	usb_do_clear_stall_callback
221184610Salfred *
222184610Salfred * This function is the USB callback for generic clear stall requests.
223184610Salfred *------------------------------------------------------------------------*/
224184610Salfredvoid
225194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
226184610Salfred{
227192984Sthompsa	struct usb_device_request req;
228192984Sthompsa	struct usb_device *udev;
229193644Sthompsa	struct usb_endpoint *ep;
230193644Sthompsa	struct usb_endpoint *ep_end;
231193644Sthompsa	struct usb_endpoint *ep_first;
232239214Shselasky	usb_stream_t x;
233190731Sthompsa	uint8_t to;
234184610Salfred
235187173Sthompsa	udev = xfer->xroot->udev;
236184610Salfred
237187173Sthompsa	USB_BUS_LOCK(udev->bus);
238187173Sthompsa
239193644Sthompsa	/* round robin endpoint clear stall */
240184610Salfred
241193644Sthompsa	ep = udev->ep_curr;
242193644Sthompsa	ep_end = udev->endpoints + udev->endpoints_max;
243193644Sthompsa	ep_first = udev->endpoints;
244193644Sthompsa	to = udev->endpoints_max;
245193318Sthompsa
246184610Salfred	switch (USB_GET_STATE(xfer)) {
247184610Salfred	case USB_ST_TRANSFERRED:
248225000Shselaskytr_transferred:
249222786Shselasky		/* reset error counter */
250222786Shselasky		udev->clear_stall_errors = 0;
251222786Shselasky
252193644Sthompsa		if (ep == NULL)
253193318Sthompsa			goto tr_setup;		/* device was unconfigured */
254193644Sthompsa		if (ep->edesc &&
255193644Sthompsa		    ep->is_stalled) {
256193644Sthompsa			ep->toggle_next = 0;
257193644Sthompsa			ep->is_stalled = 0;
258213435Shselasky			/* some hardware needs a callback to clear the data toggle */
259213435Shselasky			usbd_clear_stall_locked(udev, ep);
260239214Shselasky			for (x = 0; x != USB_MAX_EP_STREAMS; x++) {
261239214Shselasky				/* start the current or next transfer, if any */
262239214Shselasky				usb_command_wrapper(&ep->endpoint_q[x],
263239214Shselasky				    ep->endpoint_q[x].curr);
264239214Shselasky			}
265184610Salfred		}
266193644Sthompsa		ep++;
267184610Salfred
268184610Salfred	case USB_ST_SETUP:
269184610Salfredtr_setup:
270193318Sthompsa		if (to == 0)
271193644Sthompsa			break;			/* no endpoints - nothing to do */
272193644Sthompsa		if ((ep < ep_first) || (ep >= ep_end))
273193644Sthompsa			ep = ep_first;	/* endpoint wrapped around */
274193644Sthompsa		if (ep->edesc &&
275193644Sthompsa		    ep->is_stalled) {
276184610Salfred
277184610Salfred			/* setup a clear-stall packet */
278184610Salfred
279184610Salfred			req.bmRequestType = UT_WRITE_ENDPOINT;
280184610Salfred			req.bRequest = UR_CLEAR_FEATURE;
281184610Salfred			USETW(req.wValue, UF_ENDPOINT_HALT);
282193644Sthompsa			req.wIndex[0] = ep->edesc->bEndpointAddress;
283184610Salfred			req.wIndex[1] = 0;
284184610Salfred			USETW(req.wLength, 0);
285184610Salfred
286184610Salfred			/* copy in the transfer */
287184610Salfred
288194228Sthompsa			usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
289184610Salfred
290184610Salfred			/* set length */
291194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
292184610Salfred			xfer->nframes = 1;
293187173Sthompsa			USB_BUS_UNLOCK(udev->bus);
294184610Salfred
295194228Sthompsa			usbd_transfer_submit(xfer);
296184610Salfred
297187173Sthompsa			USB_BUS_LOCK(udev->bus);
298184610Salfred			break;
299184610Salfred		}
300193644Sthompsa		ep++;
301193318Sthompsa		to--;
302193318Sthompsa		goto tr_setup;
303184610Salfred
304184610Salfred	default:
305222786Shselasky		if (error == USB_ERR_CANCELLED)
306184610Salfred			break;
307222786Shselasky
308222786Shselasky		DPRINTF("Clear stall failed.\n");
309225000Shselasky
310225000Shselasky		/*
311225000Shselasky		 * Some VMs like VirtualBox always return failure on
312225000Shselasky		 * clear-stall which we sometimes should just ignore.
313225000Shselasky		 */
314225000Shselasky		if (usb_no_cs_fail)
315225000Shselasky			goto tr_transferred;
316222786Shselasky		if (udev->clear_stall_errors == USB_CS_RESET_LIMIT)
317222786Shselasky			goto tr_setup;
318222786Shselasky
319222786Shselasky		if (error == USB_ERR_TIMEOUT) {
320222786Shselasky			udev->clear_stall_errors = USB_CS_RESET_LIMIT;
321222786Shselasky			DPRINTF("Trying to re-enumerate.\n");
322222786Shselasky			usbd_start_re_enumerate(udev);
323222786Shselasky		} else {
324222786Shselasky			udev->clear_stall_errors++;
325222786Shselasky			if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) {
326222786Shselasky				DPRINTF("Trying to re-enumerate.\n");
327222786Shselasky				usbd_start_re_enumerate(udev);
328222786Shselasky			}
329184610Salfred		}
330184610Salfred		goto tr_setup;
331184610Salfred	}
332184610Salfred
333193644Sthompsa	/* store current endpoint */
334193644Sthompsa	udev->ep_curr = ep;
335187173Sthompsa	USB_BUS_UNLOCK(udev->bus);
336184610Salfred}
337184610Salfred
338193045Sthompsastatic usb_handle_req_t *
339194228Sthompsausbd_get_hr_func(struct usb_device *udev)
340191402Sthompsa{
341191402Sthompsa	/* figure out if there is a Handle Request function */
342192499Sthompsa	if (udev->flags.usb_mode == USB_MODE_DEVICE)
343194228Sthompsa		return (usb_temp_get_desc_p);
344191402Sthompsa	else if (udev->parent_hub == NULL)
345191402Sthompsa		return (udev->bus->methods->roothub_exec);
346191402Sthompsa	else
347191402Sthompsa		return (NULL);
348191402Sthompsa}
349191402Sthompsa
350184610Salfred/*------------------------------------------------------------------------*
351194228Sthompsa *	usbd_do_request_flags and usbd_do_request
352184610Salfred *
353184610Salfred * Description of arguments passed to these functions:
354184610Salfred *
355192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the
356184610Salfred * request should be performed. It is possible to call this function
357184610Salfred * in both Host Side mode and Device Side mode.
358184610Salfred *
359184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it
360184610Salfred * will get dropped and picked up during the execution of this
361184610Salfred * function, hence this function sometimes needs to sleep. If this
362184610Salfred * argument is NULL it has no effect.
363184610Salfred *
364184610Salfred * "req" - this argument must always be non-NULL and points to an
365184610Salfred * 8-byte structure holding the USB request to be done. The USB
366184610Salfred * request structure has a bit telling the direction of the USB
367184610Salfred * request, if it is a read or a write.
368184610Salfred *
369184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req"
370184610Salfred * is non-zero this argument must point to a valid kernel buffer which
371184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can
372184610Salfred * be NULL.
373184610Salfred *
374184610Salfred * "flags" - here is a list of valid flags:
375184610Salfred *
376184610Salfred *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
377184610Salfred *  specified
378184610Salfred *
379184610Salfred *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
380184610Salfred *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
381184610Salfred *  sysctl. This flag is mostly useful for debugging.
382184610Salfred *
383184610Salfred *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
384184610Salfred *  pointer.
385184610Salfred *
386184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in
387184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This
388184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
389184610Salfred * used.
390184610Salfred *
391184610Salfred * "timeout" - gives the timeout for the control transfer in
392184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is
393184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater
394184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack
395184610Salfred * does not allow control requests without a timeout.
396184610Salfred *
397246759Shselasky * NOTE: This function is thread safe. All calls to "usbd_do_request_flags"
398246759Shselasky * will be serialized by the use of the USB device enumeration lock.
399184610Salfred *
400184610Salfred * Returns:
401184610Salfred *    0: Success
402184610Salfred * Else: Failure
403184610Salfred *------------------------------------------------------------------------*/
404193045Sthompsausb_error_t
405194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
406192984Sthompsa    struct usb_device_request *req, void *data, uint16_t flags,
407193045Sthompsa    uint16_t *actlen, usb_timeout_t timeout)
408184610Salfred{
409208018Sthompsa#ifdef USB_REQ_DEBUG
410208018Sthompsa	struct usb_ctrl_debug_bits dbg;
411208018Sthompsa#endif
412193045Sthompsa	usb_handle_req_t *hr_func;
413192984Sthompsa	struct usb_xfer *xfer;
414184610Salfred	const void *desc;
415184610Salfred	int err = 0;
416193045Sthompsa	usb_ticks_t start_ticks;
417193045Sthompsa	usb_ticks_t delta_ticks;
418193045Sthompsa	usb_ticks_t max_ticks;
419184610Salfred	uint16_t length;
420184610Salfred	uint16_t temp;
421208018Sthompsa	uint16_t acttemp;
422246759Shselasky	uint8_t do_unlock;
423184610Salfred
424184610Salfred	if (timeout < 50) {
425184610Salfred		/* timeout is too small */
426184610Salfred		timeout = 50;
427184610Salfred	}
428184610Salfred	if (timeout > 30000) {
429184610Salfred		/* timeout is too big */
430184610Salfred		timeout = 30000;
431184610Salfred	}
432184610Salfred	length = UGETW(req->wLength);
433184610Salfred
434184610Salfred	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
435184610Salfred	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
436184610Salfred	    udev, req->bmRequestType, req->bRequest,
437184610Salfred	    req->wValue[1], req->wValue[0],
438184610Salfred	    req->wIndex[1], req->wIndex[0],
439184610Salfred	    req->wLength[1], req->wLength[0]);
440184610Salfred
441191494Sthompsa	/* Check if the device is still alive */
442191494Sthompsa	if (udev->state < USB_STATE_POWERED) {
443191494Sthompsa		DPRINTF("usb device has gone\n");
444191494Sthompsa		return (USB_ERR_NOT_CONFIGURED);
445191494Sthompsa	}
446191494Sthompsa
447184610Salfred	/*
448184610Salfred	 * Set "actlen" to a known value in case the caller does not
449184610Salfred	 * check the return value:
450184610Salfred	 */
451190735Sthompsa	if (actlen)
452184610Salfred		*actlen = 0;
453190735Sthompsa
454190180Sthompsa#if (USB_HAVE_USER_IO == 0)
455190180Sthompsa	if (flags & USB_USER_DATA_PTR)
456190180Sthompsa		return (USB_ERR_INVAL);
457190180Sthompsa#endif
458208008Sthompsa	if ((mtx != NULL) && (mtx != &Giant)) {
459184610Salfred		mtx_unlock(mtx);
460208008Sthompsa		mtx_assert(mtx, MA_NOTOWNED);
461184610Salfred	}
462208008Sthompsa
463184610Salfred	/*
464246759Shselasky	 * Grab the USB device enumeration SX-lock serialization is
465246759Shselasky	 * achieved when multiple threads are involved:
466208008Sthompsa	 */
467246759Shselasky	do_unlock = usbd_enum_lock(udev);
468208008Sthompsa
469208008Sthompsa	/*
470246759Shselasky	 * We need to allow suspend and resume at this point, else the
471246759Shselasky	 * control transfer will timeout if the device is suspended!
472184610Salfred	 */
473246759Shselasky	usbd_sr_unlock(udev);
474184610Salfred
475194228Sthompsa	hr_func = usbd_get_hr_func(udev);
476190735Sthompsa
477191402Sthompsa	if (hr_func != NULL) {
478191402Sthompsa		DPRINTF("Handle Request function is set\n");
479190735Sthompsa
480191402Sthompsa		desc = NULL;
481191402Sthompsa		temp = 0;
482191402Sthompsa
483191402Sthompsa		if (!(req->bmRequestType & UT_READ)) {
484190735Sthompsa			if (length != 0) {
485191402Sthompsa				DPRINTFN(1, "The handle request function "
486191402Sthompsa				    "does not support writing data!\n");
487191402Sthompsa				err = USB_ERR_INVAL;
488191402Sthompsa				goto done;
489190735Sthompsa			}
490190735Sthompsa		}
491190735Sthompsa
492191402Sthompsa		/* The root HUB code needs the BUS lock locked */
493191402Sthompsa
494190735Sthompsa		USB_BUS_LOCK(udev->bus);
495191402Sthompsa		err = (hr_func) (udev, req, &desc, &temp);
496190735Sthompsa		USB_BUS_UNLOCK(udev->bus);
497190735Sthompsa
498190735Sthompsa		if (err)
499190735Sthompsa			goto done;
500190735Sthompsa
501191402Sthompsa		if (length > temp) {
502190735Sthompsa			if (!(flags & USB_SHORT_XFER_OK)) {
503190735Sthompsa				err = USB_ERR_SHORT_XFER;
504190735Sthompsa				goto done;
505190735Sthompsa			}
506191402Sthompsa			length = temp;
507190735Sthompsa		}
508190735Sthompsa		if (actlen)
509190735Sthompsa			*actlen = length;
510190735Sthompsa
511190735Sthompsa		if (length > 0) {
512190735Sthompsa#if USB_HAVE_USER_IO
513190735Sthompsa			if (flags & USB_USER_DATA_PTR) {
514191402Sthompsa				if (copyout(desc, data, length)) {
515190735Sthompsa					err = USB_ERR_INVAL;
516190735Sthompsa					goto done;
517190735Sthompsa				}
518190735Sthompsa			} else
519190735Sthompsa#endif
520227461Shselasky				memcpy(data, desc, length);
521190735Sthompsa		}
522191402Sthompsa		goto done;		/* success */
523190735Sthompsa	}
524190735Sthompsa
525184610Salfred	/*
526184610Salfred	 * Setup a new USB transfer or use the existing one, if any:
527184610Salfred	 */
528207080Sthompsa	usbd_ctrl_transfer_setup(udev);
529184610Salfred
530207080Sthompsa	xfer = udev->ctrl_xfer[0];
531184610Salfred	if (xfer == NULL) {
532184610Salfred		/* most likely out of memory */
533184610Salfred		err = USB_ERR_NOMEM;
534184610Salfred		goto done;
535184610Salfred	}
536208018Sthompsa
537208018Sthompsa#ifdef USB_REQ_DEBUG
538208018Sthompsa	/* Get debug bits */
539208018Sthompsa	usbd_get_debug_bits(udev, req, &dbg);
540208018Sthompsa
541208018Sthompsa	/* Check for fault injection */
542208018Sthompsa	if (dbg.enabled)
543208018Sthompsa		flags |= USB_DELAY_STATUS_STAGE;
544208018Sthompsa#endif
545184824Sthompsa	USB_XFER_LOCK(xfer);
546184610Salfred
547190734Sthompsa	if (flags & USB_DELAY_STATUS_STAGE)
548184610Salfred		xfer->flags.manual_status = 1;
549190734Sthompsa	else
550184610Salfred		xfer->flags.manual_status = 0;
551184610Salfred
552190734Sthompsa	if (flags & USB_SHORT_XFER_OK)
553190734Sthompsa		xfer->flags.short_xfer_ok = 1;
554190734Sthompsa	else
555190734Sthompsa		xfer->flags.short_xfer_ok = 0;
556190734Sthompsa
557184610Salfred	xfer->timeout = timeout;
558184610Salfred
559184610Salfred	start_ticks = ticks;
560184610Salfred
561184610Salfred	max_ticks = USB_MS_TO_TICKS(timeout);
562184610Salfred
563194228Sthompsa	usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req));
564184610Salfred
565194677Sthompsa	usbd_xfer_set_frame_len(xfer, 0, sizeof(*req));
566184610Salfred
567184610Salfred	while (1) {
568184610Salfred		temp = length;
569208018Sthompsa		if (temp > usbd_xfer_max_len(xfer)) {
570194677Sthompsa			temp = usbd_xfer_max_len(xfer);
571184610Salfred		}
572208018Sthompsa#ifdef USB_REQ_DEBUG
573208018Sthompsa		if (xfer->flags.manual_status) {
574208018Sthompsa			if (usbd_xfer_frame_len(xfer, 0) != 0) {
575208018Sthompsa				/* Execute data stage separately */
576208018Sthompsa				temp = 0;
577208018Sthompsa			} else if (temp > 0) {
578208018Sthompsa				if (dbg.ds_fail) {
579208018Sthompsa					err = USB_ERR_INVAL;
580208018Sthompsa					break;
581208018Sthompsa				}
582208018Sthompsa				if (dbg.ds_delay > 0) {
583208018Sthompsa					usb_pause_mtx(
584208018Sthompsa					    xfer->xroot->xfer_mtx,
585208018Sthompsa				            USB_MS_TO_TICKS(dbg.ds_delay));
586208018Sthompsa					/* make sure we don't time out */
587208018Sthompsa					start_ticks = ticks;
588208018Sthompsa				}
589208018Sthompsa			}
590208018Sthompsa		}
591208018Sthompsa#endif
592194677Sthompsa		usbd_xfer_set_frame_len(xfer, 1, temp);
593184610Salfred
594184610Salfred		if (temp > 0) {
595184610Salfred			if (!(req->bmRequestType & UT_READ)) {
596190180Sthompsa#if USB_HAVE_USER_IO
597184610Salfred				if (flags & USB_USER_DATA_PTR) {
598184824Sthompsa					USB_XFER_UNLOCK(xfer);
599194228Sthompsa					err = usbd_copy_in_user(xfer->frbuffers + 1,
600184610Salfred					    0, data, temp);
601184824Sthompsa					USB_XFER_LOCK(xfer);
602184610Salfred					if (err) {
603184610Salfred						err = USB_ERR_INVAL;
604184610Salfred						break;
605184610Salfred					}
606190180Sthompsa				} else
607190180Sthompsa#endif
608194228Sthompsa					usbd_copy_in(xfer->frbuffers + 1,
609190180Sthompsa					    0, data, temp);
610184610Salfred			}
611208018Sthompsa			usbd_xfer_set_frames(xfer, 2);
612184610Salfred		} else {
613208018Sthompsa			if (usbd_xfer_frame_len(xfer, 0) == 0) {
614184610Salfred				if (xfer->flags.manual_status) {
615208018Sthompsa#ifdef USB_REQ_DEBUG
616208018Sthompsa					if (dbg.ss_fail) {
617208018Sthompsa						err = USB_ERR_INVAL;
618208018Sthompsa						break;
619184610Salfred					}
620208018Sthompsa					if (dbg.ss_delay > 0) {
621194228Sthompsa						usb_pause_mtx(
622187173Sthompsa						    xfer->xroot->xfer_mtx,
623208018Sthompsa						    USB_MS_TO_TICKS(dbg.ss_delay));
624208018Sthompsa						/* make sure we don't time out */
625208018Sthompsa						start_ticks = ticks;
626184610Salfred					}
627184610Salfred#endif
628184610Salfred					xfer->flags.manual_status = 0;
629184610Salfred				} else {
630184610Salfred					break;
631184610Salfred				}
632184610Salfred			}
633208018Sthompsa			usbd_xfer_set_frames(xfer, 1);
634184610Salfred		}
635184610Salfred
636194228Sthompsa		usbd_transfer_start(xfer);
637184610Salfred
638194228Sthompsa		while (usbd_transfer_pending(xfer)) {
639207079Sthompsa			cv_wait(&udev->ctrlreq_cv,
640188983Sthompsa			    xfer->xroot->xfer_mtx);
641184610Salfred		}
642184610Salfred
643184610Salfred		err = xfer->error;
644184610Salfred
645184610Salfred		if (err) {
646184610Salfred			break;
647184610Salfred		}
648184610Salfred
649208018Sthompsa		/* get actual length of DATA stage */
650208018Sthompsa
651208018Sthompsa		if (xfer->aframes < 2) {
652208018Sthompsa			acttemp = 0;
653184610Salfred		} else {
654208018Sthompsa			acttemp = usbd_xfer_frame_len(xfer, 1);
655184610Salfred		}
656184610Salfred
657184610Salfred		/* check for short packet */
658184610Salfred
659208018Sthompsa		if (temp > acttemp) {
660208018Sthompsa			temp = acttemp;
661184610Salfred			length = temp;
662184610Salfred		}
663184610Salfred		if (temp > 0) {
664184610Salfred			if (req->bmRequestType & UT_READ) {
665190180Sthompsa#if USB_HAVE_USER_IO
666184610Salfred				if (flags & USB_USER_DATA_PTR) {
667184824Sthompsa					USB_XFER_UNLOCK(xfer);
668194228Sthompsa					err = usbd_copy_out_user(xfer->frbuffers + 1,
669184610Salfred					    0, data, temp);
670184824Sthompsa					USB_XFER_LOCK(xfer);
671184610Salfred					if (err) {
672184610Salfred						err = USB_ERR_INVAL;
673184610Salfred						break;
674184610Salfred					}
675190180Sthompsa				} else
676190180Sthompsa#endif
677194228Sthompsa					usbd_copy_out(xfer->frbuffers + 1,
678184610Salfred					    0, data, temp);
679184610Salfred			}
680184610Salfred		}
681184610Salfred		/*
682184610Salfred		 * Clear "frlengths[0]" so that we don't send the setup
683184610Salfred		 * packet again:
684184610Salfred		 */
685194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, 0);
686184610Salfred
687184610Salfred		/* update length and data pointer */
688184610Salfred		length -= temp;
689184610Salfred		data = USB_ADD_BYTES(data, temp);
690184610Salfred
691184610Salfred		if (actlen) {
692184610Salfred			(*actlen) += temp;
693184610Salfred		}
694184610Salfred		/* check for timeout */
695184610Salfred
696184610Salfred		delta_ticks = ticks - start_ticks;
697184610Salfred		if (delta_ticks > max_ticks) {
698184610Salfred			if (!err) {
699184610Salfred				err = USB_ERR_TIMEOUT;
700184610Salfred			}
701184610Salfred		}
702184610Salfred		if (err) {
703184610Salfred			break;
704184610Salfred		}
705184610Salfred	}
706184610Salfred
707184610Salfred	if (err) {
708184610Salfred		/*
709184610Salfred		 * Make sure that the control endpoint is no longer
710184610Salfred		 * blocked in case of a non-transfer related error:
711184610Salfred		 */
712194228Sthompsa		usbd_transfer_stop(xfer);
713184610Salfred	}
714184824Sthompsa	USB_XFER_UNLOCK(xfer);
715184610Salfred
716184610Salfreddone:
717246759Shselasky	usbd_sr_lock(udev);
718184610Salfred
719246759Shselasky	if (do_unlock)
720246759Shselasky		usbd_enum_unlock(udev);
721208008Sthompsa
722208008Sthompsa	if ((mtx != NULL) && (mtx != &Giant))
723184610Salfred		mtx_lock(mtx);
724208008Sthompsa
725193045Sthompsa	return ((usb_error_t)err);
726184610Salfred}
727184610Salfred
728184610Salfred/*------------------------------------------------------------------------*
729194228Sthompsa *	usbd_do_request_proc - factored out code
730188411Sthompsa *
731188411Sthompsa * This function is factored out code. It does basically the same like
732194228Sthompsa * usbd_do_request_flags, except it will check the status of the
733188411Sthompsa * passed process argument before doing the USB request. If the
734188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It
735188411Sthompsa * is assumed that the mutex associated with the process is locked
736188411Sthompsa * when calling this function.
737188411Sthompsa *------------------------------------------------------------------------*/
738193045Sthompsausb_error_t
739194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc,
740192984Sthompsa    struct usb_device_request *req, void *data, uint16_t flags,
741193045Sthompsa    uint16_t *actlen, usb_timeout_t timeout)
742188411Sthompsa{
743193045Sthompsa	usb_error_t err;
744188411Sthompsa	uint16_t len;
745188411Sthompsa
746188411Sthompsa	/* get request data length */
747188411Sthompsa	len = UGETW(req->wLength);
748188411Sthompsa
749188411Sthompsa	/* check if the device is being detached */
750194228Sthompsa	if (usb_proc_is_gone(pproc)) {
751188411Sthompsa		err = USB_ERR_IOERROR;
752188411Sthompsa		goto done;
753188411Sthompsa	}
754188411Sthompsa
755188411Sthompsa	/* forward the USB request */
756194228Sthompsa	err = usbd_do_request_flags(udev, pproc->up_mtx,
757188411Sthompsa	    req, data, flags, actlen, timeout);
758188411Sthompsa
759188411Sthompsadone:
760188411Sthompsa	/* on failure we zero the data */
761188411Sthompsa	/* on short packet we zero the unused data */
762188411Sthompsa	if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) {
763188411Sthompsa		if (err)
764188411Sthompsa			memset(data, 0, len);
765188411Sthompsa		else if (actlen && *actlen != len)
766188411Sthompsa			memset(((uint8_t *)data) + *actlen, 0, len - *actlen);
767188411Sthompsa	}
768188411Sthompsa	return (err);
769188411Sthompsa}
770188411Sthompsa
771188411Sthompsa/*------------------------------------------------------------------------*
772194228Sthompsa *	usbd_req_reset_port
773184610Salfred *
774214804Shselasky * This function will instruct a USB HUB to perform a reset sequence
775184610Salfred * on the specified port number.
776184610Salfred *
777184610Salfred * Returns:
778184610Salfred *    0: Success. The USB device should now be at address zero.
779184610Salfred * Else: Failure. No USB device is present and the USB port should be
780184610Salfred *       disabled.
781184610Salfred *------------------------------------------------------------------------*/
782193045Sthompsausb_error_t
783194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
784184610Salfred{
785192984Sthompsa	struct usb_port_status ps;
786193045Sthompsa	usb_error_t err;
787184610Salfred	uint16_t n;
788230091Shselasky	uint16_t status;
789230091Shselasky	uint16_t change;
790184610Salfred
791230091Shselasky	DPRINTF("\n");
792230091Shselasky
793224095Shselasky	/* clear any leftover port reset changes first */
794224095Shselasky	usbd_req_clear_port_feature(
795224095Shselasky	    udev, mtx, port, UHF_C_PORT_RESET);
796224095Shselasky
797224095Shselasky	/* assert port reset on the given port */
798224095Shselasky	err = usbd_req_set_port_feature(
799224095Shselasky	    udev, mtx, port, UHF_PORT_RESET);
800224095Shselasky
801224095Shselasky	/* check for errors */
802224095Shselasky	if (err)
803184610Salfred		goto done;
804184610Salfred	n = 0;
805184610Salfred	while (1) {
806184610Salfred		/* wait for the device to recover from reset */
807241987Shselasky		usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay));
808241987Shselasky		n += usb_port_reset_delay;
809194228Sthompsa		err = usbd_req_get_port_status(udev, mtx, &ps, port);
810230091Shselasky		if (err)
811184610Salfred			goto done;
812230091Shselasky
813224095Shselasky		status = UGETW(ps.wPortStatus);
814224095Shselasky		change = UGETW(ps.wPortChange);
815224095Shselasky
816216249Shselasky		/* if the device disappeared, just give up */
817224095Shselasky		if (!(status & UPS_CURRENT_CONNECT_STATUS))
818216249Shselasky			goto done;
819224095Shselasky
820214804Shselasky		/* check if reset is complete */
821224095Shselasky		if (change & UPS_C_PORT_RESET)
822214804Shselasky			break;
823224095Shselasky
824224095Shselasky		/*
825224095Shselasky		 * Some Virtual Machines like VirtualBox 4.x fail to
826224095Shselasky		 * generate a port reset change event. Check if reset
827224095Shselasky		 * is no longer asserted.
828224095Shselasky		 */
829224095Shselasky		if (!(status & UPS_RESET))
830224095Shselasky			break;
831224095Shselasky
832214804Shselasky		/* check for timeout */
833214804Shselasky		if (n > 1000) {
834214804Shselasky			n = 0;
835214804Shselasky			break;
836214804Shselasky		}
837214804Shselasky	}
838214804Shselasky
839214804Shselasky	/* clear port reset first */
840214804Shselasky	err = usbd_req_clear_port_feature(
841214804Shselasky	    udev, mtx, port, UHF_C_PORT_RESET);
842230091Shselasky	if (err)
843214804Shselasky		goto done;
844230091Shselasky
845214804Shselasky	/* check for timeout */
846214804Shselasky	if (n == 0) {
847214804Shselasky		err = USB_ERR_TIMEOUT;
848214804Shselasky		goto done;
849214804Shselasky	}
850214804Shselasky	/* wait for the device to recover from reset */
851241987Shselasky	usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery));
852214804Shselasky
853214804Shselaskydone:
854214804Shselasky	DPRINTFN(2, "port %d reset returning error=%s\n",
855214804Shselasky	    port, usbd_errstr(err));
856214804Shselasky	return (err);
857214804Shselasky}
858214804Shselasky
859214804Shselasky/*------------------------------------------------------------------------*
860214804Shselasky *	usbd_req_warm_reset_port
861214804Shselasky *
862214804Shselasky * This function will instruct an USB HUB to perform a warm reset
863214804Shselasky * sequence on the specified port number. This kind of reset is not
864214804Shselasky * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted
865214804Shselasky * for SUPER-speed USB HUBs.
866214804Shselasky *
867214804Shselasky * Returns:
868214804Shselasky *    0: Success. The USB device should now be available again.
869214804Shselasky * Else: Failure. No USB device is present and the USB port should be
870214804Shselasky *       disabled.
871214804Shselasky *------------------------------------------------------------------------*/
872214804Shselaskyusb_error_t
873230091Shselaskyusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx,
874230091Shselasky    uint8_t port)
875214804Shselasky{
876214804Shselasky	struct usb_port_status ps;
877214804Shselasky	usb_error_t err;
878214804Shselasky	uint16_t n;
879230091Shselasky	uint16_t status;
880230091Shselasky	uint16_t change;
881214804Shselasky
882230091Shselasky	DPRINTF("\n");
883230091Shselasky
884230091Shselasky	err = usbd_req_get_port_status(udev, mtx, &ps, port);
885230091Shselasky	if (err)
886214804Shselasky		goto done;
887230091Shselasky
888230091Shselasky	status = UGETW(ps.wPortStatus);
889230091Shselasky
890230091Shselasky	switch (UPS_PORT_LINK_STATE_GET(status)) {
891230091Shselasky	case UPS_PORT_LS_U3:
892230091Shselasky	case UPS_PORT_LS_COMP_MODE:
893230091Shselasky	case UPS_PORT_LS_LOOPBACK:
894230091Shselasky	case UPS_PORT_LS_SS_INA:
895230091Shselasky		break;
896230091Shselasky	default:
897230091Shselasky		DPRINTF("Wrong state for warm reset\n");
898230091Shselasky		return (0);
899214804Shselasky	}
900230091Shselasky
901230091Shselasky	/* clear any leftover warm port reset changes first */
902230091Shselasky	usbd_req_clear_port_feature(udev, mtx,
903230091Shselasky	    port, UHF_C_BH_PORT_RESET);
904230091Shselasky
905230091Shselasky	/* set warm port reset */
906230091Shselasky	err = usbd_req_set_port_feature(udev, mtx,
907230091Shselasky	    port, UHF_BH_PORT_RESET);
908230091Shselasky	if (err)
909230091Shselasky		goto done;
910230091Shselasky
911214804Shselasky	n = 0;
912214804Shselasky	while (1) {
913214804Shselasky		/* wait for the device to recover from reset */
914241987Shselasky		usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay));
915241987Shselasky		n += usb_port_reset_delay;
916214804Shselasky		err = usbd_req_get_port_status(udev, mtx, &ps, port);
917230091Shselasky		if (err)
918214804Shselasky			goto done;
919230091Shselasky
920230091Shselasky		status = UGETW(ps.wPortStatus);
921230091Shselasky		change = UGETW(ps.wPortChange);
922230091Shselasky
923184610Salfred		/* if the device disappeared, just give up */
924230091Shselasky		if (!(status & UPS_CURRENT_CONNECT_STATUS))
925184610Salfred			goto done;
926230091Shselasky
927184610Salfred		/* check if reset is complete */
928230091Shselasky		if (change & UPS_C_BH_PORT_RESET)
929184610Salfred			break;
930230091Shselasky
931184610Salfred		/* check for timeout */
932184610Salfred		if (n > 1000) {
933184610Salfred			n = 0;
934184610Salfred			break;
935184610Salfred		}
936184610Salfred	}
937184610Salfred
938184610Salfred	/* clear port reset first */
939194228Sthompsa	err = usbd_req_clear_port_feature(
940214804Shselasky	    udev, mtx, port, UHF_C_BH_PORT_RESET);
941230091Shselasky	if (err)
942184610Salfred		goto done;
943230091Shselasky
944184610Salfred	/* check for timeout */
945184610Salfred	if (n == 0) {
946184610Salfred		err = USB_ERR_TIMEOUT;
947184610Salfred		goto done;
948184610Salfred	}
949184610Salfred	/* wait for the device to recover from reset */
950241987Shselasky	usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery));
951184610Salfred
952184610Salfreddone:
953214804Shselasky	DPRINTFN(2, "port %d warm reset returning error=%s\n",
954194228Sthompsa	    port, usbd_errstr(err));
955184610Salfred	return (err);
956184610Salfred}
957184610Salfred
958184610Salfred/*------------------------------------------------------------------------*
959194228Sthompsa *	usbd_req_get_desc
960184610Salfred *
961184610Salfred * This function can be used to retrieve USB descriptors. It contains
962184610Salfred * some additional logic like zeroing of missing descriptor bytes and
963184610Salfred * retrying an USB descriptor in case of failure. The "min_len"
964184610Salfred * argument specifies the minimum descriptor length. The "max_len"
965184610Salfred * argument specifies the maximum descriptor length. If the real
966184610Salfred * descriptor length is less than the minimum length the missing
967188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB
968188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen"
969188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get
970188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The
971188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen"
972188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated
973188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to
974188985Sthompsa * "max_len" then this function will try to retrive the beginning of
975188985Sthompsa * the descriptor and base the maximum length on the first byte of the
976188985Sthompsa * descriptor.
977184610Salfred *
978184610Salfred * Returns:
979184610Salfred *    0: Success
980184610Salfred * Else: Failure
981184610Salfred *------------------------------------------------------------------------*/
982193045Sthompsausb_error_t
983194228Sthompsausbd_req_get_desc(struct usb_device *udev,
984188985Sthompsa    struct mtx *mtx, uint16_t *actlen, void *desc,
985184610Salfred    uint16_t min_len, uint16_t max_len,
986184610Salfred    uint16_t id, uint8_t type, uint8_t index,
987184610Salfred    uint8_t retries)
988184610Salfred{
989192984Sthompsa	struct usb_device_request req;
990184610Salfred	uint8_t *buf;
991193045Sthompsa	usb_error_t err;
992184610Salfred
993184610Salfred	DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n",
994184610Salfred	    id, type, index, max_len);
995184610Salfred
996184610Salfred	req.bmRequestType = UT_READ_DEVICE;
997184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
998184610Salfred	USETW2(req.wValue, type, index);
999184610Salfred	USETW(req.wIndex, id);
1000184610Salfred
1001184610Salfred	while (1) {
1002184610Salfred
1003184610Salfred		if ((min_len < 2) || (max_len < 2)) {
1004184610Salfred			err = USB_ERR_INVAL;
1005184610Salfred			goto done;
1006184610Salfred		}
1007184610Salfred		USETW(req.wLength, min_len);
1008184610Salfred
1009194228Sthompsa		err = usbd_do_request_flags(udev, mtx, &req,
1010248246Shselasky		    desc, 0, NULL, 500 /* ms */);
1011184610Salfred
1012184610Salfred		if (err) {
1013184610Salfred			if (!retries) {
1014184610Salfred				goto done;
1015184610Salfred			}
1016184610Salfred			retries--;
1017184610Salfred
1018194228Sthompsa			usb_pause_mtx(mtx, hz / 5);
1019184610Salfred
1020184610Salfred			continue;
1021184610Salfred		}
1022184610Salfred		buf = desc;
1023184610Salfred
1024184610Salfred		if (min_len == max_len) {
1025184610Salfred
1026188985Sthompsa			/* enforce correct length */
1027188985Sthompsa			if ((buf[0] > min_len) && (actlen == NULL))
1028188985Sthompsa				buf[0] = min_len;
1029184610Salfred
1030188985Sthompsa			/* enforce correct type */
1031184610Salfred			buf[1] = type;
1032184610Salfred
1033184610Salfred			goto done;
1034184610Salfred		}
1035184610Salfred		/* range check */
1036184610Salfred
1037184610Salfred		if (max_len > buf[0]) {
1038184610Salfred			max_len = buf[0];
1039184610Salfred		}
1040184610Salfred		/* zero minimum data */
1041184610Salfred
1042184610Salfred		while (min_len > max_len) {
1043184610Salfred			min_len--;
1044184610Salfred			buf[min_len] = 0;
1045184610Salfred		}
1046184610Salfred
1047184610Salfred		/* set new minimum length */
1048184610Salfred
1049184610Salfred		min_len = max_len;
1050184610Salfred	}
1051184610Salfreddone:
1052188985Sthompsa	if (actlen != NULL) {
1053188985Sthompsa		if (err)
1054188985Sthompsa			*actlen = 0;
1055188985Sthompsa		else
1056188985Sthompsa			*actlen = min_len;
1057188985Sthompsa	}
1058184610Salfred	return (err);
1059184610Salfred}
1060184610Salfred
1061184610Salfred/*------------------------------------------------------------------------*
1062194228Sthompsa *	usbd_req_get_string_any
1063184610Salfred *
1064184610Salfred * This function will return the string given by "string_index"
1065184610Salfred * using the first language ID. The maximum length "len" includes
1066184610Salfred * the terminating zero. The "len" argument should be twice as
1067184610Salfred * big pluss 2 bytes, compared with the actual maximum string length !
1068184610Salfred *
1069184610Salfred * Returns:
1070184610Salfred *    0: Success
1071184610Salfred * Else: Failure
1072184610Salfred *------------------------------------------------------------------------*/
1073193045Sthompsausb_error_t
1074194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf,
1075184610Salfred    uint16_t len, uint8_t string_index)
1076184610Salfred{
1077184610Salfred	char *s;
1078184610Salfred	uint8_t *temp;
1079184610Salfred	uint16_t i;
1080184610Salfred	uint16_t n;
1081184610Salfred	uint16_t c;
1082184610Salfred	uint8_t swap;
1083193045Sthompsa	usb_error_t err;
1084184610Salfred
1085184610Salfred	if (len == 0) {
1086184610Salfred		/* should not happen */
1087184610Salfred		return (USB_ERR_NORMAL_COMPLETION);
1088184610Salfred	}
1089184610Salfred	if (string_index == 0) {
1090184610Salfred		/* this is the language table */
1091185087Salfred		buf[0] = 0;
1092184610Salfred		return (USB_ERR_INVAL);
1093184610Salfred	}
1094184610Salfred	if (udev->flags.no_strings) {
1095185087Salfred		buf[0] = 0;
1096184610Salfred		return (USB_ERR_STALLED);
1097184610Salfred	}
1098194228Sthompsa	err = usbd_req_get_string_desc
1099184610Salfred	    (udev, mtx, buf, len, udev->langid, string_index);
1100184610Salfred	if (err) {
1101185087Salfred		buf[0] = 0;
1102184610Salfred		return (err);
1103184610Salfred	}
1104184610Salfred	temp = (uint8_t *)buf;
1105184610Salfred
1106184610Salfred	if (temp[0] < 2) {
1107184610Salfred		/* string length is too short */
1108185087Salfred		buf[0] = 0;
1109184610Salfred		return (USB_ERR_INVAL);
1110184610Salfred	}
1111184610Salfred	/* reserve one byte for terminating zero */
1112184610Salfred	len--;
1113184610Salfred
1114184610Salfred	/* find maximum length */
1115184610Salfred	s = buf;
1116184610Salfred	n = (temp[0] / 2) - 1;
1117184610Salfred	if (n > len) {
1118184610Salfred		n = len;
1119184610Salfred	}
1120184610Salfred	/* skip descriptor header */
1121184610Salfred	temp += 2;
1122184610Salfred
1123184610Salfred	/* reset swap state */
1124184610Salfred	swap = 3;
1125184610Salfred
1126184610Salfred	/* convert and filter */
1127184610Salfred	for (i = 0; (i != n); i++) {
1128184610Salfred		c = UGETW(temp + (2 * i));
1129184610Salfred
1130184610Salfred		/* convert from Unicode, handle buggy strings */
1131184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
1132184610Salfred			/* Little Endian, default */
1133184610Salfred			*s = c;
1134184610Salfred			swap = 1;
1135184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
1136184610Salfred			/* Big Endian */
1137184610Salfred			*s = c >> 8;
1138184610Salfred			swap = 2;
1139184610Salfred		} else {
1140185087Salfred			/* silently skip bad character */
1141185087Salfred			continue;
1142184610Salfred		}
1143184610Salfred
1144184610Salfred		/*
1145213433Shselasky		 * Filter by default - We only allow alphanumerical
1146213433Shselasky		 * and a few more to avoid any problems with scripts
1147213433Shselasky		 * and daemons.
1148184610Salfred		 */
1149213433Shselasky		if (isalpha(*s) ||
1150213433Shselasky		    isdigit(*s) ||
1151213433Shselasky		    *s == '-' ||
1152213433Shselasky		    *s == '+' ||
1153213433Shselasky		    *s == ' ' ||
1154213433Shselasky		    *s == '.' ||
1155213433Shselasky		    *s == ',') {
1156213433Shselasky			/* allowed */
1157213433Shselasky			s++;
1158184610Salfred		}
1159213433Shselasky		/* silently skip bad character */
1160184610Salfred	}
1161185087Salfred	*s = 0;				/* zero terminate resulting string */
1162184610Salfred	return (USB_ERR_NORMAL_COMPLETION);
1163184610Salfred}
1164184610Salfred
1165184610Salfred/*------------------------------------------------------------------------*
1166194228Sthompsa *	usbd_req_get_string_desc
1167184610Salfred *
1168184610Salfred * If you don't know the language ID, consider using
1169194228Sthompsa * "usbd_req_get_string_any()".
1170184610Salfred *
1171184610Salfred * Returns:
1172184610Salfred *    0: Success
1173184610Salfred * Else: Failure
1174184610Salfred *------------------------------------------------------------------------*/
1175193045Sthompsausb_error_t
1176194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc,
1177184610Salfred    uint16_t max_len, uint16_t lang_id,
1178184610Salfred    uint8_t string_index)
1179184610Salfred{
1180194228Sthompsa	return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id,
1181184610Salfred	    UDESC_STRING, string_index, 0));
1182184610Salfred}
1183184610Salfred
1184184610Salfred/*------------------------------------------------------------------------*
1185194228Sthompsa *	usbd_req_get_config_desc_ptr
1186190727Sthompsa *
1187190727Sthompsa * This function is used in device side mode to retrieve the pointer
1188190727Sthompsa * to the generated config descriptor. This saves allocating space for
1189190727Sthompsa * an additional config descriptor when setting the configuration.
1190190727Sthompsa *
1191190727Sthompsa * Returns:
1192190727Sthompsa *    0: Success
1193190727Sthompsa * Else: Failure
1194190727Sthompsa *------------------------------------------------------------------------*/
1195193045Sthompsausb_error_t
1196194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev,
1197192984Sthompsa    struct usb_config_descriptor **ppcd, uint16_t wValue)
1198190727Sthompsa{
1199192984Sthompsa	struct usb_device_request req;
1200193045Sthompsa	usb_handle_req_t *hr_func;
1201191402Sthompsa	const void *ptr;
1202190727Sthompsa	uint16_t len;
1203193045Sthompsa	usb_error_t err;
1204190727Sthompsa
1205190731Sthompsa	req.bmRequestType = UT_READ_DEVICE;
1206190727Sthompsa	req.bRequest = UR_GET_DESCRIPTOR;
1207191402Sthompsa	USETW(req.wValue, wValue);
1208190727Sthompsa	USETW(req.wIndex, 0);
1209190727Sthompsa	USETW(req.wLength, 0);
1210190727Sthompsa
1211191402Sthompsa	ptr = NULL;
1212191402Sthompsa	len = 0;
1213190727Sthompsa
1214194228Sthompsa	hr_func = usbd_get_hr_func(udev);
1215191402Sthompsa
1216191402Sthompsa	if (hr_func == NULL)
1217191402Sthompsa		err = USB_ERR_INVAL;
1218191402Sthompsa	else {
1219191402Sthompsa		USB_BUS_LOCK(udev->bus);
1220191402Sthompsa		err = (hr_func) (udev, &req, &ptr, &len);
1221191402Sthompsa		USB_BUS_UNLOCK(udev->bus);
1222191402Sthompsa	}
1223191402Sthompsa
1224191402Sthompsa	if (err)
1225191402Sthompsa		ptr = NULL;
1226191402Sthompsa	else if (ptr == NULL)
1227191402Sthompsa		err = USB_ERR_INVAL;
1228191402Sthompsa
1229192984Sthompsa	*ppcd = __DECONST(struct usb_config_descriptor *, ptr);
1230191402Sthompsa
1231191402Sthompsa	return (err);
1232190727Sthompsa}
1233190727Sthompsa
1234190727Sthompsa/*------------------------------------------------------------------------*
1235194228Sthompsa *	usbd_req_get_config_desc
1236184610Salfred *
1237184610Salfred * Returns:
1238184610Salfred *    0: Success
1239184610Salfred * Else: Failure
1240184610Salfred *------------------------------------------------------------------------*/
1241193045Sthompsausb_error_t
1242194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx,
1243192984Sthompsa    struct usb_config_descriptor *d, uint8_t conf_index)
1244184610Salfred{
1245193045Sthompsa	usb_error_t err;
1246184610Salfred
1247184610Salfred	DPRINTFN(4, "confidx=%d\n", conf_index);
1248184610Salfred
1249194228Sthompsa	err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d),
1250184610Salfred	    sizeof(*d), 0, UDESC_CONFIG, conf_index, 0);
1251184610Salfred	if (err) {
1252184610Salfred		goto done;
1253184610Salfred	}
1254184610Salfred	/* Extra sanity checking */
1255233774Shselasky	if (UGETW(d->wTotalLength) < (uint16_t)sizeof(*d)) {
1256184610Salfred		err = USB_ERR_INVAL;
1257184610Salfred	}
1258184610Salfreddone:
1259184610Salfred	return (err);
1260184610Salfred}
1261184610Salfred
1262184610Salfred/*------------------------------------------------------------------------*
1263194228Sthompsa *	usbd_req_get_config_desc_full
1264184610Salfred *
1265184610Salfred * This function gets the complete USB configuration descriptor and
1266184610Salfred * ensures that "wTotalLength" is correct.
1267184610Salfred *
1268184610Salfred * Returns:
1269184610Salfred *    0: Success
1270184610Salfred * Else: Failure
1271184610Salfred *------------------------------------------------------------------------*/
1272193045Sthompsausb_error_t
1273194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx,
1274192984Sthompsa    struct usb_config_descriptor **ppcd, struct malloc_type *mtype,
1275184610Salfred    uint8_t index)
1276184610Salfred{
1277192984Sthompsa	struct usb_config_descriptor cd;
1278192984Sthompsa	struct usb_config_descriptor *cdesc;
1279184610Salfred	uint16_t len;
1280193045Sthompsa	usb_error_t err;
1281184610Salfred
1282184610Salfred	DPRINTFN(4, "index=%d\n", index);
1283184610Salfred
1284184610Salfred	*ppcd = NULL;
1285184610Salfred
1286194228Sthompsa	err = usbd_req_get_config_desc(udev, mtx, &cd, index);
1287184610Salfred	if (err) {
1288184610Salfred		return (err);
1289184610Salfred	}
1290184610Salfred	/* get full descriptor */
1291184610Salfred	len = UGETW(cd.wTotalLength);
1292184610Salfred	if (len < sizeof(*cdesc)) {
1293184610Salfred		/* corrupt descriptor */
1294184610Salfred		return (USB_ERR_INVAL);
1295184610Salfred	}
1296184610Salfred	cdesc = malloc(len, mtype, M_WAITOK);
1297184610Salfred	if (cdesc == NULL) {
1298184610Salfred		return (USB_ERR_NOMEM);
1299184610Salfred	}
1300194228Sthompsa	err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0,
1301184610Salfred	    UDESC_CONFIG, index, 3);
1302184610Salfred	if (err) {
1303184610Salfred		free(cdesc, mtype);
1304184610Salfred		return (err);
1305184610Salfred	}
1306184610Salfred	/* make sure that the device is not fooling us: */
1307184610Salfred	USETW(cdesc->wTotalLength, len);
1308184610Salfred
1309184610Salfred	*ppcd = cdesc;
1310184610Salfred
1311184610Salfred	return (0);			/* success */
1312184610Salfred}
1313184610Salfred
1314184610Salfred/*------------------------------------------------------------------------*
1315194228Sthompsa *	usbd_req_get_device_desc
1316184610Salfred *
1317184610Salfred * Returns:
1318184610Salfred *    0: Success
1319184610Salfred * Else: Failure
1320184610Salfred *------------------------------------------------------------------------*/
1321193045Sthompsausb_error_t
1322194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx,
1323192984Sthompsa    struct usb_device_descriptor *d)
1324184610Salfred{
1325184610Salfred	DPRINTFN(4, "\n");
1326194228Sthompsa	return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d),
1327184610Salfred	    sizeof(*d), 0, UDESC_DEVICE, 0, 3));
1328184610Salfred}
1329184610Salfred
1330184610Salfred/*------------------------------------------------------------------------*
1331194228Sthompsa *	usbd_req_get_alt_interface_no
1332184610Salfred *
1333184610Salfred * Returns:
1334184610Salfred *    0: Success
1335184610Salfred * Else: Failure
1336184610Salfred *------------------------------------------------------------------------*/
1337193045Sthompsausb_error_t
1338194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx,
1339184610Salfred    uint8_t *alt_iface_no, uint8_t iface_index)
1340184610Salfred{
1341194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1342192984Sthompsa	struct usb_device_request req;
1343184610Salfred
1344195963Salfred	if ((iface == NULL) || (iface->idesc == NULL))
1345184610Salfred		return (USB_ERR_INVAL);
1346195963Salfred
1347184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1348184610Salfred	req.bRequest = UR_GET_INTERFACE;
1349184610Salfred	USETW(req.wValue, 0);
1350184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1351184610Salfred	req.wIndex[1] = 0;
1352184610Salfred	USETW(req.wLength, 1);
1353194228Sthompsa	return (usbd_do_request(udev, mtx, &req, alt_iface_no));
1354184610Salfred}
1355184610Salfred
1356184610Salfred/*------------------------------------------------------------------------*
1357194228Sthompsa *	usbd_req_set_alt_interface_no
1358184610Salfred *
1359184610Salfred * Returns:
1360184610Salfred *    0: Success
1361184610Salfred * Else: Failure
1362184610Salfred *------------------------------------------------------------------------*/
1363193045Sthompsausb_error_t
1364194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx,
1365184610Salfred    uint8_t iface_index, uint8_t alt_no)
1366184610Salfred{
1367194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1368192984Sthompsa	struct usb_device_request req;
1369184610Salfred
1370195963Salfred	if ((iface == NULL) || (iface->idesc == NULL))
1371184610Salfred		return (USB_ERR_INVAL);
1372195963Salfred
1373184610Salfred	req.bmRequestType = UT_WRITE_INTERFACE;
1374184610Salfred	req.bRequest = UR_SET_INTERFACE;
1375184610Salfred	req.wValue[0] = alt_no;
1376184610Salfred	req.wValue[1] = 0;
1377184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1378184610Salfred	req.wIndex[1] = 0;
1379184610Salfred	USETW(req.wLength, 0);
1380194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1381184610Salfred}
1382184610Salfred
1383184610Salfred/*------------------------------------------------------------------------*
1384194228Sthompsa *	usbd_req_get_device_status
1385184610Salfred *
1386184610Salfred * Returns:
1387184610Salfred *    0: Success
1388184610Salfred * Else: Failure
1389184610Salfred *------------------------------------------------------------------------*/
1390193045Sthompsausb_error_t
1391194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx,
1392192984Sthompsa    struct usb_status *st)
1393184610Salfred{
1394192984Sthompsa	struct usb_device_request req;
1395184610Salfred
1396184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1397184610Salfred	req.bRequest = UR_GET_STATUS;
1398184610Salfred	USETW(req.wValue, 0);
1399184610Salfred	USETW(req.wIndex, 0);
1400184610Salfred	USETW(req.wLength, sizeof(*st));
1401194228Sthompsa	return (usbd_do_request(udev, mtx, &req, st));
1402184610Salfred}
1403184610Salfred
1404184610Salfred/*------------------------------------------------------------------------*
1405194228Sthompsa *	usbd_req_get_hub_descriptor
1406184610Salfred *
1407184610Salfred * Returns:
1408184610Salfred *    0: Success
1409184610Salfred * Else: Failure
1410184610Salfred *------------------------------------------------------------------------*/
1411193045Sthompsausb_error_t
1412194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx,
1413192984Sthompsa    struct usb_hub_descriptor *hd, uint8_t nports)
1414184610Salfred{
1415192984Sthompsa	struct usb_device_request req;
1416184610Salfred	uint16_t len = (nports + 7 + (8 * 8)) / 8;
1417184610Salfred
1418184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
1419184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1420184610Salfred	USETW2(req.wValue, UDESC_HUB, 0);
1421184610Salfred	USETW(req.wIndex, 0);
1422184610Salfred	USETW(req.wLength, len);
1423194228Sthompsa	return (usbd_do_request(udev, mtx, &req, hd));
1424184610Salfred}
1425184610Salfred
1426184610Salfred/*------------------------------------------------------------------------*
1427213435Shselasky *	usbd_req_get_ss_hub_descriptor
1428213435Shselasky *
1429213435Shselasky * Returns:
1430213435Shselasky *    0: Success
1431213435Shselasky * Else: Failure
1432213435Shselasky *------------------------------------------------------------------------*/
1433213435Shselaskyusb_error_t
1434213435Shselaskyusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx,
1435213435Shselasky    struct usb_hub_ss_descriptor *hd, uint8_t nports)
1436213435Shselasky{
1437213435Shselasky	struct usb_device_request req;
1438213435Shselasky	uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8);
1439213435Shselasky
1440213435Shselasky	req.bmRequestType = UT_READ_CLASS_DEVICE;
1441213435Shselasky	req.bRequest = UR_GET_DESCRIPTOR;
1442213435Shselasky	USETW2(req.wValue, UDESC_SS_HUB, 0);
1443213435Shselasky	USETW(req.wIndex, 0);
1444213435Shselasky	USETW(req.wLength, len);
1445213435Shselasky	return (usbd_do_request(udev, mtx, &req, hd));
1446213435Shselasky}
1447213435Shselasky
1448213435Shselasky/*------------------------------------------------------------------------*
1449194228Sthompsa *	usbd_req_get_hub_status
1450184610Salfred *
1451184610Salfred * Returns:
1452184610Salfred *    0: Success
1453184610Salfred * Else: Failure
1454184610Salfred *------------------------------------------------------------------------*/
1455193045Sthompsausb_error_t
1456194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx,
1457192984Sthompsa    struct usb_hub_status *st)
1458184610Salfred{
1459192984Sthompsa	struct usb_device_request req;
1460184610Salfred
1461184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
1462184610Salfred	req.bRequest = UR_GET_STATUS;
1463184610Salfred	USETW(req.wValue, 0);
1464184610Salfred	USETW(req.wIndex, 0);
1465192984Sthompsa	USETW(req.wLength, sizeof(struct usb_hub_status));
1466194228Sthompsa	return (usbd_do_request(udev, mtx, &req, st));
1467184610Salfred}
1468184610Salfred
1469184610Salfred/*------------------------------------------------------------------------*
1470194228Sthompsa *	usbd_req_set_address
1471184610Salfred *
1472184610Salfred * This function is used to set the address for an USB device. After
1473184610Salfred * port reset the USB device will respond at address zero.
1474184610Salfred *
1475184610Salfred * Returns:
1476184610Salfred *    0: Success
1477184610Salfred * Else: Failure
1478184610Salfred *------------------------------------------------------------------------*/
1479193045Sthompsausb_error_t
1480194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr)
1481184610Salfred{
1482192984Sthompsa	struct usb_device_request req;
1483213435Shselasky	usb_error_t err;
1484184610Salfred
1485184610Salfred	DPRINTFN(6, "setting device address=%d\n", addr);
1486184610Salfred
1487184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1488184610Salfred	req.bRequest = UR_SET_ADDRESS;
1489184610Salfred	USETW(req.wValue, addr);
1490184610Salfred	USETW(req.wIndex, 0);
1491184610Salfred	USETW(req.wLength, 0);
1492184610Salfred
1493213435Shselasky	err = USB_ERR_INVAL;
1494213435Shselasky
1495213435Shselasky	/* check if USB controller handles set address */
1496213435Shselasky	if (udev->bus->methods->set_address != NULL)
1497213435Shselasky		err = (udev->bus->methods->set_address) (udev, mtx, addr);
1498213435Shselasky
1499213435Shselasky	if (err != USB_ERR_INVAL)
1500213435Shselasky		goto done;
1501213435Shselasky
1502184610Salfred	/* Setting the address should not take more than 1 second ! */
1503213435Shselasky	err = usbd_do_request_flags(udev, mtx, &req, NULL,
1504213435Shselasky	    USB_DELAY_STATUS_STAGE, NULL, 1000);
1505213435Shselasky
1506213435Shselaskydone:
1507213435Shselasky	/* allow device time to set new address */
1508213435Shselasky	usb_pause_mtx(mtx,
1509241987Shselasky	    USB_MS_TO_TICKS(usb_set_address_settle));
1510213435Shselasky
1511213435Shselasky	return (err);
1512184610Salfred}
1513184610Salfred
1514184610Salfred/*------------------------------------------------------------------------*
1515194228Sthompsa *	usbd_req_get_port_status
1516184610Salfred *
1517184610Salfred * Returns:
1518184610Salfred *    0: Success
1519184610Salfred * Else: Failure
1520184610Salfred *------------------------------------------------------------------------*/
1521193045Sthompsausb_error_t
1522194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx,
1523192984Sthompsa    struct usb_port_status *ps, uint8_t port)
1524184610Salfred{
1525192984Sthompsa	struct usb_device_request req;
1526184610Salfred
1527184610Salfred	req.bmRequestType = UT_READ_CLASS_OTHER;
1528184610Salfred	req.bRequest = UR_GET_STATUS;
1529184610Salfred	USETW(req.wValue, 0);
1530184610Salfred	req.wIndex[0] = port;
1531184610Salfred	req.wIndex[1] = 0;
1532184610Salfred	USETW(req.wLength, sizeof *ps);
1533194228Sthompsa	return (usbd_do_request(udev, mtx, &req, ps));
1534184610Salfred}
1535184610Salfred
1536184610Salfred/*------------------------------------------------------------------------*
1537194228Sthompsa *	usbd_req_clear_hub_feature
1538184610Salfred *
1539184610Salfred * Returns:
1540184610Salfred *    0: Success
1541184610Salfred * Else: Failure
1542184610Salfred *------------------------------------------------------------------------*/
1543193045Sthompsausb_error_t
1544194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx,
1545184610Salfred    uint16_t sel)
1546184610Salfred{
1547192984Sthompsa	struct usb_device_request req;
1548184610Salfred
1549184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1550184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1551184610Salfred	USETW(req.wValue, sel);
1552184610Salfred	USETW(req.wIndex, 0);
1553184610Salfred	USETW(req.wLength, 0);
1554194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1555184610Salfred}
1556184610Salfred
1557184610Salfred/*------------------------------------------------------------------------*
1558194228Sthompsa *	usbd_req_set_hub_feature
1559184610Salfred *
1560184610Salfred * Returns:
1561184610Salfred *    0: Success
1562184610Salfred * Else: Failure
1563184610Salfred *------------------------------------------------------------------------*/
1564193045Sthompsausb_error_t
1565194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx,
1566184610Salfred    uint16_t sel)
1567184610Salfred{
1568192984Sthompsa	struct usb_device_request req;
1569184610Salfred
1570184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1571184610Salfred	req.bRequest = UR_SET_FEATURE;
1572184610Salfred	USETW(req.wValue, sel);
1573184610Salfred	USETW(req.wIndex, 0);
1574184610Salfred	USETW(req.wLength, 0);
1575194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1576184610Salfred}
1577184610Salfred
1578184610Salfred/*------------------------------------------------------------------------*
1579213435Shselasky *	usbd_req_set_hub_u1_timeout
1580213435Shselasky *
1581213435Shselasky * Returns:
1582213435Shselasky *    0: Success
1583213435Shselasky * Else: Failure
1584213435Shselasky *------------------------------------------------------------------------*/
1585213435Shselaskyusb_error_t
1586213435Shselaskyusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx,
1587213435Shselasky    uint8_t port, uint8_t timeout)
1588213435Shselasky{
1589213435Shselasky	struct usb_device_request req;
1590213435Shselasky
1591213435Shselasky	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1592213435Shselasky	req.bRequest = UR_SET_FEATURE;
1593213435Shselasky	USETW(req.wValue, UHF_PORT_U1_TIMEOUT);
1594213435Shselasky	req.wIndex[0] = port;
1595213435Shselasky	req.wIndex[1] = timeout;
1596213435Shselasky	USETW(req.wLength, 0);
1597213435Shselasky	return (usbd_do_request(udev, mtx, &req, 0));
1598213435Shselasky}
1599213435Shselasky
1600213435Shselasky/*------------------------------------------------------------------------*
1601213435Shselasky *	usbd_req_set_hub_u2_timeout
1602213435Shselasky *
1603213435Shselasky * Returns:
1604213435Shselasky *    0: Success
1605213435Shselasky * Else: Failure
1606213435Shselasky *------------------------------------------------------------------------*/
1607213435Shselaskyusb_error_t
1608213435Shselaskyusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx,
1609213435Shselasky    uint8_t port, uint8_t timeout)
1610213435Shselasky{
1611213435Shselasky	struct usb_device_request req;
1612213435Shselasky
1613213435Shselasky	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1614213435Shselasky	req.bRequest = UR_SET_FEATURE;
1615213435Shselasky	USETW(req.wValue, UHF_PORT_U2_TIMEOUT);
1616213435Shselasky	req.wIndex[0] = port;
1617213435Shselasky	req.wIndex[1] = timeout;
1618213435Shselasky	USETW(req.wLength, 0);
1619213435Shselasky	return (usbd_do_request(udev, mtx, &req, 0));
1620213435Shselasky}
1621213435Shselasky
1622213435Shselasky/*------------------------------------------------------------------------*
1623213435Shselasky *	usbd_req_set_hub_depth
1624213435Shselasky *
1625213435Shselasky * Returns:
1626213435Shselasky *    0: Success
1627213435Shselasky * Else: Failure
1628213435Shselasky *------------------------------------------------------------------------*/
1629213435Shselaskyusb_error_t
1630213435Shselaskyusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx,
1631213435Shselasky    uint16_t depth)
1632213435Shselasky{
1633213435Shselasky	struct usb_device_request req;
1634213435Shselasky
1635213435Shselasky	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1636213435Shselasky	req.bRequest = UR_SET_HUB_DEPTH;
1637213435Shselasky	USETW(req.wValue, depth);
1638213435Shselasky	USETW(req.wIndex, 0);
1639213435Shselasky	USETW(req.wLength, 0);
1640213435Shselasky	return (usbd_do_request(udev, mtx, &req, 0));
1641213435Shselasky}
1642213435Shselasky
1643213435Shselasky/*------------------------------------------------------------------------*
1644194228Sthompsa *	usbd_req_clear_port_feature
1645184610Salfred *
1646184610Salfred * Returns:
1647184610Salfred *    0: Success
1648184610Salfred * Else: Failure
1649184610Salfred *------------------------------------------------------------------------*/
1650193045Sthompsausb_error_t
1651194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx,
1652184610Salfred    uint8_t port, uint16_t sel)
1653184610Salfred{
1654192984Sthompsa	struct usb_device_request req;
1655184610Salfred
1656184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1657184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1658184610Salfred	USETW(req.wValue, sel);
1659184610Salfred	req.wIndex[0] = port;
1660184610Salfred	req.wIndex[1] = 0;
1661184610Salfred	USETW(req.wLength, 0);
1662194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1663184610Salfred}
1664184610Salfred
1665184610Salfred/*------------------------------------------------------------------------*
1666194228Sthompsa *	usbd_req_set_port_feature
1667184610Salfred *
1668184610Salfred * Returns:
1669184610Salfred *    0: Success
1670184610Salfred * Else: Failure
1671184610Salfred *------------------------------------------------------------------------*/
1672193045Sthompsausb_error_t
1673194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx,
1674184610Salfred    uint8_t port, uint16_t sel)
1675184610Salfred{
1676192984Sthompsa	struct usb_device_request req;
1677184610Salfred
1678184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1679184610Salfred	req.bRequest = UR_SET_FEATURE;
1680184610Salfred	USETW(req.wValue, sel);
1681184610Salfred	req.wIndex[0] = port;
1682184610Salfred	req.wIndex[1] = 0;
1683184610Salfred	USETW(req.wLength, 0);
1684194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1685184610Salfred}
1686184610Salfred
1687184610Salfred/*------------------------------------------------------------------------*
1688194228Sthompsa *	usbd_req_set_protocol
1689184610Salfred *
1690184610Salfred * Returns:
1691184610Salfred *    0: Success
1692184610Salfred * Else: Failure
1693184610Salfred *------------------------------------------------------------------------*/
1694193045Sthompsausb_error_t
1695194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx,
1696184610Salfred    uint8_t iface_index, uint16_t report)
1697184610Salfred{
1698194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1699192984Sthompsa	struct usb_device_request req;
1700184610Salfred
1701184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1702184610Salfred		return (USB_ERR_INVAL);
1703184610Salfred	}
1704184610Salfred	DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n",
1705184610Salfred	    iface, report, iface->idesc->bInterfaceNumber);
1706184610Salfred
1707184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1708184610Salfred	req.bRequest = UR_SET_PROTOCOL;
1709184610Salfred	USETW(req.wValue, report);
1710184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1711184610Salfred	req.wIndex[1] = 0;
1712184610Salfred	USETW(req.wLength, 0);
1713194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1714184610Salfred}
1715184610Salfred
1716184610Salfred/*------------------------------------------------------------------------*
1717194228Sthompsa *	usbd_req_set_report
1718184610Salfred *
1719184610Salfred * Returns:
1720184610Salfred *    0: Success
1721184610Salfred * Else: Failure
1722184610Salfred *------------------------------------------------------------------------*/
1723193045Sthompsausb_error_t
1724194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len,
1725184610Salfred    uint8_t iface_index, uint8_t type, uint8_t id)
1726184610Salfred{
1727194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1728192984Sthompsa	struct usb_device_request req;
1729184610Salfred
1730184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1731184610Salfred		return (USB_ERR_INVAL);
1732184610Salfred	}
1733184610Salfred	DPRINTFN(5, "len=%d\n", len);
1734184610Salfred
1735184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1736184610Salfred	req.bRequest = UR_SET_REPORT;
1737184610Salfred	USETW2(req.wValue, type, id);
1738184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1739184610Salfred	req.wIndex[1] = 0;
1740184610Salfred	USETW(req.wLength, len);
1741194228Sthompsa	return (usbd_do_request(udev, mtx, &req, data));
1742184610Salfred}
1743184610Salfred
1744184610Salfred/*------------------------------------------------------------------------*
1745194228Sthompsa *	usbd_req_get_report
1746184610Salfred *
1747184610Salfred * Returns:
1748184610Salfred *    0: Success
1749184610Salfred * Else: Failure
1750184610Salfred *------------------------------------------------------------------------*/
1751193045Sthompsausb_error_t
1752194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data,
1753184610Salfred    uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
1754184610Salfred{
1755194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1756192984Sthompsa	struct usb_device_request req;
1757184610Salfred
1758224728Smav	if ((iface == NULL) || (iface->idesc == NULL)) {
1759184610Salfred		return (USB_ERR_INVAL);
1760184610Salfred	}
1761184610Salfred	DPRINTFN(5, "len=%d\n", len);
1762184610Salfred
1763184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1764184610Salfred	req.bRequest = UR_GET_REPORT;
1765184610Salfred	USETW2(req.wValue, type, id);
1766184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1767184610Salfred	req.wIndex[1] = 0;
1768184610Salfred	USETW(req.wLength, len);
1769194228Sthompsa	return (usbd_do_request(udev, mtx, &req, data));
1770184610Salfred}
1771184610Salfred
1772184610Salfred/*------------------------------------------------------------------------*
1773194228Sthompsa *	usbd_req_set_idle
1774184610Salfred *
1775184610Salfred * Returns:
1776184610Salfred *    0: Success
1777184610Salfred * Else: Failure
1778184610Salfred *------------------------------------------------------------------------*/
1779193045Sthompsausb_error_t
1780194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx,
1781184610Salfred    uint8_t iface_index, uint8_t duration, uint8_t id)
1782184610Salfred{
1783194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1784192984Sthompsa	struct usb_device_request req;
1785184610Salfred
1786184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1787184610Salfred		return (USB_ERR_INVAL);
1788184610Salfred	}
1789184610Salfred	DPRINTFN(5, "%d %d\n", duration, id);
1790184610Salfred
1791184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1792184610Salfred	req.bRequest = UR_SET_IDLE;
1793184610Salfred	USETW2(req.wValue, duration, id);
1794184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1795184610Salfred	req.wIndex[1] = 0;
1796184610Salfred	USETW(req.wLength, 0);
1797194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1798184610Salfred}
1799184610Salfred
1800184610Salfred/*------------------------------------------------------------------------*
1801194228Sthompsa *	usbd_req_get_report_descriptor
1802184610Salfred *
1803184610Salfred * Returns:
1804184610Salfred *    0: Success
1805184610Salfred * Else: Failure
1806184610Salfred *------------------------------------------------------------------------*/
1807193045Sthompsausb_error_t
1808194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx,
1809184610Salfred    void *d, uint16_t size, uint8_t iface_index)
1810184610Salfred{
1811194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1812192984Sthompsa	struct usb_device_request req;
1813184610Salfred
1814184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1815184610Salfred		return (USB_ERR_INVAL);
1816184610Salfred	}
1817184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1818184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1819184610Salfred	USETW2(req.wValue, UDESC_REPORT, 0);	/* report id should be 0 */
1820184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1821184610Salfred	req.wIndex[1] = 0;
1822184610Salfred	USETW(req.wLength, size);
1823194228Sthompsa	return (usbd_do_request(udev, mtx, &req, d));
1824184610Salfred}
1825184610Salfred
1826184610Salfred/*------------------------------------------------------------------------*
1827194228Sthompsa *	usbd_req_set_config
1828184610Salfred *
1829184610Salfred * This function is used to select the current configuration number in
1830184610Salfred * both USB device side mode and USB host side mode. When setting the
1831184610Salfred * configuration the function of the interfaces can change.
1832184610Salfred *
1833184610Salfred * Returns:
1834184610Salfred *    0: Success
1835184610Salfred * Else: Failure
1836184610Salfred *------------------------------------------------------------------------*/
1837193045Sthompsausb_error_t
1838194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf)
1839184610Salfred{
1840192984Sthompsa	struct usb_device_request req;
1841184610Salfred
1842184610Salfred	DPRINTF("setting config %d\n", conf);
1843184610Salfred
1844184610Salfred	/* do "set configuration" request */
1845184610Salfred
1846184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1847184610Salfred	req.bRequest = UR_SET_CONFIG;
1848184610Salfred	req.wValue[0] = conf;
1849184610Salfred	req.wValue[1] = 0;
1850184610Salfred	USETW(req.wIndex, 0);
1851184610Salfred	USETW(req.wLength, 0);
1852194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1853184610Salfred}
1854184610Salfred
1855184610Salfred/*------------------------------------------------------------------------*
1856194228Sthompsa *	usbd_req_get_config
1857184610Salfred *
1858184610Salfred * Returns:
1859184610Salfred *    0: Success
1860184610Salfred * Else: Failure
1861184610Salfred *------------------------------------------------------------------------*/
1862193045Sthompsausb_error_t
1863194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf)
1864184610Salfred{
1865192984Sthompsa	struct usb_device_request req;
1866184610Salfred
1867184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1868184610Salfred	req.bRequest = UR_GET_CONFIG;
1869184610Salfred	USETW(req.wValue, 0);
1870184610Salfred	USETW(req.wIndex, 0);
1871184610Salfred	USETW(req.wLength, 1);
1872194228Sthompsa	return (usbd_do_request(udev, mtx, &req, pconf));
1873184610Salfred}
1874184610Salfred
1875184610Salfred/*------------------------------------------------------------------------*
1876213435Shselasky *	usbd_setup_device_desc
1877213435Shselasky *------------------------------------------------------------------------*/
1878213435Shselaskyusb_error_t
1879213435Shselaskyusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx)
1880213435Shselasky{
1881213435Shselasky	usb_error_t err;
1882213435Shselasky
1883213435Shselasky	/*
1884213435Shselasky	 * Get the first 8 bytes of the device descriptor !
1885213435Shselasky	 *
1886213435Shselasky	 * NOTE: "usbd_do_request()" will check the device descriptor
1887213435Shselasky	 * next time we do a request to see if the maximum packet size
1888213435Shselasky	 * changed! The 8 first bytes of the device descriptor
1889213435Shselasky	 * contains the maximum packet size to use on control endpoint
1890213435Shselasky	 * 0. If this value is different from "USB_MAX_IPACKET" a new
1891213435Shselasky	 * USB control request will be setup!
1892213435Shselasky	 */
1893213435Shselasky	switch (udev->speed) {
1894213435Shselasky	case USB_SPEED_FULL:
1895248246Shselasky		if (usb_full_ddesc != 0) {
1896248246Shselasky			/* get full device descriptor */
1897248246Shselasky			err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc);
1898248246Shselasky			if (err == 0)
1899248246Shselasky				break;
1900248246Shselasky		}
1901248246Shselasky
1902248246Shselasky		/* get partial device descriptor, some devices crash on this */
1903213435Shselasky		err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc,
1904213435Shselasky		    USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0);
1905248246Shselasky		if (err != 0)
1906248246Shselasky			break;
1907248246Shselasky
1908248246Shselasky		/* get the full device descriptor */
1909248246Shselasky		err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc);
1910213435Shselasky		break;
1911248246Shselasky
1912213435Shselasky	default:
1913248247Shselasky		DPRINTF("Minimum bMaxPacketSize is large enough "
1914248246Shselasky		    "to hold the complete device descriptor or "
1915248247Shselasky		    "only one bMaxPacketSize choice\n");
1916248246Shselasky
1917248246Shselasky		/* get the full device descriptor */
1918248246Shselasky		err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc);
1919248246Shselasky
1920248246Shselasky		/* try one more time, if error */
1921248246Shselasky		if (err != 0)
1922248246Shselasky			err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc);
1923213435Shselasky		break;
1924213435Shselasky	}
1925213435Shselasky
1926248246Shselasky	if (err != 0) {
1927248246Shselasky		DPRINTFN(0, "getting device descriptor "
1928248246Shselasky		    "at addr %d failed, %s\n", udev->address,
1929248246Shselasky		    usbd_errstr(err));
1930213435Shselasky		return (err);
1931213435Shselasky	}
1932213435Shselasky
1933213435Shselasky	DPRINTF("adding unit addr=%d, rev=%02x, class=%d, "
1934213435Shselasky	    "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
1935213435Shselasky	    udev->address, UGETW(udev->ddesc.bcdUSB),
1936213435Shselasky	    udev->ddesc.bDeviceClass,
1937213435Shselasky	    udev->ddesc.bDeviceSubClass,
1938213435Shselasky	    udev->ddesc.bDeviceProtocol,
1939213435Shselasky	    udev->ddesc.bMaxPacketSize,
1940213435Shselasky	    udev->ddesc.bLength,
1941213435Shselasky	    udev->speed);
1942213435Shselasky
1943213435Shselasky	return (err);
1944213435Shselasky}
1945213435Shselasky
1946213435Shselasky/*------------------------------------------------------------------------*
1947194228Sthompsa *	usbd_req_re_enumerate
1948184610Salfred *
1949185087Salfred * NOTE: After this function returns the hardware is in the
1950185087Salfred * unconfigured state! The application is responsible for setting a
1951185087Salfred * new configuration.
1952185087Salfred *
1953184610Salfred * Returns:
1954184610Salfred *    0: Success
1955184610Salfred * Else: Failure
1956184610Salfred *------------------------------------------------------------------------*/
1957193045Sthompsausb_error_t
1958194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx)
1959184610Salfred{
1960192984Sthompsa	struct usb_device *parent_hub;
1961193045Sthompsa	usb_error_t err;
1962184610Salfred	uint8_t old_addr;
1963186730Salfred	uint8_t do_retry = 1;
1964184610Salfred
1965192499Sthompsa	if (udev->flags.usb_mode != USB_MODE_HOST) {
1966185290Salfred		return (USB_ERR_INVAL);
1967185290Salfred	}
1968184610Salfred	old_addr = udev->address;
1969184610Salfred	parent_hub = udev->parent_hub;
1970184610Salfred	if (parent_hub == NULL) {
1971185290Salfred		return (USB_ERR_INVAL);
1972184610Salfred	}
1973186730Salfredretry:
1974222786Shselasky	/*
1975222786Shselasky	 * Try to reset the High Speed parent HUB of a LOW- or FULL-
1976222786Shselasky	 * speed device, if any.
1977222786Shselasky	 */
1978222786Shselasky	if (udev->parent_hs_hub != NULL &&
1979222786Shselasky	    udev->speed != USB_SPEED_HIGH) {
1980222786Shselasky		DPRINTF("Trying to reset parent High Speed TT.\n");
1981222786Shselasky		err = usbd_req_reset_tt(udev->parent_hs_hub, NULL,
1982222786Shselasky		    udev->hs_port_no);
1983222786Shselasky		if (err) {
1984222786Shselasky			DPRINTF("Resetting parent High "
1985222786Shselasky			    "Speed TT failed (%s).\n",
1986222786Shselasky			    usbd_errstr(err));
1987222786Shselasky		}
1988222786Shselasky	}
1989222786Shselasky
1990230091Shselasky	/* Try to warm reset first */
1991230091Shselasky	if (parent_hub->speed == USB_SPEED_SUPER)
1992230091Shselasky		usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no);
1993230091Shselasky
1994222786Shselasky	/* Try to reset the parent HUB port. */
1995194228Sthompsa	err = usbd_req_reset_port(parent_hub, mtx, udev->port_no);
1996184610Salfred	if (err) {
1997190739Sthompsa		DPRINTFN(0, "addr=%d, port reset failed, %s\n",
1998194228Sthompsa		    old_addr, usbd_errstr(err));
1999184610Salfred		goto done;
2000184610Salfred	}
2001213435Shselasky
2002184610Salfred	/*
2003184610Salfred	 * After that the port has been reset our device should be at
2004184610Salfred	 * address zero:
2005184610Salfred	 */
2006184610Salfred	udev->address = USB_START_ADDR;
2007184610Salfred
2008185290Salfred	/* reset "bMaxPacketSize" */
2009185290Salfred	udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET;
2010185290Salfred
2011213435Shselasky	/* reset USB state */
2012213435Shselasky	usb_set_device_state(udev, USB_STATE_POWERED);
2013213435Shselasky
2014184610Salfred	/*
2015184610Salfred	 * Restore device address:
2016184610Salfred	 */
2017194228Sthompsa	err = usbd_req_set_address(udev, mtx, old_addr);
2018184610Salfred	if (err) {
2019184610Salfred		/* XXX ignore any errors! */
2020190739Sthompsa		DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n",
2021194228Sthompsa		    old_addr, usbd_errstr(err));
2022184610Salfred	}
2023213435Shselasky	/*
2024213435Shselasky	 * Restore device address, if the controller driver did not
2025213435Shselasky	 * set a new one:
2026213435Shselasky	 */
2027213435Shselasky	if (udev->address == USB_START_ADDR)
2028213435Shselasky		udev->address = old_addr;
2029184610Salfred
2030213435Shselasky	/* setup the device descriptor and the initial "wMaxPacketSize" */
2031213435Shselasky	err = usbd_setup_device_desc(udev, mtx);
2032184610Salfred
2033184610Salfreddone:
2034186730Salfred	if (err && do_retry) {
2035186730Salfred		/* give the USB firmware some time to load */
2036194228Sthompsa		usb_pause_mtx(mtx, hz / 2);
2037186730Salfred		/* no more retries after this retry */
2038186730Salfred		do_retry = 0;
2039186730Salfred		/* try again */
2040186730Salfred		goto retry;
2041186730Salfred	}
2042184610Salfred	/* restore address */
2043213435Shselasky	if (udev->address == USB_START_ADDR)
2044213435Shselasky		udev->address = old_addr;
2045213435Shselasky	/* update state, if successful */
2046213435Shselasky	if (err == 0)
2047213435Shselasky		usb_set_device_state(udev, USB_STATE_ADDRESSED);
2048184610Salfred	return (err);
2049184610Salfred}
2050186730Salfred
2051186730Salfred/*------------------------------------------------------------------------*
2052194228Sthompsa *	usbd_req_clear_device_feature
2053186730Salfred *
2054186730Salfred * Returns:
2055186730Salfred *    0: Success
2056186730Salfred * Else: Failure
2057186730Salfred *------------------------------------------------------------------------*/
2058193045Sthompsausb_error_t
2059194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx,
2060186730Salfred    uint16_t sel)
2061186730Salfred{
2062192984Sthompsa	struct usb_device_request req;
2063186730Salfred
2064186730Salfred	req.bmRequestType = UT_WRITE_DEVICE;
2065186730Salfred	req.bRequest = UR_CLEAR_FEATURE;
2066186730Salfred	USETW(req.wValue, sel);
2067186730Salfred	USETW(req.wIndex, 0);
2068186730Salfred	USETW(req.wLength, 0);
2069194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
2070186730Salfred}
2071186730Salfred
2072186730Salfred/*------------------------------------------------------------------------*
2073194228Sthompsa *	usbd_req_set_device_feature
2074186730Salfred *
2075186730Salfred * Returns:
2076186730Salfred *    0: Success
2077186730Salfred * Else: Failure
2078186730Salfred *------------------------------------------------------------------------*/
2079193045Sthompsausb_error_t
2080194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx,
2081186730Salfred    uint16_t sel)
2082186730Salfred{
2083192984Sthompsa	struct usb_device_request req;
2084186730Salfred
2085186730Salfred	req.bmRequestType = UT_WRITE_DEVICE;
2086186730Salfred	req.bRequest = UR_SET_FEATURE;
2087186730Salfred	USETW(req.wValue, sel);
2088186730Salfred	USETW(req.wIndex, 0);
2089186730Salfred	USETW(req.wLength, 0);
2090194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
2091186730Salfred}
2092222786Shselasky
2093222786Shselasky/*------------------------------------------------------------------------*
2094222786Shselasky *	usbd_req_reset_tt
2095222786Shselasky *
2096222786Shselasky * Returns:
2097222786Shselasky *    0: Success
2098222786Shselasky * Else: Failure
2099222786Shselasky *------------------------------------------------------------------------*/
2100222786Shselaskyusb_error_t
2101222786Shselaskyusbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx,
2102222786Shselasky    uint8_t port)
2103222786Shselasky{
2104222786Shselasky	struct usb_device_request req;
2105222786Shselasky
2106222786Shselasky	/* For single TT HUBs the port should be 1 */
2107222786Shselasky
2108222786Shselasky	if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
2109222786Shselasky	    udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
2110222786Shselasky		port = 1;
2111222786Shselasky
2112222786Shselasky	req.bmRequestType = UT_WRITE_CLASS_OTHER;
2113222786Shselasky	req.bRequest = UR_RESET_TT;
2114222786Shselasky	USETW(req.wValue, 0);
2115222786Shselasky	req.wIndex[0] = port;
2116222786Shselasky	req.wIndex[1] = 0;
2117222786Shselasky	USETW(req.wLength, 0);
2118222786Shselasky	return (usbd_do_request(udev, mtx, &req, 0));
2119222786Shselasky}
2120222786Shselasky
2121222786Shselasky/*------------------------------------------------------------------------*
2122222786Shselasky *	usbd_req_clear_tt_buffer
2123222786Shselasky *
2124222786Shselasky * For single TT HUBs the port should be 1.
2125222786Shselasky *
2126222786Shselasky * Returns:
2127222786Shselasky *    0: Success
2128222786Shselasky * Else: Failure
2129222786Shselasky *------------------------------------------------------------------------*/
2130222786Shselaskyusb_error_t
2131222786Shselaskyusbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx,
2132222786Shselasky    uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint)
2133222786Shselasky{
2134222786Shselasky	struct usb_device_request req;
2135222786Shselasky	uint16_t wValue;
2136222786Shselasky
2137222786Shselasky	/* For single TT HUBs the port should be 1 */
2138222786Shselasky
2139222786Shselasky	if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
2140222786Shselasky	    udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
2141222786Shselasky		port = 1;
2142222786Shselasky
2143222786Shselasky	wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) |
2144222786Shselasky	    ((endpoint & 0x80) << 8) | ((type & 3) << 12);
2145222786Shselasky
2146222786Shselasky	req.bmRequestType = UT_WRITE_CLASS_OTHER;
2147222786Shselasky	req.bRequest = UR_CLEAR_TT_BUFFER;
2148222786Shselasky	USETW(req.wValue, wValue);
2149222786Shselasky	req.wIndex[0] = port;
2150222786Shselasky	req.wIndex[1] = 0;
2151222786Shselasky	USETW(req.wLength, 0);
2152222786Shselasky	return (usbd_do_request(udev, mtx, &req, 0));
2153222786Shselasky}
2154230032Shselasky
2155230032Shselasky/*------------------------------------------------------------------------*
2156230032Shselasky *	usbd_req_set_port_link_state
2157230032Shselasky *
2158230032Shselasky * USB 3.0 specific request
2159230032Shselasky *
2160230032Shselasky * Returns:
2161230032Shselasky *    0: Success
2162230032Shselasky * Else: Failure
2163230032Shselasky *------------------------------------------------------------------------*/
2164230032Shselaskyusb_error_t
2165230032Shselaskyusbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx,
2166230032Shselasky    uint8_t port, uint8_t link_state)
2167230032Shselasky{
2168230032Shselasky	struct usb_device_request req;
2169230032Shselasky
2170230032Shselasky	req.bmRequestType = UT_WRITE_CLASS_OTHER;
2171230032Shselasky	req.bRequest = UR_SET_FEATURE;
2172230032Shselasky	USETW(req.wValue, UHF_PORT_LINK_STATE);
2173230032Shselasky	req.wIndex[0] = port;
2174230032Shselasky	req.wIndex[1] = link_state;
2175230032Shselasky	USETW(req.wLength, 0);
2176230032Shselasky	return (usbd_do_request(udev, mtx, &req, 0));
2177230032Shselasky}
2178233771Shselasky
2179233771Shselasky/*------------------------------------------------------------------------*
2180233771Shselasky *		usbd_req_set_lpm_info
2181233771Shselasky *
2182233771Shselasky * USB 2.0 specific request for Link Power Management.
2183233771Shselasky *
2184233771Shselasky * Returns:
2185233771Shselasky * 0:				Success
2186233771Shselasky * USB_ERR_PENDING_REQUESTS:	NYET
2187233771Shselasky * USB_ERR_TIMEOUT:		TIMEOUT
2188233771Shselasky * USB_ERR_STALL:		STALL
2189233771Shselasky * Else:			Failure
2190233771Shselasky *------------------------------------------------------------------------*/
2191233771Shselaskyusb_error_t
2192233771Shselaskyusbd_req_set_lpm_info(struct usb_device *udev, struct mtx *mtx,
2193233771Shselasky    uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe)
2194233771Shselasky{
2195233771Shselasky	struct usb_device_request req;
2196233771Shselasky	usb_error_t err;
2197233771Shselasky	uint8_t buf[1];
2198233771Shselasky
2199233771Shselasky	req.bmRequestType = UT_WRITE_CLASS_OTHER;
2200233771Shselasky	req.bRequest = UR_SET_AND_TEST;
2201233771Shselasky	USETW(req.wValue, UHF_PORT_L1);
2202233771Shselasky	req.wIndex[0] = (port & 0xF) | ((besl & 0xF) << 4);
2203233771Shselasky	req.wIndex[1] = (addr & 0x7F) | (rwe ? 0x80 : 0x00);
2204233771Shselasky	USETW(req.wLength, sizeof(buf));
2205233771Shselasky
2206233771Shselasky	/* set default value in case of short transfer */
2207233771Shselasky	buf[0] = 0x00;
2208233771Shselasky
2209233771Shselasky	err = usbd_do_request(udev, mtx, &req, buf);
2210233771Shselasky	if (err)
2211233771Shselasky		return (err);
2212233771Shselasky
2213233771Shselasky	switch (buf[0]) {
2214233771Shselasky	case 0x00:	/* SUCCESS */
2215233771Shselasky		break;
2216233771Shselasky	case 0x10:	/* NYET */
2217233771Shselasky		err = USB_ERR_PENDING_REQUESTS;
2218233771Shselasky		break;
2219233771Shselasky	case 0x11:	/* TIMEOUT */
2220233771Shselasky		err = USB_ERR_TIMEOUT;
2221233771Shselasky		break;
2222233771Shselasky	case 0x30:	/* STALL */
2223233771Shselasky		err = USB_ERR_STALLED;
2224233771Shselasky		break;
2225233771Shselasky	default:	/* reserved */
2226233771Shselasky		err = USB_ERR_IOERROR;
2227233771Shselasky		break;
2228233771Shselasky	}
2229233771Shselasky	return (err);
2230233771Shselasky}
2231233771Shselasky
2232