usb_request.c revision 213433
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 213433 2010-10-04 22:45:17Z 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
29194677Sthompsa#include <sys/stdint.h>
30194677Sthompsa#include <sys/stddef.h>
31194677Sthompsa#include <sys/param.h>
32194677Sthompsa#include <sys/queue.h>
33194677Sthompsa#include <sys/types.h>
34194677Sthompsa#include <sys/systm.h>
35194677Sthompsa#include <sys/kernel.h>
36194677Sthompsa#include <sys/bus.h>
37194677Sthompsa#include <sys/linker_set.h>
38194677Sthompsa#include <sys/module.h>
39194677Sthompsa#include <sys/lock.h>
40194677Sthompsa#include <sys/mutex.h>
41194677Sthompsa#include <sys/condvar.h>
42194677Sthompsa#include <sys/sysctl.h>
43194677Sthompsa#include <sys/sx.h>
44194677Sthompsa#include <sys/unistd.h>
45194677Sthompsa#include <sys/callout.h>
46194677Sthompsa#include <sys/malloc.h>
47194677Sthompsa#include <sys/priv.h>
48194677Sthompsa
49188942Sthompsa#include <dev/usb/usb.h>
50194677Sthompsa#include <dev/usb/usbdi.h>
51194677Sthompsa#include <dev/usb/usbdi_util.h>
52188942Sthompsa#include <dev/usb/usb_ioctl.h>
53188942Sthompsa#include <dev/usb/usbhid.h>
54184610Salfred
55194228Sthompsa#define	USB_DEBUG_VAR usb_debug
56184610Salfred
57188942Sthompsa#include <dev/usb/usb_core.h>
58188942Sthompsa#include <dev/usb/usb_busdma.h>
59188942Sthompsa#include <dev/usb/usb_request.h>
60188942Sthompsa#include <dev/usb/usb_process.h>
61188942Sthompsa#include <dev/usb/usb_transfer.h>
62188942Sthompsa#include <dev/usb/usb_debug.h>
63188942Sthompsa#include <dev/usb/usb_device.h>
64188942Sthompsa#include <dev/usb/usb_util.h>
65188942Sthompsa#include <dev/usb/usb_dynamic.h>
66184610Salfred
67188942Sthompsa#include <dev/usb/usb_controller.h>
68188942Sthompsa#include <dev/usb/usb_bus.h>
69184610Salfred#include <sys/ctype.h>
70184610Salfred
71207077Sthompsa#ifdef USB_DEBUG
72194228Sthompsastatic int usb_pr_poll_delay = USB_PORT_RESET_DELAY;
73194228Sthompsastatic int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY;
74184610Salfred
75192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW,
76194228Sthompsa    &usb_pr_poll_delay, 0, "USB port reset poll delay in ms");
77192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW,
78194228Sthompsa    &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms");
79184610Salfred
80208018Sthompsa#ifdef USB_REQ_DEBUG
81208018Sthompsa/* The following structures are used in connection to fault injection. */
82208018Sthompsastruct usb_ctrl_debug {
83208018Sthompsa	int bus_index;		/* target bus */
84208018Sthompsa	int dev_index;		/* target address */
85208018Sthompsa	int ds_fail;		/* fail data stage */
86208018Sthompsa	int ss_fail;		/* fail data stage */
87208018Sthompsa	int ds_delay;		/* data stage delay in ms */
88208018Sthompsa	int ss_delay;		/* status stage delay in ms */
89208018Sthompsa	int bmRequestType_value;
90208018Sthompsa	int bRequest_value;
91208018Sthompsa};
92208018Sthompsa
93208018Sthompsastruct usb_ctrl_debug_bits {
94208018Sthompsa	uint16_t ds_delay;
95208018Sthompsa	uint16_t ss_delay;
96208018Sthompsa	uint8_t ds_fail:1;
97208018Sthompsa	uint8_t ss_fail:1;
98208018Sthompsa	uint8_t enabled:1;
99208018Sthompsa};
100208018Sthompsa
101208018Sthompsa/* The default is to disable fault injection. */
102208018Sthompsa
103208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = {
104208018Sthompsa	.bus_index = -1,
105208018Sthompsa	.dev_index = -1,
106208018Sthompsa	.bmRequestType_value = -1,
107208018Sthompsa	.bRequest_value = -1,
108208018Sthompsa};
109208018Sthompsa
110208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW,
111208018Sthompsa    &usb_ctrl_debug.bus_index, 0, "USB controller index to fail");
112208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW,
113208018Sthompsa    &usb_ctrl_debug.dev_index, 0, "USB device address to fail");
114208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW,
115208018Sthompsa    &usb_ctrl_debug.ds_fail, 0, "USB fail data stage");
116208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW,
117208018Sthompsa    &usb_ctrl_debug.ss_fail, 0, "USB fail status stage");
118208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW,
119208018Sthompsa    &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms");
120208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW,
121208018Sthompsa    &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms");
122208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW,
123208018Sthompsa    &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail");
124208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW,
125208018Sthompsa    &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail");
126208018Sthompsa
127184610Salfred/*------------------------------------------------------------------------*
128208018Sthompsa *	usbd_get_debug_bits
129208018Sthompsa *
130208018Sthompsa * This function is only useful in USB host mode.
131208018Sthompsa *------------------------------------------------------------------------*/
132208018Sthompsastatic void
133208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req,
134208018Sthompsa    struct usb_ctrl_debug_bits *dbg)
135208018Sthompsa{
136208018Sthompsa	int temp;
137208018Sthompsa
138208018Sthompsa	memset(dbg, 0, sizeof(*dbg));
139208018Sthompsa
140208018Sthompsa	/* Compute data stage delay */
141208018Sthompsa
142208018Sthompsa	temp = usb_ctrl_debug.ds_delay;
143208018Sthompsa	if (temp < 0)
144208018Sthompsa		temp = 0;
145208018Sthompsa	else if (temp > (16*1024))
146208018Sthompsa		temp = (16*1024);
147208018Sthompsa
148208018Sthompsa	dbg->ds_delay = temp;
149208018Sthompsa
150208018Sthompsa	/* Compute status stage delay */
151208018Sthompsa
152208018Sthompsa	temp = usb_ctrl_debug.ss_delay;
153208018Sthompsa	if (temp < 0)
154208018Sthompsa		temp = 0;
155208018Sthompsa	else if (temp > (16*1024))
156208018Sthompsa		temp = (16*1024);
157208018Sthompsa
158208018Sthompsa	dbg->ss_delay = temp;
159208018Sthompsa
160208018Sthompsa	/* Check if this control request should be failed */
161208018Sthompsa
162208018Sthompsa	if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index)
163208018Sthompsa		return;
164208018Sthompsa
165208018Sthompsa	if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index)
166208018Sthompsa		return;
167208018Sthompsa
168208018Sthompsa	temp = usb_ctrl_debug.bmRequestType_value;
169208018Sthompsa
170208018Sthompsa	if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255))
171208018Sthompsa		return;
172208018Sthompsa
173208018Sthompsa	temp = usb_ctrl_debug.bRequest_value;
174208018Sthompsa
175208018Sthompsa	if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255))
176208018Sthompsa		return;
177208018Sthompsa
178208018Sthompsa	temp = usb_ctrl_debug.ds_fail;
179208018Sthompsa	if (temp)
180208018Sthompsa		dbg->ds_fail = 1;
181208018Sthompsa
182208018Sthompsa	temp = usb_ctrl_debug.ss_fail;
183208018Sthompsa	if (temp)
184208018Sthompsa		dbg->ss_fail = 1;
185208018Sthompsa
186208018Sthompsa	dbg->enabled = 1;
187208018Sthompsa}
188208018Sthompsa#endif	/* USB_REQ_DEBUG */
189208018Sthompsa#endif	/* USB_DEBUG */
190208018Sthompsa
191208018Sthompsa/*------------------------------------------------------------------------*
192194228Sthompsa *	usbd_do_request_callback
193184610Salfred *
194184610Salfred * This function is the USB callback for generic USB Host control
195184610Salfred * transfers.
196184610Salfred *------------------------------------------------------------------------*/
197184610Salfredvoid
198194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error)
199184610Salfred{
200184610Salfred	;				/* workaround for a bug in "indent" */
201184610Salfred
202184610Salfred	DPRINTF("st=%u\n", USB_GET_STATE(xfer));
203184610Salfred
204184610Salfred	switch (USB_GET_STATE(xfer)) {
205184610Salfred	case USB_ST_SETUP:
206194228Sthompsa		usbd_transfer_submit(xfer);
207184610Salfred		break;
208184610Salfred	default:
209207079Sthompsa		cv_signal(&xfer->xroot->udev->ctrlreq_cv);
210184610Salfred		break;
211184610Salfred	}
212184610Salfred}
213184610Salfred
214184610Salfred/*------------------------------------------------------------------------*
215194228Sthompsa *	usb_do_clear_stall_callback
216184610Salfred *
217184610Salfred * This function is the USB callback for generic clear stall requests.
218184610Salfred *------------------------------------------------------------------------*/
219184610Salfredvoid
220194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
221184610Salfred{
222192984Sthompsa	struct usb_device_request req;
223192984Sthompsa	struct usb_device *udev;
224193644Sthompsa	struct usb_endpoint *ep;
225193644Sthompsa	struct usb_endpoint *ep_end;
226193644Sthompsa	struct usb_endpoint *ep_first;
227190731Sthompsa	uint8_t to;
228184610Salfred
229187173Sthompsa	udev = xfer->xroot->udev;
230184610Salfred
231187173Sthompsa	USB_BUS_LOCK(udev->bus);
232187173Sthompsa
233193644Sthompsa	/* round robin endpoint clear stall */
234184610Salfred
235193644Sthompsa	ep = udev->ep_curr;
236193644Sthompsa	ep_end = udev->endpoints + udev->endpoints_max;
237193644Sthompsa	ep_first = udev->endpoints;
238193644Sthompsa	to = udev->endpoints_max;
239193318Sthompsa
240184610Salfred	switch (USB_GET_STATE(xfer)) {
241184610Salfred	case USB_ST_TRANSFERRED:
242193644Sthompsa		if (ep == NULL)
243193318Sthompsa			goto tr_setup;		/* device was unconfigured */
244193644Sthompsa		if (ep->edesc &&
245193644Sthompsa		    ep->is_stalled) {
246193644Sthompsa			ep->toggle_next = 0;
247193644Sthompsa			ep->is_stalled = 0;
248184610Salfred			/* start up the current or next transfer, if any */
249194228Sthompsa			usb_command_wrapper(&ep->endpoint_q,
250193644Sthompsa			    ep->endpoint_q.curr);
251184610Salfred		}
252193644Sthompsa		ep++;
253184610Salfred
254184610Salfred	case USB_ST_SETUP:
255184610Salfredtr_setup:
256193318Sthompsa		if (to == 0)
257193644Sthompsa			break;			/* no endpoints - nothing to do */
258193644Sthompsa		if ((ep < ep_first) || (ep >= ep_end))
259193644Sthompsa			ep = ep_first;	/* endpoint wrapped around */
260193644Sthompsa		if (ep->edesc &&
261193644Sthompsa		    ep->is_stalled) {
262184610Salfred
263184610Salfred			/* setup a clear-stall packet */
264184610Salfred
265184610Salfred			req.bmRequestType = UT_WRITE_ENDPOINT;
266184610Salfred			req.bRequest = UR_CLEAR_FEATURE;
267184610Salfred			USETW(req.wValue, UF_ENDPOINT_HALT);
268193644Sthompsa			req.wIndex[0] = ep->edesc->bEndpointAddress;
269184610Salfred			req.wIndex[1] = 0;
270184610Salfred			USETW(req.wLength, 0);
271184610Salfred
272184610Salfred			/* copy in the transfer */
273184610Salfred
274194228Sthompsa			usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req));
275184610Salfred
276184610Salfred			/* set length */
277194677Sthompsa			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
278184610Salfred			xfer->nframes = 1;
279187173Sthompsa			USB_BUS_UNLOCK(udev->bus);
280184610Salfred
281194228Sthompsa			usbd_transfer_submit(xfer);
282184610Salfred
283187173Sthompsa			USB_BUS_LOCK(udev->bus);
284184610Salfred			break;
285184610Salfred		}
286193644Sthompsa		ep++;
287193318Sthompsa		to--;
288193318Sthompsa		goto tr_setup;
289184610Salfred
290184610Salfred	default:
291184610Salfred		if (xfer->error == USB_ERR_CANCELLED) {
292184610Salfred			break;
293184610Salfred		}
294184610Salfred		goto tr_setup;
295184610Salfred	}
296184610Salfred
297193644Sthompsa	/* store current endpoint */
298193644Sthompsa	udev->ep_curr = ep;
299187173Sthompsa	USB_BUS_UNLOCK(udev->bus);
300184610Salfred}
301184610Salfred
302193045Sthompsastatic usb_handle_req_t *
303194228Sthompsausbd_get_hr_func(struct usb_device *udev)
304191402Sthompsa{
305191402Sthompsa	/* figure out if there is a Handle Request function */
306192499Sthompsa	if (udev->flags.usb_mode == USB_MODE_DEVICE)
307194228Sthompsa		return (usb_temp_get_desc_p);
308191402Sthompsa	else if (udev->parent_hub == NULL)
309191402Sthompsa		return (udev->bus->methods->roothub_exec);
310191402Sthompsa	else
311191402Sthompsa		return (NULL);
312191402Sthompsa}
313191402Sthompsa
314184610Salfred/*------------------------------------------------------------------------*
315194228Sthompsa *	usbd_do_request_flags and usbd_do_request
316184610Salfred *
317184610Salfred * Description of arguments passed to these functions:
318184610Salfred *
319192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the
320184610Salfred * request should be performed. It is possible to call this function
321184610Salfred * in both Host Side mode and Device Side mode.
322184610Salfred *
323184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it
324184610Salfred * will get dropped and picked up during the execution of this
325184610Salfred * function, hence this function sometimes needs to sleep. If this
326184610Salfred * argument is NULL it has no effect.
327184610Salfred *
328184610Salfred * "req" - this argument must always be non-NULL and points to an
329184610Salfred * 8-byte structure holding the USB request to be done. The USB
330184610Salfred * request structure has a bit telling the direction of the USB
331184610Salfred * request, if it is a read or a write.
332184610Salfred *
333184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req"
334184610Salfred * is non-zero this argument must point to a valid kernel buffer which
335184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can
336184610Salfred * be NULL.
337184610Salfred *
338184610Salfred * "flags" - here is a list of valid flags:
339184610Salfred *
340184610Salfred *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
341184610Salfred *  specified
342184610Salfred *
343184610Salfred *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
344184610Salfred *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
345184610Salfred *  sysctl. This flag is mostly useful for debugging.
346184610Salfred *
347184610Salfred *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
348184610Salfred *  pointer.
349184610Salfred *
350184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in
351184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This
352184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
353184610Salfred * used.
354184610Salfred *
355184610Salfred * "timeout" - gives the timeout for the control transfer in
356184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is
357184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater
358184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack
359184610Salfred * does not allow control requests without a timeout.
360184610Salfred *
361184610Salfred * NOTE: This function is thread safe. All calls to
362194228Sthompsa * "usbd_do_request_flags" will be serialised by the use of an
363184610Salfred * internal "sx_lock".
364184610Salfred *
365184610Salfred * Returns:
366184610Salfred *    0: Success
367184610Salfred * Else: Failure
368184610Salfred *------------------------------------------------------------------------*/
369193045Sthompsausb_error_t
370194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
371192984Sthompsa    struct usb_device_request *req, void *data, uint16_t flags,
372193045Sthompsa    uint16_t *actlen, usb_timeout_t timeout)
373184610Salfred{
374208018Sthompsa#ifdef USB_REQ_DEBUG
375208018Sthompsa	struct usb_ctrl_debug_bits dbg;
376208018Sthompsa#endif
377193045Sthompsa	usb_handle_req_t *hr_func;
378192984Sthompsa	struct usb_xfer *xfer;
379184610Salfred	const void *desc;
380184610Salfred	int err = 0;
381193045Sthompsa	usb_ticks_t start_ticks;
382193045Sthompsa	usb_ticks_t delta_ticks;
383193045Sthompsa	usb_ticks_t max_ticks;
384184610Salfred	uint16_t length;
385184610Salfred	uint16_t temp;
386208018Sthompsa	uint16_t acttemp;
387208008Sthompsa	uint8_t enum_locked;
388184610Salfred
389184610Salfred	if (timeout < 50) {
390184610Salfred		/* timeout is too small */
391184610Salfred		timeout = 50;
392184610Salfred	}
393184610Salfred	if (timeout > 30000) {
394184610Salfred		/* timeout is too big */
395184610Salfred		timeout = 30000;
396184610Salfred	}
397184610Salfred	length = UGETW(req->wLength);
398184610Salfred
399208008Sthompsa	enum_locked = usbd_enum_is_locked(udev);
400208008Sthompsa
401184610Salfred	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
402184610Salfred	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
403184610Salfred	    udev, req->bmRequestType, req->bRequest,
404184610Salfred	    req->wValue[1], req->wValue[0],
405184610Salfred	    req->wIndex[1], req->wIndex[0],
406184610Salfred	    req->wLength[1], req->wLength[0]);
407184610Salfred
408191494Sthompsa	/* Check if the device is still alive */
409191494Sthompsa	if (udev->state < USB_STATE_POWERED) {
410191494Sthompsa		DPRINTF("usb device has gone\n");
411191494Sthompsa		return (USB_ERR_NOT_CONFIGURED);
412191494Sthompsa	}
413191494Sthompsa
414184610Salfred	/*
415184610Salfred	 * Set "actlen" to a known value in case the caller does not
416184610Salfred	 * check the return value:
417184610Salfred	 */
418190735Sthompsa	if (actlen)
419184610Salfred		*actlen = 0;
420190735Sthompsa
421190180Sthompsa#if (USB_HAVE_USER_IO == 0)
422190180Sthompsa	if (flags & USB_USER_DATA_PTR)
423190180Sthompsa		return (USB_ERR_INVAL);
424190180Sthompsa#endif
425208008Sthompsa	if ((mtx != NULL) && (mtx != &Giant)) {
426184610Salfred		mtx_unlock(mtx);
427208008Sthompsa		mtx_assert(mtx, MA_NOTOWNED);
428184610Salfred	}
429208008Sthompsa
430184610Salfred	/*
431208008Sthompsa	 * We need to allow suspend and resume at this point, else the
432208008Sthompsa	 * control transfer will timeout if the device is suspended!
433208008Sthompsa	 */
434208008Sthompsa	if (enum_locked)
435208008Sthompsa		usbd_sr_unlock(udev);
436208008Sthompsa
437208008Sthompsa	/*
438184610Salfred	 * Grab the default sx-lock so that serialisation
439184610Salfred	 * is achieved when multiple threads are involved:
440184610Salfred	 */
441207079Sthompsa	sx_xlock(&udev->ctrl_sx);
442184610Salfred
443194228Sthompsa	hr_func = usbd_get_hr_func(udev);
444190735Sthompsa
445191402Sthompsa	if (hr_func != NULL) {
446191402Sthompsa		DPRINTF("Handle Request function is set\n");
447190735Sthompsa
448191402Sthompsa		desc = NULL;
449191402Sthompsa		temp = 0;
450191402Sthompsa
451191402Sthompsa		if (!(req->bmRequestType & UT_READ)) {
452190735Sthompsa			if (length != 0) {
453191402Sthompsa				DPRINTFN(1, "The handle request function "
454191402Sthompsa				    "does not support writing data!\n");
455191402Sthompsa				err = USB_ERR_INVAL;
456191402Sthompsa				goto done;
457190735Sthompsa			}
458190735Sthompsa		}
459190735Sthompsa
460191402Sthompsa		/* The root HUB code needs the BUS lock locked */
461191402Sthompsa
462190735Sthompsa		USB_BUS_LOCK(udev->bus);
463191402Sthompsa		err = (hr_func) (udev, req, &desc, &temp);
464190735Sthompsa		USB_BUS_UNLOCK(udev->bus);
465190735Sthompsa
466190735Sthompsa		if (err)
467190735Sthompsa			goto done;
468190735Sthompsa
469191402Sthompsa		if (length > temp) {
470190735Sthompsa			if (!(flags & USB_SHORT_XFER_OK)) {
471190735Sthompsa				err = USB_ERR_SHORT_XFER;
472190735Sthompsa				goto done;
473190735Sthompsa			}
474191402Sthompsa			length = temp;
475190735Sthompsa		}
476190735Sthompsa		if (actlen)
477190735Sthompsa			*actlen = length;
478190735Sthompsa
479190735Sthompsa		if (length > 0) {
480190735Sthompsa#if USB_HAVE_USER_IO
481190735Sthompsa			if (flags & USB_USER_DATA_PTR) {
482191402Sthompsa				if (copyout(desc, data, length)) {
483190735Sthompsa					err = USB_ERR_INVAL;
484190735Sthompsa					goto done;
485190735Sthompsa				}
486190735Sthompsa			} else
487190735Sthompsa#endif
488191402Sthompsa				bcopy(desc, data, length);
489190735Sthompsa		}
490191402Sthompsa		goto done;		/* success */
491190735Sthompsa	}
492190735Sthompsa
493184610Salfred	/*
494184610Salfred	 * Setup a new USB transfer or use the existing one, if any:
495184610Salfred	 */
496207080Sthompsa	usbd_ctrl_transfer_setup(udev);
497184610Salfred
498207080Sthompsa	xfer = udev->ctrl_xfer[0];
499184610Salfred	if (xfer == NULL) {
500184610Salfred		/* most likely out of memory */
501184610Salfred		err = USB_ERR_NOMEM;
502184610Salfred		goto done;
503184610Salfred	}
504208018Sthompsa
505208018Sthompsa#ifdef USB_REQ_DEBUG
506208018Sthompsa	/* Get debug bits */
507208018Sthompsa	usbd_get_debug_bits(udev, req, &dbg);
508208018Sthompsa
509208018Sthompsa	/* Check for fault injection */
510208018Sthompsa	if (dbg.enabled)
511208018Sthompsa		flags |= USB_DELAY_STATUS_STAGE;
512208018Sthompsa#endif
513184824Sthompsa	USB_XFER_LOCK(xfer);
514184610Salfred
515190734Sthompsa	if (flags & USB_DELAY_STATUS_STAGE)
516184610Salfred		xfer->flags.manual_status = 1;
517190734Sthompsa	else
518184610Salfred		xfer->flags.manual_status = 0;
519184610Salfred
520190734Sthompsa	if (flags & USB_SHORT_XFER_OK)
521190734Sthompsa		xfer->flags.short_xfer_ok = 1;
522190734Sthompsa	else
523190734Sthompsa		xfer->flags.short_xfer_ok = 0;
524190734Sthompsa
525184610Salfred	xfer->timeout = timeout;
526184610Salfred
527184610Salfred	start_ticks = ticks;
528184610Salfred
529184610Salfred	max_ticks = USB_MS_TO_TICKS(timeout);
530184610Salfred
531194228Sthompsa	usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req));
532184610Salfred
533194677Sthompsa	usbd_xfer_set_frame_len(xfer, 0, sizeof(*req));
534184610Salfred
535184610Salfred	while (1) {
536184610Salfred		temp = length;
537208018Sthompsa		if (temp > usbd_xfer_max_len(xfer)) {
538194677Sthompsa			temp = usbd_xfer_max_len(xfer);
539184610Salfred		}
540208018Sthompsa#ifdef USB_REQ_DEBUG
541208018Sthompsa		if (xfer->flags.manual_status) {
542208018Sthompsa			if (usbd_xfer_frame_len(xfer, 0) != 0) {
543208018Sthompsa				/* Execute data stage separately */
544208018Sthompsa				temp = 0;
545208018Sthompsa			} else if (temp > 0) {
546208018Sthompsa				if (dbg.ds_fail) {
547208018Sthompsa					err = USB_ERR_INVAL;
548208018Sthompsa					break;
549208018Sthompsa				}
550208018Sthompsa				if (dbg.ds_delay > 0) {
551208018Sthompsa					usb_pause_mtx(
552208018Sthompsa					    xfer->xroot->xfer_mtx,
553208018Sthompsa				            USB_MS_TO_TICKS(dbg.ds_delay));
554208018Sthompsa					/* make sure we don't time out */
555208018Sthompsa					start_ticks = ticks;
556208018Sthompsa				}
557208018Sthompsa			}
558208018Sthompsa		}
559208018Sthompsa#endif
560194677Sthompsa		usbd_xfer_set_frame_len(xfer, 1, temp);
561184610Salfred
562184610Salfred		if (temp > 0) {
563184610Salfred			if (!(req->bmRequestType & UT_READ)) {
564190180Sthompsa#if USB_HAVE_USER_IO
565184610Salfred				if (flags & USB_USER_DATA_PTR) {
566184824Sthompsa					USB_XFER_UNLOCK(xfer);
567194228Sthompsa					err = usbd_copy_in_user(xfer->frbuffers + 1,
568184610Salfred					    0, data, temp);
569184824Sthompsa					USB_XFER_LOCK(xfer);
570184610Salfred					if (err) {
571184610Salfred						err = USB_ERR_INVAL;
572184610Salfred						break;
573184610Salfred					}
574190180Sthompsa				} else
575190180Sthompsa#endif
576194228Sthompsa					usbd_copy_in(xfer->frbuffers + 1,
577190180Sthompsa					    0, data, temp);
578184610Salfred			}
579208018Sthompsa			usbd_xfer_set_frames(xfer, 2);
580184610Salfred		} else {
581208018Sthompsa			if (usbd_xfer_frame_len(xfer, 0) == 0) {
582184610Salfred				if (xfer->flags.manual_status) {
583208018Sthompsa#ifdef USB_REQ_DEBUG
584208018Sthompsa					if (dbg.ss_fail) {
585208018Sthompsa						err = USB_ERR_INVAL;
586208018Sthompsa						break;
587184610Salfred					}
588208018Sthompsa					if (dbg.ss_delay > 0) {
589194228Sthompsa						usb_pause_mtx(
590187173Sthompsa						    xfer->xroot->xfer_mtx,
591208018Sthompsa						    USB_MS_TO_TICKS(dbg.ss_delay));
592208018Sthompsa						/* make sure we don't time out */
593208018Sthompsa						start_ticks = ticks;
594184610Salfred					}
595184610Salfred#endif
596184610Salfred					xfer->flags.manual_status = 0;
597184610Salfred				} else {
598184610Salfred					break;
599184610Salfred				}
600184610Salfred			}
601208018Sthompsa			usbd_xfer_set_frames(xfer, 1);
602184610Salfred		}
603184610Salfred
604194228Sthompsa		usbd_transfer_start(xfer);
605184610Salfred
606194228Sthompsa		while (usbd_transfer_pending(xfer)) {
607207079Sthompsa			cv_wait(&udev->ctrlreq_cv,
608188983Sthompsa			    xfer->xroot->xfer_mtx);
609184610Salfred		}
610184610Salfred
611184610Salfred		err = xfer->error;
612184610Salfred
613184610Salfred		if (err) {
614184610Salfred			break;
615184610Salfred		}
616184610Salfred
617208018Sthompsa		/* get actual length of DATA stage */
618208018Sthompsa
619208018Sthompsa		if (xfer->aframes < 2) {
620208018Sthompsa			acttemp = 0;
621184610Salfred		} else {
622208018Sthompsa			acttemp = usbd_xfer_frame_len(xfer, 1);
623184610Salfred		}
624184610Salfred
625184610Salfred		/* check for short packet */
626184610Salfred
627208018Sthompsa		if (temp > acttemp) {
628208018Sthompsa			temp = acttemp;
629184610Salfred			length = temp;
630184610Salfred		}
631184610Salfred		if (temp > 0) {
632184610Salfred			if (req->bmRequestType & UT_READ) {
633190180Sthompsa#if USB_HAVE_USER_IO
634184610Salfred				if (flags & USB_USER_DATA_PTR) {
635184824Sthompsa					USB_XFER_UNLOCK(xfer);
636194228Sthompsa					err = usbd_copy_out_user(xfer->frbuffers + 1,
637184610Salfred					    0, data, temp);
638184824Sthompsa					USB_XFER_LOCK(xfer);
639184610Salfred					if (err) {
640184610Salfred						err = USB_ERR_INVAL;
641184610Salfred						break;
642184610Salfred					}
643190180Sthompsa				} else
644190180Sthompsa#endif
645194228Sthompsa					usbd_copy_out(xfer->frbuffers + 1,
646184610Salfred					    0, data, temp);
647184610Salfred			}
648184610Salfred		}
649184610Salfred		/*
650184610Salfred		 * Clear "frlengths[0]" so that we don't send the setup
651184610Salfred		 * packet again:
652184610Salfred		 */
653194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, 0);
654184610Salfred
655184610Salfred		/* update length and data pointer */
656184610Salfred		length -= temp;
657184610Salfred		data = USB_ADD_BYTES(data, temp);
658184610Salfred
659184610Salfred		if (actlen) {
660184610Salfred			(*actlen) += temp;
661184610Salfred		}
662184610Salfred		/* check for timeout */
663184610Salfred
664184610Salfred		delta_ticks = ticks - start_ticks;
665184610Salfred		if (delta_ticks > max_ticks) {
666184610Salfred			if (!err) {
667184610Salfred				err = USB_ERR_TIMEOUT;
668184610Salfred			}
669184610Salfred		}
670184610Salfred		if (err) {
671184610Salfred			break;
672184610Salfred		}
673184610Salfred	}
674184610Salfred
675184610Salfred	if (err) {
676184610Salfred		/*
677184610Salfred		 * Make sure that the control endpoint is no longer
678184610Salfred		 * blocked in case of a non-transfer related error:
679184610Salfred		 */
680194228Sthompsa		usbd_transfer_stop(xfer);
681184610Salfred	}
682184824Sthompsa	USB_XFER_UNLOCK(xfer);
683184610Salfred
684184610Salfreddone:
685207079Sthompsa	sx_xunlock(&udev->ctrl_sx);
686184610Salfred
687208008Sthompsa	if (enum_locked)
688208008Sthompsa		usbd_sr_lock(udev);
689208008Sthompsa
690208008Sthompsa	if ((mtx != NULL) && (mtx != &Giant))
691184610Salfred		mtx_lock(mtx);
692208008Sthompsa
693193045Sthompsa	return ((usb_error_t)err);
694184610Salfred}
695184610Salfred
696184610Salfred/*------------------------------------------------------------------------*
697194228Sthompsa *	usbd_do_request_proc - factored out code
698188411Sthompsa *
699188411Sthompsa * This function is factored out code. It does basically the same like
700194228Sthompsa * usbd_do_request_flags, except it will check the status of the
701188411Sthompsa * passed process argument before doing the USB request. If the
702188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It
703188411Sthompsa * is assumed that the mutex associated with the process is locked
704188411Sthompsa * when calling this function.
705188411Sthompsa *------------------------------------------------------------------------*/
706193045Sthompsausb_error_t
707194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc,
708192984Sthompsa    struct usb_device_request *req, void *data, uint16_t flags,
709193045Sthompsa    uint16_t *actlen, usb_timeout_t timeout)
710188411Sthompsa{
711193045Sthompsa	usb_error_t err;
712188411Sthompsa	uint16_t len;
713188411Sthompsa
714188411Sthompsa	/* get request data length */
715188411Sthompsa	len = UGETW(req->wLength);
716188411Sthompsa
717188411Sthompsa	/* check if the device is being detached */
718194228Sthompsa	if (usb_proc_is_gone(pproc)) {
719188411Sthompsa		err = USB_ERR_IOERROR;
720188411Sthompsa		goto done;
721188411Sthompsa	}
722188411Sthompsa
723188411Sthompsa	/* forward the USB request */
724194228Sthompsa	err = usbd_do_request_flags(udev, pproc->up_mtx,
725188411Sthompsa	    req, data, flags, actlen, timeout);
726188411Sthompsa
727188411Sthompsadone:
728188411Sthompsa	/* on failure we zero the data */
729188411Sthompsa	/* on short packet we zero the unused data */
730188411Sthompsa	if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) {
731188411Sthompsa		if (err)
732188411Sthompsa			memset(data, 0, len);
733188411Sthompsa		else if (actlen && *actlen != len)
734188411Sthompsa			memset(((uint8_t *)data) + *actlen, 0, len - *actlen);
735188411Sthompsa	}
736188411Sthompsa	return (err);
737188411Sthompsa}
738188411Sthompsa
739188411Sthompsa/*------------------------------------------------------------------------*
740194228Sthompsa *	usbd_req_reset_port
741184610Salfred *
742184610Salfred * This function will instruct an USB HUB to perform a reset sequence
743184610Salfred * on the specified port number.
744184610Salfred *
745184610Salfred * Returns:
746184610Salfred *    0: Success. The USB device should now be at address zero.
747184610Salfred * Else: Failure. No USB device is present and the USB port should be
748184610Salfred *       disabled.
749184610Salfred *------------------------------------------------------------------------*/
750193045Sthompsausb_error_t
751194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
752184610Salfred{
753192984Sthompsa	struct usb_port_status ps;
754193045Sthompsa	usb_error_t err;
755184610Salfred	uint16_t n;
756184610Salfred
757207077Sthompsa#ifdef USB_DEBUG
758184610Salfred	uint16_t pr_poll_delay;
759184610Salfred	uint16_t pr_recovery_delay;
760184610Salfred
761184610Salfred#endif
762194228Sthompsa	err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
763184610Salfred	if (err) {
764184610Salfred		goto done;
765184610Salfred	}
766207077Sthompsa#ifdef USB_DEBUG
767184610Salfred	/* range check input parameters */
768194228Sthompsa	pr_poll_delay = usb_pr_poll_delay;
769184610Salfred	if (pr_poll_delay < 1) {
770184610Salfred		pr_poll_delay = 1;
771184610Salfred	} else if (pr_poll_delay > 1000) {
772184610Salfred		pr_poll_delay = 1000;
773184610Salfred	}
774194228Sthompsa	pr_recovery_delay = usb_pr_recovery_delay;
775184610Salfred	if (pr_recovery_delay > 1000) {
776184610Salfred		pr_recovery_delay = 1000;
777184610Salfred	}
778184610Salfred#endif
779184610Salfred	n = 0;
780184610Salfred	while (1) {
781207077Sthompsa#ifdef USB_DEBUG
782184610Salfred		/* wait for the device to recover from reset */
783194228Sthompsa		usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
784184610Salfred		n += pr_poll_delay;
785184610Salfred#else
786184610Salfred		/* wait for the device to recover from reset */
787194228Sthompsa		usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
788184610Salfred		n += USB_PORT_RESET_DELAY;
789184610Salfred#endif
790194228Sthompsa		err = usbd_req_get_port_status(udev, mtx, &ps, port);
791184610Salfred		if (err) {
792184610Salfred			goto done;
793184610Salfred		}
794184610Salfred		/* if the device disappeared, just give up */
795184610Salfred		if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
796184610Salfred			goto done;
797184610Salfred		}
798184610Salfred		/* check if reset is complete */
799184610Salfred		if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
800184610Salfred			break;
801184610Salfred		}
802184610Salfred		/* check for timeout */
803184610Salfred		if (n > 1000) {
804184610Salfred			n = 0;
805184610Salfred			break;
806184610Salfred		}
807184610Salfred	}
808184610Salfred
809184610Salfred	/* clear port reset first */
810194228Sthompsa	err = usbd_req_clear_port_feature(
811184610Salfred	    udev, mtx, port, UHF_C_PORT_RESET);
812184610Salfred	if (err) {
813184610Salfred		goto done;
814184610Salfred	}
815184610Salfred	/* check for timeout */
816184610Salfred	if (n == 0) {
817184610Salfred		err = USB_ERR_TIMEOUT;
818184610Salfred		goto done;
819184610Salfred	}
820207077Sthompsa#ifdef USB_DEBUG
821184610Salfred	/* wait for the device to recover from reset */
822194228Sthompsa	usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
823184610Salfred#else
824184610Salfred	/* wait for the device to recover from reset */
825194228Sthompsa	usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
826184610Salfred#endif
827184610Salfred
828184610Salfreddone:
829184610Salfred	DPRINTFN(2, "port %d reset returning error=%s\n",
830194228Sthompsa	    port, usbd_errstr(err));
831184610Salfred	return (err);
832184610Salfred}
833184610Salfred
834184610Salfred/*------------------------------------------------------------------------*
835194228Sthompsa *	usbd_req_get_desc
836184610Salfred *
837184610Salfred * This function can be used to retrieve USB descriptors. It contains
838184610Salfred * some additional logic like zeroing of missing descriptor bytes and
839184610Salfred * retrying an USB descriptor in case of failure. The "min_len"
840184610Salfred * argument specifies the minimum descriptor length. The "max_len"
841184610Salfred * argument specifies the maximum descriptor length. If the real
842184610Salfred * descriptor length is less than the minimum length the missing
843188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB
844188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen"
845188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get
846188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The
847188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen"
848188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated
849188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to
850188985Sthompsa * "max_len" then this function will try to retrive the beginning of
851188985Sthompsa * the descriptor and base the maximum length on the first byte of the
852188985Sthompsa * descriptor.
853184610Salfred *
854184610Salfred * Returns:
855184610Salfred *    0: Success
856184610Salfred * Else: Failure
857184610Salfred *------------------------------------------------------------------------*/
858193045Sthompsausb_error_t
859194228Sthompsausbd_req_get_desc(struct usb_device *udev,
860188985Sthompsa    struct mtx *mtx, uint16_t *actlen, void *desc,
861184610Salfred    uint16_t min_len, uint16_t max_len,
862184610Salfred    uint16_t id, uint8_t type, uint8_t index,
863184610Salfred    uint8_t retries)
864184610Salfred{
865192984Sthompsa	struct usb_device_request req;
866184610Salfred	uint8_t *buf;
867193045Sthompsa	usb_error_t err;
868184610Salfred
869184610Salfred	DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n",
870184610Salfred	    id, type, index, max_len);
871184610Salfred
872184610Salfred	req.bmRequestType = UT_READ_DEVICE;
873184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
874184610Salfred	USETW2(req.wValue, type, index);
875184610Salfred	USETW(req.wIndex, id);
876184610Salfred
877184610Salfred	while (1) {
878184610Salfred
879184610Salfred		if ((min_len < 2) || (max_len < 2)) {
880184610Salfred			err = USB_ERR_INVAL;
881184610Salfred			goto done;
882184610Salfred		}
883184610Salfred		USETW(req.wLength, min_len);
884184610Salfred
885194228Sthompsa		err = usbd_do_request_flags(udev, mtx, &req,
886186730Salfred		    desc, 0, NULL, 1000);
887184610Salfred
888184610Salfred		if (err) {
889184610Salfred			if (!retries) {
890184610Salfred				goto done;
891184610Salfred			}
892184610Salfred			retries--;
893184610Salfred
894194228Sthompsa			usb_pause_mtx(mtx, hz / 5);
895184610Salfred
896184610Salfred			continue;
897184610Salfred		}
898184610Salfred		buf = desc;
899184610Salfred
900184610Salfred		if (min_len == max_len) {
901184610Salfred
902188985Sthompsa			/* enforce correct length */
903188985Sthompsa			if ((buf[0] > min_len) && (actlen == NULL))
904188985Sthompsa				buf[0] = min_len;
905184610Salfred
906188985Sthompsa			/* enforce correct type */
907184610Salfred			buf[1] = type;
908184610Salfred
909184610Salfred			goto done;
910184610Salfred		}
911184610Salfred		/* range check */
912184610Salfred
913184610Salfred		if (max_len > buf[0]) {
914184610Salfred			max_len = buf[0];
915184610Salfred		}
916184610Salfred		/* zero minimum data */
917184610Salfred
918184610Salfred		while (min_len > max_len) {
919184610Salfred			min_len--;
920184610Salfred			buf[min_len] = 0;
921184610Salfred		}
922184610Salfred
923184610Salfred		/* set new minimum length */
924184610Salfred
925184610Salfred		min_len = max_len;
926184610Salfred	}
927184610Salfreddone:
928188985Sthompsa	if (actlen != NULL) {
929188985Sthompsa		if (err)
930188985Sthompsa			*actlen = 0;
931188985Sthompsa		else
932188985Sthompsa			*actlen = min_len;
933188985Sthompsa	}
934184610Salfred	return (err);
935184610Salfred}
936184610Salfred
937184610Salfred/*------------------------------------------------------------------------*
938194228Sthompsa *	usbd_req_get_string_any
939184610Salfred *
940184610Salfred * This function will return the string given by "string_index"
941184610Salfred * using the first language ID. The maximum length "len" includes
942184610Salfred * the terminating zero. The "len" argument should be twice as
943184610Salfred * big pluss 2 bytes, compared with the actual maximum string length !
944184610Salfred *
945184610Salfred * Returns:
946184610Salfred *    0: Success
947184610Salfred * Else: Failure
948184610Salfred *------------------------------------------------------------------------*/
949193045Sthompsausb_error_t
950194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf,
951184610Salfred    uint16_t len, uint8_t string_index)
952184610Salfred{
953184610Salfred	char *s;
954184610Salfred	uint8_t *temp;
955184610Salfred	uint16_t i;
956184610Salfred	uint16_t n;
957184610Salfred	uint16_t c;
958184610Salfred	uint8_t swap;
959193045Sthompsa	usb_error_t err;
960184610Salfred
961184610Salfred	if (len == 0) {
962184610Salfred		/* should not happen */
963184610Salfred		return (USB_ERR_NORMAL_COMPLETION);
964184610Salfred	}
965184610Salfred	if (string_index == 0) {
966184610Salfred		/* this is the language table */
967185087Salfred		buf[0] = 0;
968184610Salfred		return (USB_ERR_INVAL);
969184610Salfred	}
970184610Salfred	if (udev->flags.no_strings) {
971185087Salfred		buf[0] = 0;
972184610Salfred		return (USB_ERR_STALLED);
973184610Salfred	}
974194228Sthompsa	err = usbd_req_get_string_desc
975184610Salfred	    (udev, mtx, buf, len, udev->langid, string_index);
976184610Salfred	if (err) {
977185087Salfred		buf[0] = 0;
978184610Salfred		return (err);
979184610Salfred	}
980184610Salfred	temp = (uint8_t *)buf;
981184610Salfred
982184610Salfred	if (temp[0] < 2) {
983184610Salfred		/* string length is too short */
984185087Salfred		buf[0] = 0;
985184610Salfred		return (USB_ERR_INVAL);
986184610Salfred	}
987184610Salfred	/* reserve one byte for terminating zero */
988184610Salfred	len--;
989184610Salfred
990184610Salfred	/* find maximum length */
991184610Salfred	s = buf;
992184610Salfred	n = (temp[0] / 2) - 1;
993184610Salfred	if (n > len) {
994184610Salfred		n = len;
995184610Salfred	}
996184610Salfred	/* skip descriptor header */
997184610Salfred	temp += 2;
998184610Salfred
999184610Salfred	/* reset swap state */
1000184610Salfred	swap = 3;
1001184610Salfred
1002184610Salfred	/* convert and filter */
1003184610Salfred	for (i = 0; (i != n); i++) {
1004184610Salfred		c = UGETW(temp + (2 * i));
1005184610Salfred
1006184610Salfred		/* convert from Unicode, handle buggy strings */
1007184610Salfred		if (((c & 0xff00) == 0) && (swap & 1)) {
1008184610Salfred			/* Little Endian, default */
1009184610Salfred			*s = c;
1010184610Salfred			swap = 1;
1011184610Salfred		} else if (((c & 0x00ff) == 0) && (swap & 2)) {
1012184610Salfred			/* Big Endian */
1013184610Salfred			*s = c >> 8;
1014184610Salfred			swap = 2;
1015184610Salfred		} else {
1016185087Salfred			/* silently skip bad character */
1017185087Salfred			continue;
1018184610Salfred		}
1019184610Salfred
1020184610Salfred		/*
1021213433Shselasky		 * Filter by default - We only allow alphanumerical
1022213433Shselasky		 * and a few more to avoid any problems with scripts
1023213433Shselasky		 * and daemons.
1024184610Salfred		 */
1025213433Shselasky		if (isalpha(*s) ||
1026213433Shselasky		    isdigit(*s) ||
1027213433Shselasky		    *s == '-' ||
1028213433Shselasky		    *s == '+' ||
1029213433Shselasky		    *s == ' ' ||
1030213433Shselasky		    *s == '.' ||
1031213433Shselasky		    *s == ',') {
1032213433Shselasky			/* allowed */
1033213433Shselasky			s++;
1034184610Salfred		}
1035213433Shselasky		/* silently skip bad character */
1036184610Salfred	}
1037185087Salfred	*s = 0;				/* zero terminate resulting string */
1038184610Salfred	return (USB_ERR_NORMAL_COMPLETION);
1039184610Salfred}
1040184610Salfred
1041184610Salfred/*------------------------------------------------------------------------*
1042194228Sthompsa *	usbd_req_get_string_desc
1043184610Salfred *
1044184610Salfred * If you don't know the language ID, consider using
1045194228Sthompsa * "usbd_req_get_string_any()".
1046184610Salfred *
1047184610Salfred * Returns:
1048184610Salfred *    0: Success
1049184610Salfred * Else: Failure
1050184610Salfred *------------------------------------------------------------------------*/
1051193045Sthompsausb_error_t
1052194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc,
1053184610Salfred    uint16_t max_len, uint16_t lang_id,
1054184610Salfred    uint8_t string_index)
1055184610Salfred{
1056194228Sthompsa	return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id,
1057184610Salfred	    UDESC_STRING, string_index, 0));
1058184610Salfred}
1059184610Salfred
1060184610Salfred/*------------------------------------------------------------------------*
1061194228Sthompsa *	usbd_req_get_config_desc_ptr
1062190727Sthompsa *
1063190727Sthompsa * This function is used in device side mode to retrieve the pointer
1064190727Sthompsa * to the generated config descriptor. This saves allocating space for
1065190727Sthompsa * an additional config descriptor when setting the configuration.
1066190727Sthompsa *
1067190727Sthompsa * Returns:
1068190727Sthompsa *    0: Success
1069190727Sthompsa * Else: Failure
1070190727Sthompsa *------------------------------------------------------------------------*/
1071193045Sthompsausb_error_t
1072194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev,
1073192984Sthompsa    struct usb_config_descriptor **ppcd, uint16_t wValue)
1074190727Sthompsa{
1075192984Sthompsa	struct usb_device_request req;
1076193045Sthompsa	usb_handle_req_t *hr_func;
1077191402Sthompsa	const void *ptr;
1078190727Sthompsa	uint16_t len;
1079193045Sthompsa	usb_error_t err;
1080190727Sthompsa
1081190731Sthompsa	req.bmRequestType = UT_READ_DEVICE;
1082190727Sthompsa	req.bRequest = UR_GET_DESCRIPTOR;
1083191402Sthompsa	USETW(req.wValue, wValue);
1084190727Sthompsa	USETW(req.wIndex, 0);
1085190727Sthompsa	USETW(req.wLength, 0);
1086190727Sthompsa
1087191402Sthompsa	ptr = NULL;
1088191402Sthompsa	len = 0;
1089190727Sthompsa
1090194228Sthompsa	hr_func = usbd_get_hr_func(udev);
1091191402Sthompsa
1092191402Sthompsa	if (hr_func == NULL)
1093191402Sthompsa		err = USB_ERR_INVAL;
1094191402Sthompsa	else {
1095191402Sthompsa		USB_BUS_LOCK(udev->bus);
1096191402Sthompsa		err = (hr_func) (udev, &req, &ptr, &len);
1097191402Sthompsa		USB_BUS_UNLOCK(udev->bus);
1098191402Sthompsa	}
1099191402Sthompsa
1100191402Sthompsa	if (err)
1101191402Sthompsa		ptr = NULL;
1102191402Sthompsa	else if (ptr == NULL)
1103191402Sthompsa		err = USB_ERR_INVAL;
1104191402Sthompsa
1105192984Sthompsa	*ppcd = __DECONST(struct usb_config_descriptor *, ptr);
1106191402Sthompsa
1107191402Sthompsa	return (err);
1108190727Sthompsa}
1109190727Sthompsa
1110190727Sthompsa/*------------------------------------------------------------------------*
1111194228Sthompsa *	usbd_req_get_config_desc
1112184610Salfred *
1113184610Salfred * Returns:
1114184610Salfred *    0: Success
1115184610Salfred * Else: Failure
1116184610Salfred *------------------------------------------------------------------------*/
1117193045Sthompsausb_error_t
1118194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx,
1119192984Sthompsa    struct usb_config_descriptor *d, uint8_t conf_index)
1120184610Salfred{
1121193045Sthompsa	usb_error_t err;
1122184610Salfred
1123184610Salfred	DPRINTFN(4, "confidx=%d\n", conf_index);
1124184610Salfred
1125194228Sthompsa	err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d),
1126184610Salfred	    sizeof(*d), 0, UDESC_CONFIG, conf_index, 0);
1127184610Salfred	if (err) {
1128184610Salfred		goto done;
1129184610Salfred	}
1130184610Salfred	/* Extra sanity checking */
1131184610Salfred	if (UGETW(d->wTotalLength) < sizeof(*d)) {
1132184610Salfred		err = USB_ERR_INVAL;
1133184610Salfred	}
1134184610Salfreddone:
1135184610Salfred	return (err);
1136184610Salfred}
1137184610Salfred
1138184610Salfred/*------------------------------------------------------------------------*
1139194228Sthompsa *	usbd_req_get_config_desc_full
1140184610Salfred *
1141184610Salfred * This function gets the complete USB configuration descriptor and
1142184610Salfred * ensures that "wTotalLength" is correct.
1143184610Salfred *
1144184610Salfred * Returns:
1145184610Salfred *    0: Success
1146184610Salfred * Else: Failure
1147184610Salfred *------------------------------------------------------------------------*/
1148193045Sthompsausb_error_t
1149194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx,
1150192984Sthompsa    struct usb_config_descriptor **ppcd, struct malloc_type *mtype,
1151184610Salfred    uint8_t index)
1152184610Salfred{
1153192984Sthompsa	struct usb_config_descriptor cd;
1154192984Sthompsa	struct usb_config_descriptor *cdesc;
1155184610Salfred	uint16_t len;
1156193045Sthompsa	usb_error_t err;
1157184610Salfred
1158184610Salfred	DPRINTFN(4, "index=%d\n", index);
1159184610Salfred
1160184610Salfred	*ppcd = NULL;
1161184610Salfred
1162194228Sthompsa	err = usbd_req_get_config_desc(udev, mtx, &cd, index);
1163184610Salfred	if (err) {
1164184610Salfred		return (err);
1165184610Salfred	}
1166184610Salfred	/* get full descriptor */
1167184610Salfred	len = UGETW(cd.wTotalLength);
1168184610Salfred	if (len < sizeof(*cdesc)) {
1169184610Salfred		/* corrupt descriptor */
1170184610Salfred		return (USB_ERR_INVAL);
1171184610Salfred	}
1172184610Salfred	cdesc = malloc(len, mtype, M_WAITOK);
1173184610Salfred	if (cdesc == NULL) {
1174184610Salfred		return (USB_ERR_NOMEM);
1175184610Salfred	}
1176194228Sthompsa	err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0,
1177184610Salfred	    UDESC_CONFIG, index, 3);
1178184610Salfred	if (err) {
1179184610Salfred		free(cdesc, mtype);
1180184610Salfred		return (err);
1181184610Salfred	}
1182184610Salfred	/* make sure that the device is not fooling us: */
1183184610Salfred	USETW(cdesc->wTotalLength, len);
1184184610Salfred
1185184610Salfred	*ppcd = cdesc;
1186184610Salfred
1187184610Salfred	return (0);			/* success */
1188184610Salfred}
1189184610Salfred
1190184610Salfred/*------------------------------------------------------------------------*
1191194228Sthompsa *	usbd_req_get_device_desc
1192184610Salfred *
1193184610Salfred * Returns:
1194184610Salfred *    0: Success
1195184610Salfred * Else: Failure
1196184610Salfred *------------------------------------------------------------------------*/
1197193045Sthompsausb_error_t
1198194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx,
1199192984Sthompsa    struct usb_device_descriptor *d)
1200184610Salfred{
1201184610Salfred	DPRINTFN(4, "\n");
1202194228Sthompsa	return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d),
1203184610Salfred	    sizeof(*d), 0, UDESC_DEVICE, 0, 3));
1204184610Salfred}
1205184610Salfred
1206184610Salfred/*------------------------------------------------------------------------*
1207194228Sthompsa *	usbd_req_get_alt_interface_no
1208184610Salfred *
1209184610Salfred * Returns:
1210184610Salfred *    0: Success
1211184610Salfred * Else: Failure
1212184610Salfred *------------------------------------------------------------------------*/
1213193045Sthompsausb_error_t
1214194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx,
1215184610Salfred    uint8_t *alt_iface_no, uint8_t iface_index)
1216184610Salfred{
1217194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1218192984Sthompsa	struct usb_device_request req;
1219184610Salfred
1220195963Salfred	if ((iface == NULL) || (iface->idesc == NULL))
1221184610Salfred		return (USB_ERR_INVAL);
1222195963Salfred
1223184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1224184610Salfred	req.bRequest = UR_GET_INTERFACE;
1225184610Salfred	USETW(req.wValue, 0);
1226184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1227184610Salfred	req.wIndex[1] = 0;
1228184610Salfred	USETW(req.wLength, 1);
1229194228Sthompsa	return (usbd_do_request(udev, mtx, &req, alt_iface_no));
1230184610Salfred}
1231184610Salfred
1232184610Salfred/*------------------------------------------------------------------------*
1233194228Sthompsa *	usbd_req_set_alt_interface_no
1234184610Salfred *
1235184610Salfred * Returns:
1236184610Salfred *    0: Success
1237184610Salfred * Else: Failure
1238184610Salfred *------------------------------------------------------------------------*/
1239193045Sthompsausb_error_t
1240194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx,
1241184610Salfred    uint8_t iface_index, uint8_t alt_no)
1242184610Salfred{
1243194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1244192984Sthompsa	struct usb_device_request req;
1245184610Salfred
1246195963Salfred	if ((iface == NULL) || (iface->idesc == NULL))
1247184610Salfred		return (USB_ERR_INVAL);
1248195963Salfred
1249184610Salfred	req.bmRequestType = UT_WRITE_INTERFACE;
1250184610Salfred	req.bRequest = UR_SET_INTERFACE;
1251184610Salfred	req.wValue[0] = alt_no;
1252184610Salfred	req.wValue[1] = 0;
1253184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1254184610Salfred	req.wIndex[1] = 0;
1255184610Salfred	USETW(req.wLength, 0);
1256194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1257184610Salfred}
1258184610Salfred
1259184610Salfred/*------------------------------------------------------------------------*
1260194228Sthompsa *	usbd_req_get_device_status
1261184610Salfred *
1262184610Salfred * Returns:
1263184610Salfred *    0: Success
1264184610Salfred * Else: Failure
1265184610Salfred *------------------------------------------------------------------------*/
1266193045Sthompsausb_error_t
1267194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx,
1268192984Sthompsa    struct usb_status *st)
1269184610Salfred{
1270192984Sthompsa	struct usb_device_request req;
1271184610Salfred
1272184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1273184610Salfred	req.bRequest = UR_GET_STATUS;
1274184610Salfred	USETW(req.wValue, 0);
1275184610Salfred	USETW(req.wIndex, 0);
1276184610Salfred	USETW(req.wLength, sizeof(*st));
1277194228Sthompsa	return (usbd_do_request(udev, mtx, &req, st));
1278184610Salfred}
1279184610Salfred
1280184610Salfred/*------------------------------------------------------------------------*
1281194228Sthompsa *	usbd_req_get_hub_descriptor
1282184610Salfred *
1283184610Salfred * Returns:
1284184610Salfred *    0: Success
1285184610Salfred * Else: Failure
1286184610Salfred *------------------------------------------------------------------------*/
1287193045Sthompsausb_error_t
1288194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx,
1289192984Sthompsa    struct usb_hub_descriptor *hd, uint8_t nports)
1290184610Salfred{
1291192984Sthompsa	struct usb_device_request req;
1292184610Salfred	uint16_t len = (nports + 7 + (8 * 8)) / 8;
1293184610Salfred
1294184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
1295184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1296184610Salfred	USETW2(req.wValue, UDESC_HUB, 0);
1297184610Salfred	USETW(req.wIndex, 0);
1298184610Salfred	USETW(req.wLength, len);
1299194228Sthompsa	return (usbd_do_request(udev, mtx, &req, hd));
1300184610Salfred}
1301184610Salfred
1302184610Salfred/*------------------------------------------------------------------------*
1303194228Sthompsa *	usbd_req_get_hub_status
1304184610Salfred *
1305184610Salfred * Returns:
1306184610Salfred *    0: Success
1307184610Salfred * Else: Failure
1308184610Salfred *------------------------------------------------------------------------*/
1309193045Sthompsausb_error_t
1310194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx,
1311192984Sthompsa    struct usb_hub_status *st)
1312184610Salfred{
1313192984Sthompsa	struct usb_device_request req;
1314184610Salfred
1315184610Salfred	req.bmRequestType = UT_READ_CLASS_DEVICE;
1316184610Salfred	req.bRequest = UR_GET_STATUS;
1317184610Salfred	USETW(req.wValue, 0);
1318184610Salfred	USETW(req.wIndex, 0);
1319192984Sthompsa	USETW(req.wLength, sizeof(struct usb_hub_status));
1320194228Sthompsa	return (usbd_do_request(udev, mtx, &req, st));
1321184610Salfred}
1322184610Salfred
1323184610Salfred/*------------------------------------------------------------------------*
1324194228Sthompsa *	usbd_req_set_address
1325184610Salfred *
1326184610Salfred * This function is used to set the address for an USB device. After
1327184610Salfred * port reset the USB device will respond at address zero.
1328184610Salfred *
1329184610Salfred * Returns:
1330184610Salfred *    0: Success
1331184610Salfred * Else: Failure
1332184610Salfred *------------------------------------------------------------------------*/
1333193045Sthompsausb_error_t
1334194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr)
1335184610Salfred{
1336192984Sthompsa	struct usb_device_request req;
1337184610Salfred
1338184610Salfred	DPRINTFN(6, "setting device address=%d\n", addr);
1339184610Salfred
1340184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1341184610Salfred	req.bRequest = UR_SET_ADDRESS;
1342184610Salfred	USETW(req.wValue, addr);
1343184610Salfred	USETW(req.wIndex, 0);
1344184610Salfred	USETW(req.wLength, 0);
1345184610Salfred
1346184610Salfred	/* Setting the address should not take more than 1 second ! */
1347194228Sthompsa	return (usbd_do_request_flags(udev, mtx, &req, NULL,
1348184610Salfred	    USB_DELAY_STATUS_STAGE, NULL, 1000));
1349184610Salfred}
1350184610Salfred
1351184610Salfred/*------------------------------------------------------------------------*
1352194228Sthompsa *	usbd_req_get_port_status
1353184610Salfred *
1354184610Salfred * Returns:
1355184610Salfred *    0: Success
1356184610Salfred * Else: Failure
1357184610Salfred *------------------------------------------------------------------------*/
1358193045Sthompsausb_error_t
1359194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx,
1360192984Sthompsa    struct usb_port_status *ps, uint8_t port)
1361184610Salfred{
1362192984Sthompsa	struct usb_device_request req;
1363184610Salfred
1364184610Salfred	req.bmRequestType = UT_READ_CLASS_OTHER;
1365184610Salfred	req.bRequest = UR_GET_STATUS;
1366184610Salfred	USETW(req.wValue, 0);
1367184610Salfred	req.wIndex[0] = port;
1368184610Salfred	req.wIndex[1] = 0;
1369184610Salfred	USETW(req.wLength, sizeof *ps);
1370194228Sthompsa	return (usbd_do_request(udev, mtx, &req, ps));
1371184610Salfred}
1372184610Salfred
1373184610Salfred/*------------------------------------------------------------------------*
1374194228Sthompsa *	usbd_req_clear_hub_feature
1375184610Salfred *
1376184610Salfred * Returns:
1377184610Salfred *    0: Success
1378184610Salfred * Else: Failure
1379184610Salfred *------------------------------------------------------------------------*/
1380193045Sthompsausb_error_t
1381194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx,
1382184610Salfred    uint16_t sel)
1383184610Salfred{
1384192984Sthompsa	struct usb_device_request req;
1385184610Salfred
1386184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1387184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1388184610Salfred	USETW(req.wValue, sel);
1389184610Salfred	USETW(req.wIndex, 0);
1390184610Salfred	USETW(req.wLength, 0);
1391194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1392184610Salfred}
1393184610Salfred
1394184610Salfred/*------------------------------------------------------------------------*
1395194228Sthompsa *	usbd_req_set_hub_feature
1396184610Salfred *
1397184610Salfred * Returns:
1398184610Salfred *    0: Success
1399184610Salfred * Else: Failure
1400184610Salfred *------------------------------------------------------------------------*/
1401193045Sthompsausb_error_t
1402194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx,
1403184610Salfred    uint16_t sel)
1404184610Salfred{
1405192984Sthompsa	struct usb_device_request req;
1406184610Salfred
1407184610Salfred	req.bmRequestType = UT_WRITE_CLASS_DEVICE;
1408184610Salfred	req.bRequest = UR_SET_FEATURE;
1409184610Salfred	USETW(req.wValue, sel);
1410184610Salfred	USETW(req.wIndex, 0);
1411184610Salfred	USETW(req.wLength, 0);
1412194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1413184610Salfred}
1414184610Salfred
1415184610Salfred/*------------------------------------------------------------------------*
1416194228Sthompsa *	usbd_req_clear_port_feature
1417184610Salfred *
1418184610Salfred * Returns:
1419184610Salfred *    0: Success
1420184610Salfred * Else: Failure
1421184610Salfred *------------------------------------------------------------------------*/
1422193045Sthompsausb_error_t
1423194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx,
1424184610Salfred    uint8_t port, uint16_t sel)
1425184610Salfred{
1426192984Sthompsa	struct usb_device_request req;
1427184610Salfred
1428184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1429184610Salfred	req.bRequest = UR_CLEAR_FEATURE;
1430184610Salfred	USETW(req.wValue, sel);
1431184610Salfred	req.wIndex[0] = port;
1432184610Salfred	req.wIndex[1] = 0;
1433184610Salfred	USETW(req.wLength, 0);
1434194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1435184610Salfred}
1436184610Salfred
1437184610Salfred/*------------------------------------------------------------------------*
1438194228Sthompsa *	usbd_req_set_port_feature
1439184610Salfred *
1440184610Salfred * Returns:
1441184610Salfred *    0: Success
1442184610Salfred * Else: Failure
1443184610Salfred *------------------------------------------------------------------------*/
1444193045Sthompsausb_error_t
1445194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx,
1446184610Salfred    uint8_t port, uint16_t sel)
1447184610Salfred{
1448192984Sthompsa	struct usb_device_request req;
1449184610Salfred
1450184610Salfred	req.bmRequestType = UT_WRITE_CLASS_OTHER;
1451184610Salfred	req.bRequest = UR_SET_FEATURE;
1452184610Salfred	USETW(req.wValue, sel);
1453184610Salfred	req.wIndex[0] = port;
1454184610Salfred	req.wIndex[1] = 0;
1455184610Salfred	USETW(req.wLength, 0);
1456194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1457184610Salfred}
1458184610Salfred
1459184610Salfred/*------------------------------------------------------------------------*
1460194228Sthompsa *	usbd_req_set_protocol
1461184610Salfred *
1462184610Salfred * Returns:
1463184610Salfred *    0: Success
1464184610Salfred * Else: Failure
1465184610Salfred *------------------------------------------------------------------------*/
1466193045Sthompsausb_error_t
1467194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx,
1468184610Salfred    uint8_t iface_index, uint16_t report)
1469184610Salfred{
1470194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1471192984Sthompsa	struct usb_device_request req;
1472184610Salfred
1473184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1474184610Salfred		return (USB_ERR_INVAL);
1475184610Salfred	}
1476184610Salfred	DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n",
1477184610Salfred	    iface, report, iface->idesc->bInterfaceNumber);
1478184610Salfred
1479184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1480184610Salfred	req.bRequest = UR_SET_PROTOCOL;
1481184610Salfred	USETW(req.wValue, report);
1482184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1483184610Salfred	req.wIndex[1] = 0;
1484184610Salfred	USETW(req.wLength, 0);
1485194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1486184610Salfred}
1487184610Salfred
1488184610Salfred/*------------------------------------------------------------------------*
1489194228Sthompsa *	usbd_req_set_report
1490184610Salfred *
1491184610Salfred * Returns:
1492184610Salfred *    0: Success
1493184610Salfred * Else: Failure
1494184610Salfred *------------------------------------------------------------------------*/
1495193045Sthompsausb_error_t
1496194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len,
1497184610Salfred    uint8_t iface_index, uint8_t type, uint8_t id)
1498184610Salfred{
1499194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1500192984Sthompsa	struct usb_device_request req;
1501184610Salfred
1502184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1503184610Salfred		return (USB_ERR_INVAL);
1504184610Salfred	}
1505184610Salfred	DPRINTFN(5, "len=%d\n", len);
1506184610Salfred
1507184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1508184610Salfred	req.bRequest = UR_SET_REPORT;
1509184610Salfred	USETW2(req.wValue, type, id);
1510184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1511184610Salfred	req.wIndex[1] = 0;
1512184610Salfred	USETW(req.wLength, len);
1513194228Sthompsa	return (usbd_do_request(udev, mtx, &req, data));
1514184610Salfred}
1515184610Salfred
1516184610Salfred/*------------------------------------------------------------------------*
1517194228Sthompsa *	usbd_req_get_report
1518184610Salfred *
1519184610Salfred * Returns:
1520184610Salfred *    0: Success
1521184610Salfred * Else: Failure
1522184610Salfred *------------------------------------------------------------------------*/
1523193045Sthompsausb_error_t
1524194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data,
1525184610Salfred    uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id)
1526184610Salfred{
1527194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1528192984Sthompsa	struct usb_device_request req;
1529184610Salfred
1530184610Salfred	if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) {
1531184610Salfred		return (USB_ERR_INVAL);
1532184610Salfred	}
1533184610Salfred	DPRINTFN(5, "len=%d\n", len);
1534184610Salfred
1535184610Salfred	req.bmRequestType = UT_READ_CLASS_INTERFACE;
1536184610Salfred	req.bRequest = UR_GET_REPORT;
1537184610Salfred	USETW2(req.wValue, type, id);
1538184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1539184610Salfred	req.wIndex[1] = 0;
1540184610Salfred	USETW(req.wLength, len);
1541194228Sthompsa	return (usbd_do_request(udev, mtx, &req, data));
1542184610Salfred}
1543184610Salfred
1544184610Salfred/*------------------------------------------------------------------------*
1545194228Sthompsa *	usbd_req_set_idle
1546184610Salfred *
1547184610Salfred * Returns:
1548184610Salfred *    0: Success
1549184610Salfred * Else: Failure
1550184610Salfred *------------------------------------------------------------------------*/
1551193045Sthompsausb_error_t
1552194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx,
1553184610Salfred    uint8_t iface_index, uint8_t duration, uint8_t id)
1554184610Salfred{
1555194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1556192984Sthompsa	struct usb_device_request req;
1557184610Salfred
1558184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1559184610Salfred		return (USB_ERR_INVAL);
1560184610Salfred	}
1561184610Salfred	DPRINTFN(5, "%d %d\n", duration, id);
1562184610Salfred
1563184610Salfred	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
1564184610Salfred	req.bRequest = UR_SET_IDLE;
1565184610Salfred	USETW2(req.wValue, duration, id);
1566184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1567184610Salfred	req.wIndex[1] = 0;
1568184610Salfred	USETW(req.wLength, 0);
1569194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1570184610Salfred}
1571184610Salfred
1572184610Salfred/*------------------------------------------------------------------------*
1573194228Sthompsa *	usbd_req_get_report_descriptor
1574184610Salfred *
1575184610Salfred * Returns:
1576184610Salfred *    0: Success
1577184610Salfred * Else: Failure
1578184610Salfred *------------------------------------------------------------------------*/
1579193045Sthompsausb_error_t
1580194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx,
1581184610Salfred    void *d, uint16_t size, uint8_t iface_index)
1582184610Salfred{
1583194228Sthompsa	struct usb_interface *iface = usbd_get_iface(udev, iface_index);
1584192984Sthompsa	struct usb_device_request req;
1585184610Salfred
1586184610Salfred	if ((iface == NULL) || (iface->idesc == NULL)) {
1587184610Salfred		return (USB_ERR_INVAL);
1588184610Salfred	}
1589184610Salfred	req.bmRequestType = UT_READ_INTERFACE;
1590184610Salfred	req.bRequest = UR_GET_DESCRIPTOR;
1591184610Salfred	USETW2(req.wValue, UDESC_REPORT, 0);	/* report id should be 0 */
1592184610Salfred	req.wIndex[0] = iface->idesc->bInterfaceNumber;
1593184610Salfred	req.wIndex[1] = 0;
1594184610Salfred	USETW(req.wLength, size);
1595194228Sthompsa	return (usbd_do_request(udev, mtx, &req, d));
1596184610Salfred}
1597184610Salfred
1598184610Salfred/*------------------------------------------------------------------------*
1599194228Sthompsa *	usbd_req_set_config
1600184610Salfred *
1601184610Salfred * This function is used to select the current configuration number in
1602184610Salfred * both USB device side mode and USB host side mode. When setting the
1603184610Salfred * configuration the function of the interfaces can change.
1604184610Salfred *
1605184610Salfred * Returns:
1606184610Salfred *    0: Success
1607184610Salfred * Else: Failure
1608184610Salfred *------------------------------------------------------------------------*/
1609193045Sthompsausb_error_t
1610194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf)
1611184610Salfred{
1612192984Sthompsa	struct usb_device_request req;
1613184610Salfred
1614184610Salfred	DPRINTF("setting config %d\n", conf);
1615184610Salfred
1616184610Salfred	/* do "set configuration" request */
1617184610Salfred
1618184610Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1619184610Salfred	req.bRequest = UR_SET_CONFIG;
1620184610Salfred	req.wValue[0] = conf;
1621184610Salfred	req.wValue[1] = 0;
1622184610Salfred	USETW(req.wIndex, 0);
1623184610Salfred	USETW(req.wLength, 0);
1624194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1625184610Salfred}
1626184610Salfred
1627184610Salfred/*------------------------------------------------------------------------*
1628194228Sthompsa *	usbd_req_get_config
1629184610Salfred *
1630184610Salfred * Returns:
1631184610Salfred *    0: Success
1632184610Salfred * Else: Failure
1633184610Salfred *------------------------------------------------------------------------*/
1634193045Sthompsausb_error_t
1635194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf)
1636184610Salfred{
1637192984Sthompsa	struct usb_device_request req;
1638184610Salfred
1639184610Salfred	req.bmRequestType = UT_READ_DEVICE;
1640184610Salfred	req.bRequest = UR_GET_CONFIG;
1641184610Salfred	USETW(req.wValue, 0);
1642184610Salfred	USETW(req.wIndex, 0);
1643184610Salfred	USETW(req.wLength, 1);
1644194228Sthompsa	return (usbd_do_request(udev, mtx, &req, pconf));
1645184610Salfred}
1646184610Salfred
1647184610Salfred/*------------------------------------------------------------------------*
1648194228Sthompsa *	usbd_req_re_enumerate
1649184610Salfred *
1650185087Salfred * NOTE: After this function returns the hardware is in the
1651185087Salfred * unconfigured state! The application is responsible for setting a
1652185087Salfred * new configuration.
1653185087Salfred *
1654184610Salfred * Returns:
1655184610Salfred *    0: Success
1656184610Salfred * Else: Failure
1657184610Salfred *------------------------------------------------------------------------*/
1658193045Sthompsausb_error_t
1659194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx)
1660184610Salfred{
1661192984Sthompsa	struct usb_device *parent_hub;
1662193045Sthompsa	usb_error_t err;
1663184610Salfred	uint8_t old_addr;
1664186730Salfred	uint8_t do_retry = 1;
1665184610Salfred
1666192499Sthompsa	if (udev->flags.usb_mode != USB_MODE_HOST) {
1667185290Salfred		return (USB_ERR_INVAL);
1668185290Salfred	}
1669184610Salfred	old_addr = udev->address;
1670184610Salfred	parent_hub = udev->parent_hub;
1671184610Salfred	if (parent_hub == NULL) {
1672185290Salfred		return (USB_ERR_INVAL);
1673184610Salfred	}
1674186730Salfredretry:
1675194228Sthompsa	err = usbd_req_reset_port(parent_hub, mtx, udev->port_no);
1676184610Salfred	if (err) {
1677190739Sthompsa		DPRINTFN(0, "addr=%d, port reset failed, %s\n",
1678194228Sthompsa		    old_addr, usbd_errstr(err));
1679184610Salfred		goto done;
1680184610Salfred	}
1681184610Salfred	/*
1682184610Salfred	 * After that the port has been reset our device should be at
1683184610Salfred	 * address zero:
1684184610Salfred	 */
1685184610Salfred	udev->address = USB_START_ADDR;
1686184610Salfred
1687185290Salfred	/* reset "bMaxPacketSize" */
1688185290Salfred	udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET;
1689185290Salfred
1690184610Salfred	/*
1691184610Salfred	 * Restore device address:
1692184610Salfred	 */
1693194228Sthompsa	err = usbd_req_set_address(udev, mtx, old_addr);
1694184610Salfred	if (err) {
1695184610Salfred		/* XXX ignore any errors! */
1696190739Sthompsa		DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n",
1697194228Sthompsa		    old_addr, usbd_errstr(err));
1698184610Salfred	}
1699184610Salfred	/* restore device address */
1700184610Salfred	udev->address = old_addr;
1701184610Salfred
1702184610Salfred	/* allow device time to set new address */
1703194228Sthompsa	usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE));
1704184610Salfred
1705184610Salfred	/* get the device descriptor */
1706194228Sthompsa	err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc,
1707185290Salfred	    USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0);
1708184610Salfred	if (err) {
1709185290Salfred		DPRINTFN(0, "getting device descriptor "
1710199816Sthompsa		    "at addr %d failed, %s\n", udev->address,
1711194228Sthompsa		    usbd_errstr(err));
1712185290Salfred		goto done;
1713185290Salfred	}
1714185290Salfred	/* get the full device descriptor */
1715194228Sthompsa	err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc);
1716185290Salfred	if (err) {
1717184610Salfred		DPRINTFN(0, "addr=%d, getting device "
1718199816Sthompsa		    "descriptor failed, %s\n", old_addr,
1719194228Sthompsa		    usbd_errstr(err));
1720184610Salfred		goto done;
1721184610Salfred	}
1722184610Salfreddone:
1723186730Salfred	if (err && do_retry) {
1724186730Salfred		/* give the USB firmware some time to load */
1725194228Sthompsa		usb_pause_mtx(mtx, hz / 2);
1726186730Salfred		/* no more retries after this retry */
1727186730Salfred		do_retry = 0;
1728186730Salfred		/* try again */
1729186730Salfred		goto retry;
1730186730Salfred	}
1731184610Salfred	/* restore address */
1732184610Salfred	udev->address = old_addr;
1733184610Salfred	return (err);
1734184610Salfred}
1735186730Salfred
1736186730Salfred/*------------------------------------------------------------------------*
1737194228Sthompsa *	usbd_req_clear_device_feature
1738186730Salfred *
1739186730Salfred * Returns:
1740186730Salfred *    0: Success
1741186730Salfred * Else: Failure
1742186730Salfred *------------------------------------------------------------------------*/
1743193045Sthompsausb_error_t
1744194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx,
1745186730Salfred    uint16_t sel)
1746186730Salfred{
1747192984Sthompsa	struct usb_device_request req;
1748186730Salfred
1749186730Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1750186730Salfred	req.bRequest = UR_CLEAR_FEATURE;
1751186730Salfred	USETW(req.wValue, sel);
1752186730Salfred	USETW(req.wIndex, 0);
1753186730Salfred	USETW(req.wLength, 0);
1754194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1755186730Salfred}
1756186730Salfred
1757186730Salfred/*------------------------------------------------------------------------*
1758194228Sthompsa *	usbd_req_set_device_feature
1759186730Salfred *
1760186730Salfred * Returns:
1761186730Salfred *    0: Success
1762186730Salfred * Else: Failure
1763186730Salfred *------------------------------------------------------------------------*/
1764193045Sthompsausb_error_t
1765194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx,
1766186730Salfred    uint16_t sel)
1767186730Salfred{
1768192984Sthompsa	struct usb_device_request req;
1769186730Salfred
1770186730Salfred	req.bmRequestType = UT_WRITE_DEVICE;
1771186730Salfred	req.bRequest = UR_SET_FEATURE;
1772186730Salfred	USETW(req.wValue, sel);
1773186730Salfred	USETW(req.wIndex, 0);
1774186730Salfred	USETW(req.wLength, 0);
1775194228Sthompsa	return (usbd_do_request(udev, mtx, &req, 0));
1776186730Salfred}
1777