usb_request.c revision 224095
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 224095 2011-07-16 12:50:30Z 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/module.h> 38194677Sthompsa#include <sys/lock.h> 39194677Sthompsa#include <sys/mutex.h> 40194677Sthompsa#include <sys/condvar.h> 41194677Sthompsa#include <sys/sysctl.h> 42194677Sthompsa#include <sys/sx.h> 43194677Sthompsa#include <sys/unistd.h> 44194677Sthompsa#include <sys/callout.h> 45194677Sthompsa#include <sys/malloc.h> 46194677Sthompsa#include <sys/priv.h> 47194677Sthompsa 48188942Sthompsa#include <dev/usb/usb.h> 49194677Sthompsa#include <dev/usb/usbdi.h> 50194677Sthompsa#include <dev/usb/usbdi_util.h> 51188942Sthompsa#include <dev/usb/usb_ioctl.h> 52188942Sthompsa#include <dev/usb/usbhid.h> 53184610Salfred 54194228Sthompsa#define USB_DEBUG_VAR usb_debug 55184610Salfred 56188942Sthompsa#include <dev/usb/usb_core.h> 57188942Sthompsa#include <dev/usb/usb_busdma.h> 58188942Sthompsa#include <dev/usb/usb_request.h> 59188942Sthompsa#include <dev/usb/usb_process.h> 60188942Sthompsa#include <dev/usb/usb_transfer.h> 61188942Sthompsa#include <dev/usb/usb_debug.h> 62188942Sthompsa#include <dev/usb/usb_device.h> 63188942Sthompsa#include <dev/usb/usb_util.h> 64188942Sthompsa#include <dev/usb/usb_dynamic.h> 65184610Salfred 66188942Sthompsa#include <dev/usb/usb_controller.h> 67188942Sthompsa#include <dev/usb/usb_bus.h> 68184610Salfred#include <sys/ctype.h> 69184610Salfred 70207077Sthompsa#ifdef USB_DEBUG 71194228Sthompsastatic int usb_pr_poll_delay = USB_PORT_RESET_DELAY; 72194228Sthompsastatic int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY; 73184610Salfred 74192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW, 75194228Sthompsa &usb_pr_poll_delay, 0, "USB port reset poll delay in ms"); 76192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, 77194228Sthompsa &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms"); 78184610Salfred 79208018Sthompsa#ifdef USB_REQ_DEBUG 80208018Sthompsa/* The following structures are used in connection to fault injection. */ 81208018Sthompsastruct usb_ctrl_debug { 82208018Sthompsa int bus_index; /* target bus */ 83208018Sthompsa int dev_index; /* target address */ 84208018Sthompsa int ds_fail; /* fail data stage */ 85208018Sthompsa int ss_fail; /* fail data stage */ 86208018Sthompsa int ds_delay; /* data stage delay in ms */ 87208018Sthompsa int ss_delay; /* status stage delay in ms */ 88208018Sthompsa int bmRequestType_value; 89208018Sthompsa int bRequest_value; 90208018Sthompsa}; 91208018Sthompsa 92208018Sthompsastruct usb_ctrl_debug_bits { 93208018Sthompsa uint16_t ds_delay; 94208018Sthompsa uint16_t ss_delay; 95208018Sthompsa uint8_t ds_fail:1; 96208018Sthompsa uint8_t ss_fail:1; 97208018Sthompsa uint8_t enabled:1; 98208018Sthompsa}; 99208018Sthompsa 100208018Sthompsa/* The default is to disable fault injection. */ 101208018Sthompsa 102208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = { 103208018Sthompsa .bus_index = -1, 104208018Sthompsa .dev_index = -1, 105208018Sthompsa .bmRequestType_value = -1, 106208018Sthompsa .bRequest_value = -1, 107208018Sthompsa}; 108208018Sthompsa 109208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW, 110208018Sthompsa &usb_ctrl_debug.bus_index, 0, "USB controller index to fail"); 111208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW, 112208018Sthompsa &usb_ctrl_debug.dev_index, 0, "USB device address to fail"); 113208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW, 114208018Sthompsa &usb_ctrl_debug.ds_fail, 0, "USB fail data stage"); 115208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW, 116208018Sthompsa &usb_ctrl_debug.ss_fail, 0, "USB fail status stage"); 117208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW, 118208018Sthompsa &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms"); 119208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW, 120208018Sthompsa &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms"); 121208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW, 122208018Sthompsa &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail"); 123208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW, 124208018Sthompsa &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail"); 125208018Sthompsa 126184610Salfred/*------------------------------------------------------------------------* 127208018Sthompsa * usbd_get_debug_bits 128208018Sthompsa * 129208018Sthompsa * This function is only useful in USB host mode. 130208018Sthompsa *------------------------------------------------------------------------*/ 131208018Sthompsastatic void 132208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, 133208018Sthompsa struct usb_ctrl_debug_bits *dbg) 134208018Sthompsa{ 135208018Sthompsa int temp; 136208018Sthompsa 137208018Sthompsa memset(dbg, 0, sizeof(*dbg)); 138208018Sthompsa 139208018Sthompsa /* Compute data stage delay */ 140208018Sthompsa 141208018Sthompsa temp = usb_ctrl_debug.ds_delay; 142208018Sthompsa if (temp < 0) 143208018Sthompsa temp = 0; 144208018Sthompsa else if (temp > (16*1024)) 145208018Sthompsa temp = (16*1024); 146208018Sthompsa 147208018Sthompsa dbg->ds_delay = temp; 148208018Sthompsa 149208018Sthompsa /* Compute status stage delay */ 150208018Sthompsa 151208018Sthompsa temp = usb_ctrl_debug.ss_delay; 152208018Sthompsa if (temp < 0) 153208018Sthompsa temp = 0; 154208018Sthompsa else if (temp > (16*1024)) 155208018Sthompsa temp = (16*1024); 156208018Sthompsa 157208018Sthompsa dbg->ss_delay = temp; 158208018Sthompsa 159208018Sthompsa /* Check if this control request should be failed */ 160208018Sthompsa 161208018Sthompsa if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) 162208018Sthompsa return; 163208018Sthompsa 164208018Sthompsa if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) 165208018Sthompsa return; 166208018Sthompsa 167208018Sthompsa temp = usb_ctrl_debug.bmRequestType_value; 168208018Sthompsa 169208018Sthompsa if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) 170208018Sthompsa return; 171208018Sthompsa 172208018Sthompsa temp = usb_ctrl_debug.bRequest_value; 173208018Sthompsa 174208018Sthompsa if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) 175208018Sthompsa return; 176208018Sthompsa 177208018Sthompsa temp = usb_ctrl_debug.ds_fail; 178208018Sthompsa if (temp) 179208018Sthompsa dbg->ds_fail = 1; 180208018Sthompsa 181208018Sthompsa temp = usb_ctrl_debug.ss_fail; 182208018Sthompsa if (temp) 183208018Sthompsa dbg->ss_fail = 1; 184208018Sthompsa 185208018Sthompsa dbg->enabled = 1; 186208018Sthompsa} 187208018Sthompsa#endif /* USB_REQ_DEBUG */ 188208018Sthompsa#endif /* USB_DEBUG */ 189208018Sthompsa 190208018Sthompsa/*------------------------------------------------------------------------* 191194228Sthompsa * usbd_do_request_callback 192184610Salfred * 193184610Salfred * This function is the USB callback for generic USB Host control 194184610Salfred * transfers. 195184610Salfred *------------------------------------------------------------------------*/ 196184610Salfredvoid 197194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error) 198184610Salfred{ 199184610Salfred ; /* workaround for a bug in "indent" */ 200184610Salfred 201184610Salfred DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 202184610Salfred 203184610Salfred switch (USB_GET_STATE(xfer)) { 204184610Salfred case USB_ST_SETUP: 205194228Sthompsa usbd_transfer_submit(xfer); 206184610Salfred break; 207184610Salfred default: 208207079Sthompsa cv_signal(&xfer->xroot->udev->ctrlreq_cv); 209184610Salfred break; 210184610Salfred } 211184610Salfred} 212184610Salfred 213184610Salfred/*------------------------------------------------------------------------* 214194228Sthompsa * usb_do_clear_stall_callback 215184610Salfred * 216184610Salfred * This function is the USB callback for generic clear stall requests. 217184610Salfred *------------------------------------------------------------------------*/ 218184610Salfredvoid 219194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 220184610Salfred{ 221192984Sthompsa struct usb_device_request req; 222192984Sthompsa struct usb_device *udev; 223193644Sthompsa struct usb_endpoint *ep; 224193644Sthompsa struct usb_endpoint *ep_end; 225193644Sthompsa struct usb_endpoint *ep_first; 226190731Sthompsa uint8_t to; 227184610Salfred 228187173Sthompsa udev = xfer->xroot->udev; 229184610Salfred 230187173Sthompsa USB_BUS_LOCK(udev->bus); 231187173Sthompsa 232193644Sthompsa /* round robin endpoint clear stall */ 233184610Salfred 234193644Sthompsa ep = udev->ep_curr; 235193644Sthompsa ep_end = udev->endpoints + udev->endpoints_max; 236193644Sthompsa ep_first = udev->endpoints; 237193644Sthompsa to = udev->endpoints_max; 238193318Sthompsa 239184610Salfred switch (USB_GET_STATE(xfer)) { 240184610Salfred case USB_ST_TRANSFERRED: 241222786Shselasky 242222786Shselasky /* reset error counter */ 243222786Shselasky udev->clear_stall_errors = 0; 244222786Shselasky 245193644Sthompsa if (ep == NULL) 246193318Sthompsa goto tr_setup; /* device was unconfigured */ 247193644Sthompsa if (ep->edesc && 248193644Sthompsa ep->is_stalled) { 249193644Sthompsa ep->toggle_next = 0; 250193644Sthompsa ep->is_stalled = 0; 251213435Shselasky /* some hardware needs a callback to clear the data toggle */ 252213435Shselasky usbd_clear_stall_locked(udev, ep); 253184610Salfred /* start up the current or next transfer, if any */ 254194228Sthompsa usb_command_wrapper(&ep->endpoint_q, 255193644Sthompsa ep->endpoint_q.curr); 256184610Salfred } 257193644Sthompsa ep++; 258184610Salfred 259184610Salfred case USB_ST_SETUP: 260184610Salfredtr_setup: 261193318Sthompsa if (to == 0) 262193644Sthompsa break; /* no endpoints - nothing to do */ 263193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 264193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 265193644Sthompsa if (ep->edesc && 266193644Sthompsa ep->is_stalled) { 267184610Salfred 268184610Salfred /* setup a clear-stall packet */ 269184610Salfred 270184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 271184610Salfred req.bRequest = UR_CLEAR_FEATURE; 272184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 273193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 274184610Salfred req.wIndex[1] = 0; 275184610Salfred USETW(req.wLength, 0); 276184610Salfred 277184610Salfred /* copy in the transfer */ 278184610Salfred 279194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 280184610Salfred 281184610Salfred /* set length */ 282194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 283184610Salfred xfer->nframes = 1; 284187173Sthompsa USB_BUS_UNLOCK(udev->bus); 285184610Salfred 286194228Sthompsa usbd_transfer_submit(xfer); 287184610Salfred 288187173Sthompsa USB_BUS_LOCK(udev->bus); 289184610Salfred break; 290184610Salfred } 291193644Sthompsa ep++; 292193318Sthompsa to--; 293193318Sthompsa goto tr_setup; 294184610Salfred 295184610Salfred default: 296222786Shselasky if (error == USB_ERR_CANCELLED) 297184610Salfred break; 298222786Shselasky 299222786Shselasky DPRINTF("Clear stall failed.\n"); 300222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) 301222786Shselasky goto tr_setup; 302222786Shselasky 303222786Shselasky if (error == USB_ERR_TIMEOUT) { 304222786Shselasky udev->clear_stall_errors = USB_CS_RESET_LIMIT; 305222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 306222786Shselasky usbd_start_re_enumerate(udev); 307222786Shselasky } else { 308222786Shselasky udev->clear_stall_errors++; 309222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) { 310222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 311222786Shselasky usbd_start_re_enumerate(udev); 312222786Shselasky } 313184610Salfred } 314184610Salfred goto tr_setup; 315184610Salfred } 316184610Salfred 317193644Sthompsa /* store current endpoint */ 318193644Sthompsa udev->ep_curr = ep; 319187173Sthompsa USB_BUS_UNLOCK(udev->bus); 320184610Salfred} 321184610Salfred 322193045Sthompsastatic usb_handle_req_t * 323194228Sthompsausbd_get_hr_func(struct usb_device *udev) 324191402Sthompsa{ 325191402Sthompsa /* figure out if there is a Handle Request function */ 326192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 327194228Sthompsa return (usb_temp_get_desc_p); 328191402Sthompsa else if (udev->parent_hub == NULL) 329191402Sthompsa return (udev->bus->methods->roothub_exec); 330191402Sthompsa else 331191402Sthompsa return (NULL); 332191402Sthompsa} 333191402Sthompsa 334184610Salfred/*------------------------------------------------------------------------* 335194228Sthompsa * usbd_do_request_flags and usbd_do_request 336184610Salfred * 337184610Salfred * Description of arguments passed to these functions: 338184610Salfred * 339192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 340184610Salfred * request should be performed. It is possible to call this function 341184610Salfred * in both Host Side mode and Device Side mode. 342184610Salfred * 343184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 344184610Salfred * will get dropped and picked up during the execution of this 345184610Salfred * function, hence this function sometimes needs to sleep. If this 346184610Salfred * argument is NULL it has no effect. 347184610Salfred * 348184610Salfred * "req" - this argument must always be non-NULL and points to an 349184610Salfred * 8-byte structure holding the USB request to be done. The USB 350184610Salfred * request structure has a bit telling the direction of the USB 351184610Salfred * request, if it is a read or a write. 352184610Salfred * 353184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 354184610Salfred * is non-zero this argument must point to a valid kernel buffer which 355184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 356184610Salfred * be NULL. 357184610Salfred * 358184610Salfred * "flags" - here is a list of valid flags: 359184610Salfred * 360184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 361184610Salfred * specified 362184610Salfred * 363184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 364184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 365184610Salfred * sysctl. This flag is mostly useful for debugging. 366184610Salfred * 367184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 368184610Salfred * pointer. 369184610Salfred * 370184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 371184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 372184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 373184610Salfred * used. 374184610Salfred * 375184610Salfred * "timeout" - gives the timeout for the control transfer in 376184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 377184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 378184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 379184610Salfred * does not allow control requests without a timeout. 380184610Salfred * 381184610Salfred * NOTE: This function is thread safe. All calls to 382194228Sthompsa * "usbd_do_request_flags" will be serialised by the use of an 383184610Salfred * internal "sx_lock". 384184610Salfred * 385184610Salfred * Returns: 386184610Salfred * 0: Success 387184610Salfred * Else: Failure 388184610Salfred *------------------------------------------------------------------------*/ 389193045Sthompsausb_error_t 390194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 391192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 392193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 393184610Salfred{ 394208018Sthompsa#ifdef USB_REQ_DEBUG 395208018Sthompsa struct usb_ctrl_debug_bits dbg; 396208018Sthompsa#endif 397193045Sthompsa usb_handle_req_t *hr_func; 398192984Sthompsa struct usb_xfer *xfer; 399184610Salfred const void *desc; 400184610Salfred int err = 0; 401193045Sthompsa usb_ticks_t start_ticks; 402193045Sthompsa usb_ticks_t delta_ticks; 403193045Sthompsa usb_ticks_t max_ticks; 404184610Salfred uint16_t length; 405184610Salfred uint16_t temp; 406208018Sthompsa uint16_t acttemp; 407208008Sthompsa uint8_t enum_locked; 408184610Salfred 409184610Salfred if (timeout < 50) { 410184610Salfred /* timeout is too small */ 411184610Salfred timeout = 50; 412184610Salfred } 413184610Salfred if (timeout > 30000) { 414184610Salfred /* timeout is too big */ 415184610Salfred timeout = 30000; 416184610Salfred } 417184610Salfred length = UGETW(req->wLength); 418184610Salfred 419208008Sthompsa enum_locked = usbd_enum_is_locked(udev); 420208008Sthompsa 421184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 422184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 423184610Salfred udev, req->bmRequestType, req->bRequest, 424184610Salfred req->wValue[1], req->wValue[0], 425184610Salfred req->wIndex[1], req->wIndex[0], 426184610Salfred req->wLength[1], req->wLength[0]); 427184610Salfred 428191494Sthompsa /* Check if the device is still alive */ 429191494Sthompsa if (udev->state < USB_STATE_POWERED) { 430191494Sthompsa DPRINTF("usb device has gone\n"); 431191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 432191494Sthompsa } 433191494Sthompsa 434184610Salfred /* 435184610Salfred * Set "actlen" to a known value in case the caller does not 436184610Salfred * check the return value: 437184610Salfred */ 438190735Sthompsa if (actlen) 439184610Salfred *actlen = 0; 440190735Sthompsa 441190180Sthompsa#if (USB_HAVE_USER_IO == 0) 442190180Sthompsa if (flags & USB_USER_DATA_PTR) 443190180Sthompsa return (USB_ERR_INVAL); 444190180Sthompsa#endif 445208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) { 446184610Salfred mtx_unlock(mtx); 447208008Sthompsa mtx_assert(mtx, MA_NOTOWNED); 448184610Salfred } 449208008Sthompsa 450184610Salfred /* 451208008Sthompsa * We need to allow suspend and resume at this point, else the 452208008Sthompsa * control transfer will timeout if the device is suspended! 453208008Sthompsa */ 454208008Sthompsa if (enum_locked) 455208008Sthompsa usbd_sr_unlock(udev); 456208008Sthompsa 457208008Sthompsa /* 458184610Salfred * Grab the default sx-lock so that serialisation 459184610Salfred * is achieved when multiple threads are involved: 460184610Salfred */ 461207079Sthompsa sx_xlock(&udev->ctrl_sx); 462184610Salfred 463194228Sthompsa hr_func = usbd_get_hr_func(udev); 464190735Sthompsa 465191402Sthompsa if (hr_func != NULL) { 466191402Sthompsa DPRINTF("Handle Request function is set\n"); 467190735Sthompsa 468191402Sthompsa desc = NULL; 469191402Sthompsa temp = 0; 470191402Sthompsa 471191402Sthompsa if (!(req->bmRequestType & UT_READ)) { 472190735Sthompsa if (length != 0) { 473191402Sthompsa DPRINTFN(1, "The handle request function " 474191402Sthompsa "does not support writing data!\n"); 475191402Sthompsa err = USB_ERR_INVAL; 476191402Sthompsa goto done; 477190735Sthompsa } 478190735Sthompsa } 479190735Sthompsa 480191402Sthompsa /* The root HUB code needs the BUS lock locked */ 481191402Sthompsa 482190735Sthompsa USB_BUS_LOCK(udev->bus); 483191402Sthompsa err = (hr_func) (udev, req, &desc, &temp); 484190735Sthompsa USB_BUS_UNLOCK(udev->bus); 485190735Sthompsa 486190735Sthompsa if (err) 487190735Sthompsa goto done; 488190735Sthompsa 489191402Sthompsa if (length > temp) { 490190735Sthompsa if (!(flags & USB_SHORT_XFER_OK)) { 491190735Sthompsa err = USB_ERR_SHORT_XFER; 492190735Sthompsa goto done; 493190735Sthompsa } 494191402Sthompsa length = temp; 495190735Sthompsa } 496190735Sthompsa if (actlen) 497190735Sthompsa *actlen = length; 498190735Sthompsa 499190735Sthompsa if (length > 0) { 500190735Sthompsa#if USB_HAVE_USER_IO 501190735Sthompsa if (flags & USB_USER_DATA_PTR) { 502191402Sthompsa if (copyout(desc, data, length)) { 503190735Sthompsa err = USB_ERR_INVAL; 504190735Sthompsa goto done; 505190735Sthompsa } 506190735Sthompsa } else 507190735Sthompsa#endif 508191402Sthompsa bcopy(desc, data, length); 509190735Sthompsa } 510191402Sthompsa goto done; /* success */ 511190735Sthompsa } 512190735Sthompsa 513184610Salfred /* 514184610Salfred * Setup a new USB transfer or use the existing one, if any: 515184610Salfred */ 516207080Sthompsa usbd_ctrl_transfer_setup(udev); 517184610Salfred 518207080Sthompsa xfer = udev->ctrl_xfer[0]; 519184610Salfred if (xfer == NULL) { 520184610Salfred /* most likely out of memory */ 521184610Salfred err = USB_ERR_NOMEM; 522184610Salfred goto done; 523184610Salfred } 524208018Sthompsa 525208018Sthompsa#ifdef USB_REQ_DEBUG 526208018Sthompsa /* Get debug bits */ 527208018Sthompsa usbd_get_debug_bits(udev, req, &dbg); 528208018Sthompsa 529208018Sthompsa /* Check for fault injection */ 530208018Sthompsa if (dbg.enabled) 531208018Sthompsa flags |= USB_DELAY_STATUS_STAGE; 532208018Sthompsa#endif 533184824Sthompsa USB_XFER_LOCK(xfer); 534184610Salfred 535190734Sthompsa if (flags & USB_DELAY_STATUS_STAGE) 536184610Salfred xfer->flags.manual_status = 1; 537190734Sthompsa else 538184610Salfred xfer->flags.manual_status = 0; 539184610Salfred 540190734Sthompsa if (flags & USB_SHORT_XFER_OK) 541190734Sthompsa xfer->flags.short_xfer_ok = 1; 542190734Sthompsa else 543190734Sthompsa xfer->flags.short_xfer_ok = 0; 544190734Sthompsa 545184610Salfred xfer->timeout = timeout; 546184610Salfred 547184610Salfred start_ticks = ticks; 548184610Salfred 549184610Salfred max_ticks = USB_MS_TO_TICKS(timeout); 550184610Salfred 551194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 552184610Salfred 553194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); 554184610Salfred 555184610Salfred while (1) { 556184610Salfred temp = length; 557208018Sthompsa if (temp > usbd_xfer_max_len(xfer)) { 558194677Sthompsa temp = usbd_xfer_max_len(xfer); 559184610Salfred } 560208018Sthompsa#ifdef USB_REQ_DEBUG 561208018Sthompsa if (xfer->flags.manual_status) { 562208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) != 0) { 563208018Sthompsa /* Execute data stage separately */ 564208018Sthompsa temp = 0; 565208018Sthompsa } else if (temp > 0) { 566208018Sthompsa if (dbg.ds_fail) { 567208018Sthompsa err = USB_ERR_INVAL; 568208018Sthompsa break; 569208018Sthompsa } 570208018Sthompsa if (dbg.ds_delay > 0) { 571208018Sthompsa usb_pause_mtx( 572208018Sthompsa xfer->xroot->xfer_mtx, 573208018Sthompsa USB_MS_TO_TICKS(dbg.ds_delay)); 574208018Sthompsa /* make sure we don't time out */ 575208018Sthompsa start_ticks = ticks; 576208018Sthompsa } 577208018Sthompsa } 578208018Sthompsa } 579208018Sthompsa#endif 580194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, temp); 581184610Salfred 582184610Salfred if (temp > 0) { 583184610Salfred if (!(req->bmRequestType & UT_READ)) { 584190180Sthompsa#if USB_HAVE_USER_IO 585184610Salfred if (flags & USB_USER_DATA_PTR) { 586184824Sthompsa USB_XFER_UNLOCK(xfer); 587194228Sthompsa err = usbd_copy_in_user(xfer->frbuffers + 1, 588184610Salfred 0, data, temp); 589184824Sthompsa USB_XFER_LOCK(xfer); 590184610Salfred if (err) { 591184610Salfred err = USB_ERR_INVAL; 592184610Salfred break; 593184610Salfred } 594190180Sthompsa } else 595190180Sthompsa#endif 596194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 597190180Sthompsa 0, data, temp); 598184610Salfred } 599208018Sthompsa usbd_xfer_set_frames(xfer, 2); 600184610Salfred } else { 601208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) == 0) { 602184610Salfred if (xfer->flags.manual_status) { 603208018Sthompsa#ifdef USB_REQ_DEBUG 604208018Sthompsa if (dbg.ss_fail) { 605208018Sthompsa err = USB_ERR_INVAL; 606208018Sthompsa break; 607184610Salfred } 608208018Sthompsa if (dbg.ss_delay > 0) { 609194228Sthompsa usb_pause_mtx( 610187173Sthompsa xfer->xroot->xfer_mtx, 611208018Sthompsa USB_MS_TO_TICKS(dbg.ss_delay)); 612208018Sthompsa /* make sure we don't time out */ 613208018Sthompsa start_ticks = ticks; 614184610Salfred } 615184610Salfred#endif 616184610Salfred xfer->flags.manual_status = 0; 617184610Salfred } else { 618184610Salfred break; 619184610Salfred } 620184610Salfred } 621208018Sthompsa usbd_xfer_set_frames(xfer, 1); 622184610Salfred } 623184610Salfred 624194228Sthompsa usbd_transfer_start(xfer); 625184610Salfred 626194228Sthompsa while (usbd_transfer_pending(xfer)) { 627207079Sthompsa cv_wait(&udev->ctrlreq_cv, 628188983Sthompsa xfer->xroot->xfer_mtx); 629184610Salfred } 630184610Salfred 631184610Salfred err = xfer->error; 632184610Salfred 633184610Salfred if (err) { 634184610Salfred break; 635184610Salfred } 636184610Salfred 637208018Sthompsa /* get actual length of DATA stage */ 638208018Sthompsa 639208018Sthompsa if (xfer->aframes < 2) { 640208018Sthompsa acttemp = 0; 641184610Salfred } else { 642208018Sthompsa acttemp = usbd_xfer_frame_len(xfer, 1); 643184610Salfred } 644184610Salfred 645184610Salfred /* check for short packet */ 646184610Salfred 647208018Sthompsa if (temp > acttemp) { 648208018Sthompsa temp = acttemp; 649184610Salfred length = temp; 650184610Salfred } 651184610Salfred if (temp > 0) { 652184610Salfred if (req->bmRequestType & UT_READ) { 653190180Sthompsa#if USB_HAVE_USER_IO 654184610Salfred if (flags & USB_USER_DATA_PTR) { 655184824Sthompsa USB_XFER_UNLOCK(xfer); 656194228Sthompsa err = usbd_copy_out_user(xfer->frbuffers + 1, 657184610Salfred 0, data, temp); 658184824Sthompsa USB_XFER_LOCK(xfer); 659184610Salfred if (err) { 660184610Salfred err = USB_ERR_INVAL; 661184610Salfred break; 662184610Salfred } 663190180Sthompsa } else 664190180Sthompsa#endif 665194228Sthompsa usbd_copy_out(xfer->frbuffers + 1, 666184610Salfred 0, data, temp); 667184610Salfred } 668184610Salfred } 669184610Salfred /* 670184610Salfred * Clear "frlengths[0]" so that we don't send the setup 671184610Salfred * packet again: 672184610Salfred */ 673194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, 0); 674184610Salfred 675184610Salfred /* update length and data pointer */ 676184610Salfred length -= temp; 677184610Salfred data = USB_ADD_BYTES(data, temp); 678184610Salfred 679184610Salfred if (actlen) { 680184610Salfred (*actlen) += temp; 681184610Salfred } 682184610Salfred /* check for timeout */ 683184610Salfred 684184610Salfred delta_ticks = ticks - start_ticks; 685184610Salfred if (delta_ticks > max_ticks) { 686184610Salfred if (!err) { 687184610Salfred err = USB_ERR_TIMEOUT; 688184610Salfred } 689184610Salfred } 690184610Salfred if (err) { 691184610Salfred break; 692184610Salfred } 693184610Salfred } 694184610Salfred 695184610Salfred if (err) { 696184610Salfred /* 697184610Salfred * Make sure that the control endpoint is no longer 698184610Salfred * blocked in case of a non-transfer related error: 699184610Salfred */ 700194228Sthompsa usbd_transfer_stop(xfer); 701184610Salfred } 702184824Sthompsa USB_XFER_UNLOCK(xfer); 703184610Salfred 704184610Salfreddone: 705207079Sthompsa sx_xunlock(&udev->ctrl_sx); 706184610Salfred 707208008Sthompsa if (enum_locked) 708208008Sthompsa usbd_sr_lock(udev); 709208008Sthompsa 710208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) 711184610Salfred mtx_lock(mtx); 712208008Sthompsa 713193045Sthompsa return ((usb_error_t)err); 714184610Salfred} 715184610Salfred 716184610Salfred/*------------------------------------------------------------------------* 717194228Sthompsa * usbd_do_request_proc - factored out code 718188411Sthompsa * 719188411Sthompsa * This function is factored out code. It does basically the same like 720194228Sthompsa * usbd_do_request_flags, except it will check the status of the 721188411Sthompsa * passed process argument before doing the USB request. If the 722188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It 723188411Sthompsa * is assumed that the mutex associated with the process is locked 724188411Sthompsa * when calling this function. 725188411Sthompsa *------------------------------------------------------------------------*/ 726193045Sthompsausb_error_t 727194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 728192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 729193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 730188411Sthompsa{ 731193045Sthompsa usb_error_t err; 732188411Sthompsa uint16_t len; 733188411Sthompsa 734188411Sthompsa /* get request data length */ 735188411Sthompsa len = UGETW(req->wLength); 736188411Sthompsa 737188411Sthompsa /* check if the device is being detached */ 738194228Sthompsa if (usb_proc_is_gone(pproc)) { 739188411Sthompsa err = USB_ERR_IOERROR; 740188411Sthompsa goto done; 741188411Sthompsa } 742188411Sthompsa 743188411Sthompsa /* forward the USB request */ 744194228Sthompsa err = usbd_do_request_flags(udev, pproc->up_mtx, 745188411Sthompsa req, data, flags, actlen, timeout); 746188411Sthompsa 747188411Sthompsadone: 748188411Sthompsa /* on failure we zero the data */ 749188411Sthompsa /* on short packet we zero the unused data */ 750188411Sthompsa if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 751188411Sthompsa if (err) 752188411Sthompsa memset(data, 0, len); 753188411Sthompsa else if (actlen && *actlen != len) 754188411Sthompsa memset(((uint8_t *)data) + *actlen, 0, len - *actlen); 755188411Sthompsa } 756188411Sthompsa return (err); 757188411Sthompsa} 758188411Sthompsa 759188411Sthompsa/*------------------------------------------------------------------------* 760194228Sthompsa * usbd_req_reset_port 761184610Salfred * 762214804Shselasky * This function will instruct a USB HUB to perform a reset sequence 763184610Salfred * on the specified port number. 764184610Salfred * 765184610Salfred * Returns: 766184610Salfred * 0: Success. The USB device should now be at address zero. 767184610Salfred * Else: Failure. No USB device is present and the USB port should be 768184610Salfred * disabled. 769184610Salfred *------------------------------------------------------------------------*/ 770193045Sthompsausb_error_t 771194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 772184610Salfred{ 773192984Sthompsa struct usb_port_status ps; 774193045Sthompsa usb_error_t err; 775184610Salfred uint16_t n; 776184610Salfred 777207077Sthompsa#ifdef USB_DEBUG 778184610Salfred uint16_t pr_poll_delay; 779184610Salfred uint16_t pr_recovery_delay; 780184610Salfred 781184610Salfred#endif 782224095Shselasky /* clear any leftover port reset changes first */ 783224095Shselasky usbd_req_clear_port_feature( 784224095Shselasky udev, mtx, port, UHF_C_PORT_RESET); 785224095Shselasky 786224095Shselasky /* assert port reset on the given port */ 787224095Shselasky err = usbd_req_set_port_feature( 788224095Shselasky udev, mtx, port, UHF_PORT_RESET); 789224095Shselasky 790224095Shselasky /* check for errors */ 791224095Shselasky if (err) 792184610Salfred goto done; 793207077Sthompsa#ifdef USB_DEBUG 794184610Salfred /* range check input parameters */ 795194228Sthompsa pr_poll_delay = usb_pr_poll_delay; 796184610Salfred if (pr_poll_delay < 1) { 797184610Salfred pr_poll_delay = 1; 798184610Salfred } else if (pr_poll_delay > 1000) { 799184610Salfred pr_poll_delay = 1000; 800184610Salfred } 801194228Sthompsa pr_recovery_delay = usb_pr_recovery_delay; 802184610Salfred if (pr_recovery_delay > 1000) { 803184610Salfred pr_recovery_delay = 1000; 804184610Salfred } 805184610Salfred#endif 806184610Salfred n = 0; 807184610Salfred while (1) { 808224095Shselasky uint16_t status; 809224095Shselasky uint16_t change; 810224095Shselasky 811207077Sthompsa#ifdef USB_DEBUG 812184610Salfred /* wait for the device to recover from reset */ 813194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 814184610Salfred n += pr_poll_delay; 815184610Salfred#else 816184610Salfred /* wait for the device to recover from reset */ 817194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 818184610Salfred n += USB_PORT_RESET_DELAY; 819184610Salfred#endif 820194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 821184610Salfred if (err) { 822184610Salfred goto done; 823184610Salfred } 824224095Shselasky status = UGETW(ps.wPortStatus); 825224095Shselasky change = UGETW(ps.wPortChange); 826224095Shselasky 827216249Shselasky /* if the device disappeared, just give up */ 828224095Shselasky if (!(status & UPS_CURRENT_CONNECT_STATUS)) 829216249Shselasky goto done; 830224095Shselasky 831214804Shselasky /* check if reset is complete */ 832224095Shselasky if (change & UPS_C_PORT_RESET) 833214804Shselasky break; 834224095Shselasky 835224095Shselasky /* 836224095Shselasky * Some Virtual Machines like VirtualBox 4.x fail to 837224095Shselasky * generate a port reset change event. Check if reset 838224095Shselasky * is no longer asserted. 839224095Shselasky */ 840224095Shselasky if (!(status & UPS_RESET)) 841224095Shselasky break; 842224095Shselasky 843214804Shselasky /* check for timeout */ 844214804Shselasky if (n > 1000) { 845214804Shselasky n = 0; 846214804Shselasky break; 847214804Shselasky } 848214804Shselasky } 849214804Shselasky 850214804Shselasky /* clear port reset first */ 851214804Shselasky err = usbd_req_clear_port_feature( 852214804Shselasky udev, mtx, port, UHF_C_PORT_RESET); 853214804Shselasky if (err) { 854214804Shselasky goto done; 855214804Shselasky } 856214804Shselasky /* check for timeout */ 857214804Shselasky if (n == 0) { 858214804Shselasky err = USB_ERR_TIMEOUT; 859214804Shselasky goto done; 860214804Shselasky } 861214804Shselasky#ifdef USB_DEBUG 862214804Shselasky /* wait for the device to recover from reset */ 863214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 864214804Shselasky#else 865214804Shselasky /* wait for the device to recover from reset */ 866214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 867214804Shselasky#endif 868214804Shselasky 869214804Shselaskydone: 870214804Shselasky DPRINTFN(2, "port %d reset returning error=%s\n", 871214804Shselasky port, usbd_errstr(err)); 872214804Shselasky return (err); 873214804Shselasky} 874214804Shselasky 875214804Shselasky/*------------------------------------------------------------------------* 876214804Shselasky * usbd_req_warm_reset_port 877214804Shselasky * 878214804Shselasky * This function will instruct an USB HUB to perform a warm reset 879214804Shselasky * sequence on the specified port number. This kind of reset is not 880214804Shselasky * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted 881214804Shselasky * for SUPER-speed USB HUBs. 882214804Shselasky * 883214804Shselasky * Returns: 884214804Shselasky * 0: Success. The USB device should now be available again. 885214804Shselasky * Else: Failure. No USB device is present and the USB port should be 886214804Shselasky * disabled. 887214804Shselasky *------------------------------------------------------------------------*/ 888214804Shselaskyusb_error_t 889214804Shselaskyusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 890214804Shselasky{ 891214804Shselasky struct usb_port_status ps; 892214804Shselasky usb_error_t err; 893214804Shselasky uint16_t n; 894214804Shselasky 895214804Shselasky#ifdef USB_DEBUG 896214804Shselasky uint16_t pr_poll_delay; 897214804Shselasky uint16_t pr_recovery_delay; 898214804Shselasky 899214804Shselasky#endif 900214804Shselasky err = usbd_req_set_port_feature(udev, mtx, port, UHF_BH_PORT_RESET); 901214804Shselasky if (err) { 902214804Shselasky goto done; 903214804Shselasky } 904214804Shselasky#ifdef USB_DEBUG 905214804Shselasky /* range check input parameters */ 906214804Shselasky pr_poll_delay = usb_pr_poll_delay; 907214804Shselasky if (pr_poll_delay < 1) { 908214804Shselasky pr_poll_delay = 1; 909214804Shselasky } else if (pr_poll_delay > 1000) { 910214804Shselasky pr_poll_delay = 1000; 911214804Shselasky } 912214804Shselasky pr_recovery_delay = usb_pr_recovery_delay; 913214804Shselasky if (pr_recovery_delay > 1000) { 914214804Shselasky pr_recovery_delay = 1000; 915214804Shselasky } 916214804Shselasky#endif 917214804Shselasky n = 0; 918214804Shselasky while (1) { 919214804Shselasky#ifdef USB_DEBUG 920214804Shselasky /* wait for the device to recover from reset */ 921214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 922214804Shselasky n += pr_poll_delay; 923214804Shselasky#else 924214804Shselasky /* wait for the device to recover from reset */ 925214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 926214804Shselasky n += USB_PORT_RESET_DELAY; 927214804Shselasky#endif 928214804Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 929214804Shselasky if (err) { 930214804Shselasky goto done; 931214804Shselasky } 932184610Salfred /* if the device disappeared, just give up */ 933184610Salfred if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) { 934184610Salfred goto done; 935184610Salfred } 936184610Salfred /* check if reset is complete */ 937214804Shselasky if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) { 938184610Salfred break; 939184610Salfred } 940184610Salfred /* check for timeout */ 941184610Salfred if (n > 1000) { 942184610Salfred n = 0; 943184610Salfred break; 944184610Salfred } 945184610Salfred } 946184610Salfred 947184610Salfred /* clear port reset first */ 948194228Sthompsa err = usbd_req_clear_port_feature( 949214804Shselasky udev, mtx, port, UHF_C_BH_PORT_RESET); 950184610Salfred if (err) { 951184610Salfred goto done; 952184610Salfred } 953184610Salfred /* check for timeout */ 954184610Salfred if (n == 0) { 955184610Salfred err = USB_ERR_TIMEOUT; 956184610Salfred goto done; 957184610Salfred } 958207077Sthompsa#ifdef USB_DEBUG 959184610Salfred /* wait for the device to recover from reset */ 960194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 961184610Salfred#else 962184610Salfred /* wait for the device to recover from reset */ 963194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 964184610Salfred#endif 965184610Salfred 966184610Salfreddone: 967214804Shselasky DPRINTFN(2, "port %d warm reset returning error=%s\n", 968194228Sthompsa port, usbd_errstr(err)); 969184610Salfred return (err); 970184610Salfred} 971184610Salfred 972184610Salfred/*------------------------------------------------------------------------* 973194228Sthompsa * usbd_req_get_desc 974184610Salfred * 975184610Salfred * This function can be used to retrieve USB descriptors. It contains 976184610Salfred * some additional logic like zeroing of missing descriptor bytes and 977184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 978184610Salfred * argument specifies the minimum descriptor length. The "max_len" 979184610Salfred * argument specifies the maximum descriptor length. If the real 980184610Salfred * descriptor length is less than the minimum length the missing 981188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 982188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 983188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 984188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 985188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 986188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 987188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 988188985Sthompsa * "max_len" then this function will try to retrive the beginning of 989188985Sthompsa * the descriptor and base the maximum length on the first byte of the 990188985Sthompsa * descriptor. 991184610Salfred * 992184610Salfred * Returns: 993184610Salfred * 0: Success 994184610Salfred * Else: Failure 995184610Salfred *------------------------------------------------------------------------*/ 996193045Sthompsausb_error_t 997194228Sthompsausbd_req_get_desc(struct usb_device *udev, 998188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 999184610Salfred uint16_t min_len, uint16_t max_len, 1000184610Salfred uint16_t id, uint8_t type, uint8_t index, 1001184610Salfred uint8_t retries) 1002184610Salfred{ 1003192984Sthompsa struct usb_device_request req; 1004184610Salfred uint8_t *buf; 1005193045Sthompsa usb_error_t err; 1006184610Salfred 1007184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 1008184610Salfred id, type, index, max_len); 1009184610Salfred 1010184610Salfred req.bmRequestType = UT_READ_DEVICE; 1011184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1012184610Salfred USETW2(req.wValue, type, index); 1013184610Salfred USETW(req.wIndex, id); 1014184610Salfred 1015184610Salfred while (1) { 1016184610Salfred 1017184610Salfred if ((min_len < 2) || (max_len < 2)) { 1018184610Salfred err = USB_ERR_INVAL; 1019184610Salfred goto done; 1020184610Salfred } 1021184610Salfred USETW(req.wLength, min_len); 1022184610Salfred 1023194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 1024186730Salfred desc, 0, NULL, 1000); 1025184610Salfred 1026184610Salfred if (err) { 1027184610Salfred if (!retries) { 1028184610Salfred goto done; 1029184610Salfred } 1030184610Salfred retries--; 1031184610Salfred 1032194228Sthompsa usb_pause_mtx(mtx, hz / 5); 1033184610Salfred 1034184610Salfred continue; 1035184610Salfred } 1036184610Salfred buf = desc; 1037184610Salfred 1038184610Salfred if (min_len == max_len) { 1039184610Salfred 1040188985Sthompsa /* enforce correct length */ 1041188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 1042188985Sthompsa buf[0] = min_len; 1043184610Salfred 1044188985Sthompsa /* enforce correct type */ 1045184610Salfred buf[1] = type; 1046184610Salfred 1047184610Salfred goto done; 1048184610Salfred } 1049184610Salfred /* range check */ 1050184610Salfred 1051184610Salfred if (max_len > buf[0]) { 1052184610Salfred max_len = buf[0]; 1053184610Salfred } 1054184610Salfred /* zero minimum data */ 1055184610Salfred 1056184610Salfred while (min_len > max_len) { 1057184610Salfred min_len--; 1058184610Salfred buf[min_len] = 0; 1059184610Salfred } 1060184610Salfred 1061184610Salfred /* set new minimum length */ 1062184610Salfred 1063184610Salfred min_len = max_len; 1064184610Salfred } 1065184610Salfreddone: 1066188985Sthompsa if (actlen != NULL) { 1067188985Sthompsa if (err) 1068188985Sthompsa *actlen = 0; 1069188985Sthompsa else 1070188985Sthompsa *actlen = min_len; 1071188985Sthompsa } 1072184610Salfred return (err); 1073184610Salfred} 1074184610Salfred 1075184610Salfred/*------------------------------------------------------------------------* 1076194228Sthompsa * usbd_req_get_string_any 1077184610Salfred * 1078184610Salfred * This function will return the string given by "string_index" 1079184610Salfred * using the first language ID. The maximum length "len" includes 1080184610Salfred * the terminating zero. The "len" argument should be twice as 1081184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 1082184610Salfred * 1083184610Salfred * Returns: 1084184610Salfred * 0: Success 1085184610Salfred * Else: Failure 1086184610Salfred *------------------------------------------------------------------------*/ 1087193045Sthompsausb_error_t 1088194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 1089184610Salfred uint16_t len, uint8_t string_index) 1090184610Salfred{ 1091184610Salfred char *s; 1092184610Salfred uint8_t *temp; 1093184610Salfred uint16_t i; 1094184610Salfred uint16_t n; 1095184610Salfred uint16_t c; 1096184610Salfred uint8_t swap; 1097193045Sthompsa usb_error_t err; 1098184610Salfred 1099184610Salfred if (len == 0) { 1100184610Salfred /* should not happen */ 1101184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1102184610Salfred } 1103184610Salfred if (string_index == 0) { 1104184610Salfred /* this is the language table */ 1105185087Salfred buf[0] = 0; 1106184610Salfred return (USB_ERR_INVAL); 1107184610Salfred } 1108184610Salfred if (udev->flags.no_strings) { 1109185087Salfred buf[0] = 0; 1110184610Salfred return (USB_ERR_STALLED); 1111184610Salfred } 1112194228Sthompsa err = usbd_req_get_string_desc 1113184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 1114184610Salfred if (err) { 1115185087Salfred buf[0] = 0; 1116184610Salfred return (err); 1117184610Salfred } 1118184610Salfred temp = (uint8_t *)buf; 1119184610Salfred 1120184610Salfred if (temp[0] < 2) { 1121184610Salfred /* string length is too short */ 1122185087Salfred buf[0] = 0; 1123184610Salfred return (USB_ERR_INVAL); 1124184610Salfred } 1125184610Salfred /* reserve one byte for terminating zero */ 1126184610Salfred len--; 1127184610Salfred 1128184610Salfred /* find maximum length */ 1129184610Salfred s = buf; 1130184610Salfred n = (temp[0] / 2) - 1; 1131184610Salfred if (n > len) { 1132184610Salfred n = len; 1133184610Salfred } 1134184610Salfred /* skip descriptor header */ 1135184610Salfred temp += 2; 1136184610Salfred 1137184610Salfred /* reset swap state */ 1138184610Salfred swap = 3; 1139184610Salfred 1140184610Salfred /* convert and filter */ 1141184610Salfred for (i = 0; (i != n); i++) { 1142184610Salfred c = UGETW(temp + (2 * i)); 1143184610Salfred 1144184610Salfred /* convert from Unicode, handle buggy strings */ 1145184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 1146184610Salfred /* Little Endian, default */ 1147184610Salfred *s = c; 1148184610Salfred swap = 1; 1149184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1150184610Salfred /* Big Endian */ 1151184610Salfred *s = c >> 8; 1152184610Salfred swap = 2; 1153184610Salfred } else { 1154185087Salfred /* silently skip bad character */ 1155185087Salfred continue; 1156184610Salfred } 1157184610Salfred 1158184610Salfred /* 1159213433Shselasky * Filter by default - We only allow alphanumerical 1160213433Shselasky * and a few more to avoid any problems with scripts 1161213433Shselasky * and daemons. 1162184610Salfred */ 1163213433Shselasky if (isalpha(*s) || 1164213433Shselasky isdigit(*s) || 1165213433Shselasky *s == '-' || 1166213433Shselasky *s == '+' || 1167213433Shselasky *s == ' ' || 1168213433Shselasky *s == '.' || 1169213433Shselasky *s == ',') { 1170213433Shselasky /* allowed */ 1171213433Shselasky s++; 1172184610Salfred } 1173213433Shselasky /* silently skip bad character */ 1174184610Salfred } 1175185087Salfred *s = 0; /* zero terminate resulting string */ 1176184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1177184610Salfred} 1178184610Salfred 1179184610Salfred/*------------------------------------------------------------------------* 1180194228Sthompsa * usbd_req_get_string_desc 1181184610Salfred * 1182184610Salfred * If you don't know the language ID, consider using 1183194228Sthompsa * "usbd_req_get_string_any()". 1184184610Salfred * 1185184610Salfred * Returns: 1186184610Salfred * 0: Success 1187184610Salfred * Else: Failure 1188184610Salfred *------------------------------------------------------------------------*/ 1189193045Sthompsausb_error_t 1190194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1191184610Salfred uint16_t max_len, uint16_t lang_id, 1192184610Salfred uint8_t string_index) 1193184610Salfred{ 1194194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1195184610Salfred UDESC_STRING, string_index, 0)); 1196184610Salfred} 1197184610Salfred 1198184610Salfred/*------------------------------------------------------------------------* 1199194228Sthompsa * usbd_req_get_config_desc_ptr 1200190727Sthompsa * 1201190727Sthompsa * This function is used in device side mode to retrieve the pointer 1202190727Sthompsa * to the generated config descriptor. This saves allocating space for 1203190727Sthompsa * an additional config descriptor when setting the configuration. 1204190727Sthompsa * 1205190727Sthompsa * Returns: 1206190727Sthompsa * 0: Success 1207190727Sthompsa * Else: Failure 1208190727Sthompsa *------------------------------------------------------------------------*/ 1209193045Sthompsausb_error_t 1210194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 1211192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 1212190727Sthompsa{ 1213192984Sthompsa struct usb_device_request req; 1214193045Sthompsa usb_handle_req_t *hr_func; 1215191402Sthompsa const void *ptr; 1216190727Sthompsa uint16_t len; 1217193045Sthompsa usb_error_t err; 1218190727Sthompsa 1219190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 1220190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 1221191402Sthompsa USETW(req.wValue, wValue); 1222190727Sthompsa USETW(req.wIndex, 0); 1223190727Sthompsa USETW(req.wLength, 0); 1224190727Sthompsa 1225191402Sthompsa ptr = NULL; 1226191402Sthompsa len = 0; 1227190727Sthompsa 1228194228Sthompsa hr_func = usbd_get_hr_func(udev); 1229191402Sthompsa 1230191402Sthompsa if (hr_func == NULL) 1231191402Sthompsa err = USB_ERR_INVAL; 1232191402Sthompsa else { 1233191402Sthompsa USB_BUS_LOCK(udev->bus); 1234191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 1235191402Sthompsa USB_BUS_UNLOCK(udev->bus); 1236191402Sthompsa } 1237191402Sthompsa 1238191402Sthompsa if (err) 1239191402Sthompsa ptr = NULL; 1240191402Sthompsa else if (ptr == NULL) 1241191402Sthompsa err = USB_ERR_INVAL; 1242191402Sthompsa 1243192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1244191402Sthompsa 1245191402Sthompsa return (err); 1246190727Sthompsa} 1247190727Sthompsa 1248190727Sthompsa/*------------------------------------------------------------------------* 1249194228Sthompsa * usbd_req_get_config_desc 1250184610Salfred * 1251184610Salfred * Returns: 1252184610Salfred * 0: Success 1253184610Salfred * Else: Failure 1254184610Salfred *------------------------------------------------------------------------*/ 1255193045Sthompsausb_error_t 1256194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1257192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 1258184610Salfred{ 1259193045Sthompsa usb_error_t err; 1260184610Salfred 1261184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 1262184610Salfred 1263194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1264184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1265184610Salfred if (err) { 1266184610Salfred goto done; 1267184610Salfred } 1268184610Salfred /* Extra sanity checking */ 1269184610Salfred if (UGETW(d->wTotalLength) < sizeof(*d)) { 1270184610Salfred err = USB_ERR_INVAL; 1271184610Salfred } 1272184610Salfreddone: 1273184610Salfred return (err); 1274184610Salfred} 1275184610Salfred 1276184610Salfred/*------------------------------------------------------------------------* 1277194228Sthompsa * usbd_req_get_config_desc_full 1278184610Salfred * 1279184610Salfred * This function gets the complete USB configuration descriptor and 1280184610Salfred * ensures that "wTotalLength" is correct. 1281184610Salfred * 1282184610Salfred * Returns: 1283184610Salfred * 0: Success 1284184610Salfred * Else: Failure 1285184610Salfred *------------------------------------------------------------------------*/ 1286193045Sthompsausb_error_t 1287194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1288192984Sthompsa struct usb_config_descriptor **ppcd, struct malloc_type *mtype, 1289184610Salfred uint8_t index) 1290184610Salfred{ 1291192984Sthompsa struct usb_config_descriptor cd; 1292192984Sthompsa struct usb_config_descriptor *cdesc; 1293184610Salfred uint16_t len; 1294193045Sthompsa usb_error_t err; 1295184610Salfred 1296184610Salfred DPRINTFN(4, "index=%d\n", index); 1297184610Salfred 1298184610Salfred *ppcd = NULL; 1299184610Salfred 1300194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1301184610Salfred if (err) { 1302184610Salfred return (err); 1303184610Salfred } 1304184610Salfred /* get full descriptor */ 1305184610Salfred len = UGETW(cd.wTotalLength); 1306184610Salfred if (len < sizeof(*cdesc)) { 1307184610Salfred /* corrupt descriptor */ 1308184610Salfred return (USB_ERR_INVAL); 1309184610Salfred } 1310184610Salfred cdesc = malloc(len, mtype, M_WAITOK); 1311184610Salfred if (cdesc == NULL) { 1312184610Salfred return (USB_ERR_NOMEM); 1313184610Salfred } 1314194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1315184610Salfred UDESC_CONFIG, index, 3); 1316184610Salfred if (err) { 1317184610Salfred free(cdesc, mtype); 1318184610Salfred return (err); 1319184610Salfred } 1320184610Salfred /* make sure that the device is not fooling us: */ 1321184610Salfred USETW(cdesc->wTotalLength, len); 1322184610Salfred 1323184610Salfred *ppcd = cdesc; 1324184610Salfred 1325184610Salfred return (0); /* success */ 1326184610Salfred} 1327184610Salfred 1328184610Salfred/*------------------------------------------------------------------------* 1329194228Sthompsa * usbd_req_get_device_desc 1330184610Salfred * 1331184610Salfred * Returns: 1332184610Salfred * 0: Success 1333184610Salfred * Else: Failure 1334184610Salfred *------------------------------------------------------------------------*/ 1335193045Sthompsausb_error_t 1336194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1337192984Sthompsa struct usb_device_descriptor *d) 1338184610Salfred{ 1339184610Salfred DPRINTFN(4, "\n"); 1340194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1341184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1342184610Salfred} 1343184610Salfred 1344184610Salfred/*------------------------------------------------------------------------* 1345194228Sthompsa * usbd_req_get_alt_interface_no 1346184610Salfred * 1347184610Salfred * Returns: 1348184610Salfred * 0: Success 1349184610Salfred * Else: Failure 1350184610Salfred *------------------------------------------------------------------------*/ 1351193045Sthompsausb_error_t 1352194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1353184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 1354184610Salfred{ 1355194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1356192984Sthompsa struct usb_device_request req; 1357184610Salfred 1358195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1359184610Salfred return (USB_ERR_INVAL); 1360195963Salfred 1361184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1362184610Salfred req.bRequest = UR_GET_INTERFACE; 1363184610Salfred USETW(req.wValue, 0); 1364184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1365184610Salfred req.wIndex[1] = 0; 1366184610Salfred USETW(req.wLength, 1); 1367194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1368184610Salfred} 1369184610Salfred 1370184610Salfred/*------------------------------------------------------------------------* 1371194228Sthompsa * usbd_req_set_alt_interface_no 1372184610Salfred * 1373184610Salfred * Returns: 1374184610Salfred * 0: Success 1375184610Salfred * Else: Failure 1376184610Salfred *------------------------------------------------------------------------*/ 1377193045Sthompsausb_error_t 1378194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1379184610Salfred uint8_t iface_index, uint8_t alt_no) 1380184610Salfred{ 1381194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1382192984Sthompsa struct usb_device_request req; 1383184610Salfred 1384195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1385184610Salfred return (USB_ERR_INVAL); 1386195963Salfred 1387184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1388184610Salfred req.bRequest = UR_SET_INTERFACE; 1389184610Salfred req.wValue[0] = alt_no; 1390184610Salfred req.wValue[1] = 0; 1391184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1392184610Salfred req.wIndex[1] = 0; 1393184610Salfred USETW(req.wLength, 0); 1394194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1395184610Salfred} 1396184610Salfred 1397184610Salfred/*------------------------------------------------------------------------* 1398194228Sthompsa * usbd_req_get_device_status 1399184610Salfred * 1400184610Salfred * Returns: 1401184610Salfred * 0: Success 1402184610Salfred * Else: Failure 1403184610Salfred *------------------------------------------------------------------------*/ 1404193045Sthompsausb_error_t 1405194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1406192984Sthompsa struct usb_status *st) 1407184610Salfred{ 1408192984Sthompsa struct usb_device_request req; 1409184610Salfred 1410184610Salfred req.bmRequestType = UT_READ_DEVICE; 1411184610Salfred req.bRequest = UR_GET_STATUS; 1412184610Salfred USETW(req.wValue, 0); 1413184610Salfred USETW(req.wIndex, 0); 1414184610Salfred USETW(req.wLength, sizeof(*st)); 1415194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1416184610Salfred} 1417184610Salfred 1418184610Salfred/*------------------------------------------------------------------------* 1419194228Sthompsa * usbd_req_get_hub_descriptor 1420184610Salfred * 1421184610Salfred * Returns: 1422184610Salfred * 0: Success 1423184610Salfred * Else: Failure 1424184610Salfred *------------------------------------------------------------------------*/ 1425193045Sthompsausb_error_t 1426194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1427192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1428184610Salfred{ 1429192984Sthompsa struct usb_device_request req; 1430184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1431184610Salfred 1432184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1433184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1434184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1435184610Salfred USETW(req.wIndex, 0); 1436184610Salfred USETW(req.wLength, len); 1437194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1438184610Salfred} 1439184610Salfred 1440184610Salfred/*------------------------------------------------------------------------* 1441213435Shselasky * usbd_req_get_ss_hub_descriptor 1442213435Shselasky * 1443213435Shselasky * Returns: 1444213435Shselasky * 0: Success 1445213435Shselasky * Else: Failure 1446213435Shselasky *------------------------------------------------------------------------*/ 1447213435Shselaskyusb_error_t 1448213435Shselaskyusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1449213435Shselasky struct usb_hub_ss_descriptor *hd, uint8_t nports) 1450213435Shselasky{ 1451213435Shselasky struct usb_device_request req; 1452213435Shselasky uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); 1453213435Shselasky 1454213435Shselasky req.bmRequestType = UT_READ_CLASS_DEVICE; 1455213435Shselasky req.bRequest = UR_GET_DESCRIPTOR; 1456213435Shselasky USETW2(req.wValue, UDESC_SS_HUB, 0); 1457213435Shselasky USETW(req.wIndex, 0); 1458213435Shselasky USETW(req.wLength, len); 1459213435Shselasky return (usbd_do_request(udev, mtx, &req, hd)); 1460213435Shselasky} 1461213435Shselasky 1462213435Shselasky/*------------------------------------------------------------------------* 1463194228Sthompsa * usbd_req_get_hub_status 1464184610Salfred * 1465184610Salfred * Returns: 1466184610Salfred * 0: Success 1467184610Salfred * Else: Failure 1468184610Salfred *------------------------------------------------------------------------*/ 1469193045Sthompsausb_error_t 1470194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1471192984Sthompsa struct usb_hub_status *st) 1472184610Salfred{ 1473192984Sthompsa struct usb_device_request req; 1474184610Salfred 1475184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1476184610Salfred req.bRequest = UR_GET_STATUS; 1477184610Salfred USETW(req.wValue, 0); 1478184610Salfred USETW(req.wIndex, 0); 1479192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1480194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1481184610Salfred} 1482184610Salfred 1483184610Salfred/*------------------------------------------------------------------------* 1484194228Sthompsa * usbd_req_set_address 1485184610Salfred * 1486184610Salfred * This function is used to set the address for an USB device. After 1487184610Salfred * port reset the USB device will respond at address zero. 1488184610Salfred * 1489184610Salfred * Returns: 1490184610Salfred * 0: Success 1491184610Salfred * Else: Failure 1492184610Salfred *------------------------------------------------------------------------*/ 1493193045Sthompsausb_error_t 1494194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1495184610Salfred{ 1496192984Sthompsa struct usb_device_request req; 1497213435Shselasky usb_error_t err; 1498184610Salfred 1499184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1500184610Salfred 1501184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1502184610Salfred req.bRequest = UR_SET_ADDRESS; 1503184610Salfred USETW(req.wValue, addr); 1504184610Salfred USETW(req.wIndex, 0); 1505184610Salfred USETW(req.wLength, 0); 1506184610Salfred 1507213435Shselasky err = USB_ERR_INVAL; 1508213435Shselasky 1509213435Shselasky /* check if USB controller handles set address */ 1510213435Shselasky if (udev->bus->methods->set_address != NULL) 1511213435Shselasky err = (udev->bus->methods->set_address) (udev, mtx, addr); 1512213435Shselasky 1513213435Shselasky if (err != USB_ERR_INVAL) 1514213435Shselasky goto done; 1515213435Shselasky 1516184610Salfred /* Setting the address should not take more than 1 second ! */ 1517213435Shselasky err = usbd_do_request_flags(udev, mtx, &req, NULL, 1518213435Shselasky USB_DELAY_STATUS_STAGE, NULL, 1000); 1519213435Shselasky 1520213435Shselaskydone: 1521213435Shselasky /* allow device time to set new address */ 1522213435Shselasky usb_pause_mtx(mtx, 1523213435Shselasky USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); 1524213435Shselasky 1525213435Shselasky return (err); 1526184610Salfred} 1527184610Salfred 1528184610Salfred/*------------------------------------------------------------------------* 1529194228Sthompsa * usbd_req_get_port_status 1530184610Salfred * 1531184610Salfred * Returns: 1532184610Salfred * 0: Success 1533184610Salfred * Else: Failure 1534184610Salfred *------------------------------------------------------------------------*/ 1535193045Sthompsausb_error_t 1536194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1537192984Sthompsa struct usb_port_status *ps, uint8_t port) 1538184610Salfred{ 1539192984Sthompsa struct usb_device_request req; 1540184610Salfred 1541184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1542184610Salfred req.bRequest = UR_GET_STATUS; 1543184610Salfred USETW(req.wValue, 0); 1544184610Salfred req.wIndex[0] = port; 1545184610Salfred req.wIndex[1] = 0; 1546184610Salfred USETW(req.wLength, sizeof *ps); 1547194228Sthompsa return (usbd_do_request(udev, mtx, &req, ps)); 1548184610Salfred} 1549184610Salfred 1550184610Salfred/*------------------------------------------------------------------------* 1551194228Sthompsa * usbd_req_clear_hub_feature 1552184610Salfred * 1553184610Salfred * Returns: 1554184610Salfred * 0: Success 1555184610Salfred * Else: Failure 1556184610Salfred *------------------------------------------------------------------------*/ 1557193045Sthompsausb_error_t 1558194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1559184610Salfred uint16_t sel) 1560184610Salfred{ 1561192984Sthompsa struct usb_device_request req; 1562184610Salfred 1563184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1564184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1565184610Salfred USETW(req.wValue, sel); 1566184610Salfred USETW(req.wIndex, 0); 1567184610Salfred USETW(req.wLength, 0); 1568194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1569184610Salfred} 1570184610Salfred 1571184610Salfred/*------------------------------------------------------------------------* 1572194228Sthompsa * usbd_req_set_hub_feature 1573184610Salfred * 1574184610Salfred * Returns: 1575184610Salfred * 0: Success 1576184610Salfred * Else: Failure 1577184610Salfred *------------------------------------------------------------------------*/ 1578193045Sthompsausb_error_t 1579194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1580184610Salfred uint16_t sel) 1581184610Salfred{ 1582192984Sthompsa struct usb_device_request req; 1583184610Salfred 1584184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1585184610Salfred req.bRequest = UR_SET_FEATURE; 1586184610Salfred USETW(req.wValue, sel); 1587184610Salfred USETW(req.wIndex, 0); 1588184610Salfred USETW(req.wLength, 0); 1589194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1590184610Salfred} 1591184610Salfred 1592184610Salfred/*------------------------------------------------------------------------* 1593213435Shselasky * usbd_req_set_hub_u1_timeout 1594213435Shselasky * 1595213435Shselasky * Returns: 1596213435Shselasky * 0: Success 1597213435Shselasky * Else: Failure 1598213435Shselasky *------------------------------------------------------------------------*/ 1599213435Shselaskyusb_error_t 1600213435Shselaskyusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, 1601213435Shselasky uint8_t port, uint8_t timeout) 1602213435Shselasky{ 1603213435Shselasky struct usb_device_request req; 1604213435Shselasky 1605213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1606213435Shselasky req.bRequest = UR_SET_FEATURE; 1607213435Shselasky USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 1608213435Shselasky req.wIndex[0] = port; 1609213435Shselasky req.wIndex[1] = timeout; 1610213435Shselasky USETW(req.wLength, 0); 1611213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1612213435Shselasky} 1613213435Shselasky 1614213435Shselasky/*------------------------------------------------------------------------* 1615213435Shselasky * usbd_req_set_hub_u2_timeout 1616213435Shselasky * 1617213435Shselasky * Returns: 1618213435Shselasky * 0: Success 1619213435Shselasky * Else: Failure 1620213435Shselasky *------------------------------------------------------------------------*/ 1621213435Shselaskyusb_error_t 1622213435Shselaskyusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, 1623213435Shselasky uint8_t port, uint8_t timeout) 1624213435Shselasky{ 1625213435Shselasky struct usb_device_request req; 1626213435Shselasky 1627213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1628213435Shselasky req.bRequest = UR_SET_FEATURE; 1629213435Shselasky USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 1630213435Shselasky req.wIndex[0] = port; 1631213435Shselasky req.wIndex[1] = timeout; 1632213435Shselasky USETW(req.wLength, 0); 1633213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1634213435Shselasky} 1635213435Shselasky 1636213435Shselasky/*------------------------------------------------------------------------* 1637213435Shselasky * usbd_req_set_hub_depth 1638213435Shselasky * 1639213435Shselasky * Returns: 1640213435Shselasky * 0: Success 1641213435Shselasky * Else: Failure 1642213435Shselasky *------------------------------------------------------------------------*/ 1643213435Shselaskyusb_error_t 1644213435Shselaskyusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, 1645213435Shselasky uint16_t depth) 1646213435Shselasky{ 1647213435Shselasky struct usb_device_request req; 1648213435Shselasky 1649213435Shselasky req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1650213435Shselasky req.bRequest = UR_SET_HUB_DEPTH; 1651213435Shselasky USETW(req.wValue, depth); 1652213435Shselasky USETW(req.wIndex, 0); 1653213435Shselasky USETW(req.wLength, 0); 1654213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1655213435Shselasky} 1656213435Shselasky 1657213435Shselasky/*------------------------------------------------------------------------* 1658194228Sthompsa * usbd_req_clear_port_feature 1659184610Salfred * 1660184610Salfred * Returns: 1661184610Salfred * 0: Success 1662184610Salfred * Else: Failure 1663184610Salfred *------------------------------------------------------------------------*/ 1664193045Sthompsausb_error_t 1665194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1666184610Salfred uint8_t port, uint16_t sel) 1667184610Salfred{ 1668192984Sthompsa struct usb_device_request req; 1669184610Salfred 1670184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1671184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1672184610Salfred USETW(req.wValue, sel); 1673184610Salfred req.wIndex[0] = port; 1674184610Salfred req.wIndex[1] = 0; 1675184610Salfred USETW(req.wLength, 0); 1676194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1677184610Salfred} 1678184610Salfred 1679184610Salfred/*------------------------------------------------------------------------* 1680194228Sthompsa * usbd_req_set_port_feature 1681184610Salfred * 1682184610Salfred * Returns: 1683184610Salfred * 0: Success 1684184610Salfred * Else: Failure 1685184610Salfred *------------------------------------------------------------------------*/ 1686193045Sthompsausb_error_t 1687194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1688184610Salfred uint8_t port, uint16_t sel) 1689184610Salfred{ 1690192984Sthompsa struct usb_device_request req; 1691184610Salfred 1692184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1693184610Salfred req.bRequest = UR_SET_FEATURE; 1694184610Salfred USETW(req.wValue, sel); 1695184610Salfred req.wIndex[0] = port; 1696184610Salfred req.wIndex[1] = 0; 1697184610Salfred USETW(req.wLength, 0); 1698194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1699184610Salfred} 1700184610Salfred 1701184610Salfred/*------------------------------------------------------------------------* 1702194228Sthompsa * usbd_req_set_protocol 1703184610Salfred * 1704184610Salfred * Returns: 1705184610Salfred * 0: Success 1706184610Salfred * Else: Failure 1707184610Salfred *------------------------------------------------------------------------*/ 1708193045Sthompsausb_error_t 1709194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1710184610Salfred uint8_t iface_index, uint16_t report) 1711184610Salfred{ 1712194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1713192984Sthompsa struct usb_device_request req; 1714184610Salfred 1715184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1716184610Salfred return (USB_ERR_INVAL); 1717184610Salfred } 1718184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1719184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1720184610Salfred 1721184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1722184610Salfred req.bRequest = UR_SET_PROTOCOL; 1723184610Salfred USETW(req.wValue, report); 1724184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1725184610Salfred req.wIndex[1] = 0; 1726184610Salfred USETW(req.wLength, 0); 1727194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1728184610Salfred} 1729184610Salfred 1730184610Salfred/*------------------------------------------------------------------------* 1731194228Sthompsa * usbd_req_set_report 1732184610Salfred * 1733184610Salfred * Returns: 1734184610Salfred * 0: Success 1735184610Salfred * Else: Failure 1736184610Salfred *------------------------------------------------------------------------*/ 1737193045Sthompsausb_error_t 1738194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1739184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 1740184610Salfred{ 1741194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1742192984Sthompsa struct usb_device_request req; 1743184610Salfred 1744184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1745184610Salfred return (USB_ERR_INVAL); 1746184610Salfred } 1747184610Salfred DPRINTFN(5, "len=%d\n", len); 1748184610Salfred 1749184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1750184610Salfred req.bRequest = UR_SET_REPORT; 1751184610Salfred USETW2(req.wValue, type, id); 1752184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1753184610Salfred req.wIndex[1] = 0; 1754184610Salfred USETW(req.wLength, len); 1755194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1756184610Salfred} 1757184610Salfred 1758184610Salfred/*------------------------------------------------------------------------* 1759194228Sthompsa * usbd_req_get_report 1760184610Salfred * 1761184610Salfred * Returns: 1762184610Salfred * 0: Success 1763184610Salfred * Else: Failure 1764184610Salfred *------------------------------------------------------------------------*/ 1765193045Sthompsausb_error_t 1766194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1767184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1768184610Salfred{ 1769194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1770192984Sthompsa struct usb_device_request req; 1771184610Salfred 1772184610Salfred if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) { 1773184610Salfred return (USB_ERR_INVAL); 1774184610Salfred } 1775184610Salfred DPRINTFN(5, "len=%d\n", len); 1776184610Salfred 1777184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1778184610Salfred req.bRequest = UR_GET_REPORT; 1779184610Salfred USETW2(req.wValue, type, id); 1780184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1781184610Salfred req.wIndex[1] = 0; 1782184610Salfred USETW(req.wLength, len); 1783194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1784184610Salfred} 1785184610Salfred 1786184610Salfred/*------------------------------------------------------------------------* 1787194228Sthompsa * usbd_req_set_idle 1788184610Salfred * 1789184610Salfred * Returns: 1790184610Salfred * 0: Success 1791184610Salfred * Else: Failure 1792184610Salfred *------------------------------------------------------------------------*/ 1793193045Sthompsausb_error_t 1794194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1795184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1796184610Salfred{ 1797194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1798192984Sthompsa struct usb_device_request req; 1799184610Salfred 1800184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1801184610Salfred return (USB_ERR_INVAL); 1802184610Salfred } 1803184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1804184610Salfred 1805184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1806184610Salfred req.bRequest = UR_SET_IDLE; 1807184610Salfred USETW2(req.wValue, duration, id); 1808184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1809184610Salfred req.wIndex[1] = 0; 1810184610Salfred USETW(req.wLength, 0); 1811194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1812184610Salfred} 1813184610Salfred 1814184610Salfred/*------------------------------------------------------------------------* 1815194228Sthompsa * usbd_req_get_report_descriptor 1816184610Salfred * 1817184610Salfred * Returns: 1818184610Salfred * 0: Success 1819184610Salfred * Else: Failure 1820184610Salfred *------------------------------------------------------------------------*/ 1821193045Sthompsausb_error_t 1822194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1823184610Salfred void *d, uint16_t size, uint8_t iface_index) 1824184610Salfred{ 1825194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1826192984Sthompsa struct usb_device_request req; 1827184610Salfred 1828184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1829184610Salfred return (USB_ERR_INVAL); 1830184610Salfred } 1831184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1832184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1833184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1834184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1835184610Salfred req.wIndex[1] = 0; 1836184610Salfred USETW(req.wLength, size); 1837194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1838184610Salfred} 1839184610Salfred 1840184610Salfred/*------------------------------------------------------------------------* 1841194228Sthompsa * usbd_req_set_config 1842184610Salfred * 1843184610Salfred * This function is used to select the current configuration number in 1844184610Salfred * both USB device side mode and USB host side mode. When setting the 1845184610Salfred * configuration the function of the interfaces can change. 1846184610Salfred * 1847184610Salfred * Returns: 1848184610Salfred * 0: Success 1849184610Salfred * Else: Failure 1850184610Salfred *------------------------------------------------------------------------*/ 1851193045Sthompsausb_error_t 1852194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1853184610Salfred{ 1854192984Sthompsa struct usb_device_request req; 1855184610Salfred 1856184610Salfred DPRINTF("setting config %d\n", conf); 1857184610Salfred 1858184610Salfred /* do "set configuration" request */ 1859184610Salfred 1860184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1861184610Salfred req.bRequest = UR_SET_CONFIG; 1862184610Salfred req.wValue[0] = conf; 1863184610Salfred req.wValue[1] = 0; 1864184610Salfred USETW(req.wIndex, 0); 1865184610Salfred USETW(req.wLength, 0); 1866194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1867184610Salfred} 1868184610Salfred 1869184610Salfred/*------------------------------------------------------------------------* 1870194228Sthompsa * usbd_req_get_config 1871184610Salfred * 1872184610Salfred * Returns: 1873184610Salfred * 0: Success 1874184610Salfred * Else: Failure 1875184610Salfred *------------------------------------------------------------------------*/ 1876193045Sthompsausb_error_t 1877194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1878184610Salfred{ 1879192984Sthompsa struct usb_device_request req; 1880184610Salfred 1881184610Salfred req.bmRequestType = UT_READ_DEVICE; 1882184610Salfred req.bRequest = UR_GET_CONFIG; 1883184610Salfred USETW(req.wValue, 0); 1884184610Salfred USETW(req.wIndex, 0); 1885184610Salfred USETW(req.wLength, 1); 1886194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1887184610Salfred} 1888184610Salfred 1889184610Salfred/*------------------------------------------------------------------------* 1890213435Shselasky * usbd_setup_device_desc 1891213435Shselasky *------------------------------------------------------------------------*/ 1892213435Shselaskyusb_error_t 1893213435Shselaskyusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) 1894213435Shselasky{ 1895213435Shselasky usb_error_t err; 1896213435Shselasky 1897213435Shselasky /* 1898213435Shselasky * Get the first 8 bytes of the device descriptor ! 1899213435Shselasky * 1900213435Shselasky * NOTE: "usbd_do_request()" will check the device descriptor 1901213435Shselasky * next time we do a request to see if the maximum packet size 1902213435Shselasky * changed! The 8 first bytes of the device descriptor 1903213435Shselasky * contains the maximum packet size to use on control endpoint 1904213435Shselasky * 0. If this value is different from "USB_MAX_IPACKET" a new 1905213435Shselasky * USB control request will be setup! 1906213435Shselasky */ 1907213435Shselasky switch (udev->speed) { 1908213435Shselasky case USB_SPEED_FULL: 1909213435Shselasky case USB_SPEED_LOW: 1910213435Shselasky err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1911213435Shselasky USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1912213435Shselasky if (err != 0) { 1913213435Shselasky DPRINTFN(0, "getting device descriptor " 1914213435Shselasky "at addr %d failed, %s\n", udev->address, 1915213435Shselasky usbd_errstr(err)); 1916213435Shselasky return (err); 1917213435Shselasky } 1918213435Shselasky break; 1919213435Shselasky default: 1920213435Shselasky DPRINTF("Minimum MaxPacketSize is large enough " 1921213435Shselasky "to hold the complete device descriptor\n"); 1922213435Shselasky break; 1923213435Shselasky } 1924213435Shselasky 1925213435Shselasky /* get the full device descriptor */ 1926213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1927213435Shselasky 1928213435Shselasky /* try one more time, if error */ 1929213435Shselasky if (err) 1930213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1931213435Shselasky 1932213435Shselasky if (err) { 1933213435Shselasky DPRINTF("addr=%d, getting full desc failed\n", 1934213435Shselasky udev->address); 1935213435Shselasky return (err); 1936213435Shselasky } 1937213435Shselasky 1938213435Shselasky DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " 1939213435Shselasky "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", 1940213435Shselasky udev->address, UGETW(udev->ddesc.bcdUSB), 1941213435Shselasky udev->ddesc.bDeviceClass, 1942213435Shselasky udev->ddesc.bDeviceSubClass, 1943213435Shselasky udev->ddesc.bDeviceProtocol, 1944213435Shselasky udev->ddesc.bMaxPacketSize, 1945213435Shselasky udev->ddesc.bLength, 1946213435Shselasky udev->speed); 1947213435Shselasky 1948213435Shselasky return (err); 1949213435Shselasky} 1950213435Shselasky 1951213435Shselasky/*------------------------------------------------------------------------* 1952194228Sthompsa * usbd_req_re_enumerate 1953184610Salfred * 1954185087Salfred * NOTE: After this function returns the hardware is in the 1955185087Salfred * unconfigured state! The application is responsible for setting a 1956185087Salfred * new configuration. 1957185087Salfred * 1958184610Salfred * Returns: 1959184610Salfred * 0: Success 1960184610Salfred * Else: Failure 1961184610Salfred *------------------------------------------------------------------------*/ 1962193045Sthompsausb_error_t 1963194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 1964184610Salfred{ 1965192984Sthompsa struct usb_device *parent_hub; 1966193045Sthompsa usb_error_t err; 1967184610Salfred uint8_t old_addr; 1968186730Salfred uint8_t do_retry = 1; 1969184610Salfred 1970192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 1971185290Salfred return (USB_ERR_INVAL); 1972185290Salfred } 1973184610Salfred old_addr = udev->address; 1974184610Salfred parent_hub = udev->parent_hub; 1975184610Salfred if (parent_hub == NULL) { 1976185290Salfred return (USB_ERR_INVAL); 1977184610Salfred } 1978186730Salfredretry: 1979222786Shselasky /* 1980222786Shselasky * Try to reset the High Speed parent HUB of a LOW- or FULL- 1981222786Shselasky * speed device, if any. 1982222786Shselasky */ 1983222786Shselasky if (udev->parent_hs_hub != NULL && 1984222786Shselasky udev->speed != USB_SPEED_HIGH) { 1985222786Shselasky DPRINTF("Trying to reset parent High Speed TT.\n"); 1986222786Shselasky err = usbd_req_reset_tt(udev->parent_hs_hub, NULL, 1987222786Shselasky udev->hs_port_no); 1988222786Shselasky if (err) { 1989222786Shselasky DPRINTF("Resetting parent High " 1990222786Shselasky "Speed TT failed (%s).\n", 1991222786Shselasky usbd_errstr(err)); 1992222786Shselasky } 1993222786Shselasky } 1994222786Shselasky 1995222786Shselasky /* Try to reset the parent HUB port. */ 1996194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 1997184610Salfred if (err) { 1998190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 1999194228Sthompsa old_addr, usbd_errstr(err)); 2000184610Salfred goto done; 2001184610Salfred } 2002213435Shselasky 2003184610Salfred /* 2004184610Salfred * After that the port has been reset our device should be at 2005184610Salfred * address zero: 2006184610Salfred */ 2007184610Salfred udev->address = USB_START_ADDR; 2008184610Salfred 2009185290Salfred /* reset "bMaxPacketSize" */ 2010185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 2011185290Salfred 2012213435Shselasky /* reset USB state */ 2013213435Shselasky usb_set_device_state(udev, USB_STATE_POWERED); 2014213435Shselasky 2015184610Salfred /* 2016184610Salfred * Restore device address: 2017184610Salfred */ 2018194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 2019184610Salfred if (err) { 2020184610Salfred /* XXX ignore any errors! */ 2021190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 2022194228Sthompsa old_addr, usbd_errstr(err)); 2023184610Salfred } 2024213435Shselasky /* 2025213435Shselasky * Restore device address, if the controller driver did not 2026213435Shselasky * set a new one: 2027213435Shselasky */ 2028213435Shselasky if (udev->address == USB_START_ADDR) 2029213435Shselasky udev->address = old_addr; 2030184610Salfred 2031213435Shselasky /* setup the device descriptor and the initial "wMaxPacketSize" */ 2032213435Shselasky err = usbd_setup_device_desc(udev, mtx); 2033184610Salfred 2034184610Salfreddone: 2035186730Salfred if (err && do_retry) { 2036186730Salfred /* give the USB firmware some time to load */ 2037194228Sthompsa usb_pause_mtx(mtx, hz / 2); 2038186730Salfred /* no more retries after this retry */ 2039186730Salfred do_retry = 0; 2040186730Salfred /* try again */ 2041186730Salfred goto retry; 2042186730Salfred } 2043184610Salfred /* restore address */ 2044213435Shselasky if (udev->address == USB_START_ADDR) 2045213435Shselasky udev->address = old_addr; 2046213435Shselasky /* update state, if successful */ 2047213435Shselasky if (err == 0) 2048213435Shselasky usb_set_device_state(udev, USB_STATE_ADDRESSED); 2049184610Salfred return (err); 2050184610Salfred} 2051186730Salfred 2052186730Salfred/*------------------------------------------------------------------------* 2053194228Sthompsa * usbd_req_clear_device_feature 2054186730Salfred * 2055186730Salfred * Returns: 2056186730Salfred * 0: Success 2057186730Salfred * Else: Failure 2058186730Salfred *------------------------------------------------------------------------*/ 2059193045Sthompsausb_error_t 2060194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 2061186730Salfred uint16_t sel) 2062186730Salfred{ 2063192984Sthompsa struct usb_device_request req; 2064186730Salfred 2065186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2066186730Salfred req.bRequest = UR_CLEAR_FEATURE; 2067186730Salfred USETW(req.wValue, sel); 2068186730Salfred USETW(req.wIndex, 0); 2069186730Salfred USETW(req.wLength, 0); 2070194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2071186730Salfred} 2072186730Salfred 2073186730Salfred/*------------------------------------------------------------------------* 2074194228Sthompsa * usbd_req_set_device_feature 2075186730Salfred * 2076186730Salfred * Returns: 2077186730Salfred * 0: Success 2078186730Salfred * Else: Failure 2079186730Salfred *------------------------------------------------------------------------*/ 2080193045Sthompsausb_error_t 2081194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 2082186730Salfred uint16_t sel) 2083186730Salfred{ 2084192984Sthompsa struct usb_device_request req; 2085186730Salfred 2086186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2087186730Salfred req.bRequest = UR_SET_FEATURE; 2088186730Salfred USETW(req.wValue, sel); 2089186730Salfred USETW(req.wIndex, 0); 2090186730Salfred USETW(req.wLength, 0); 2091194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2092186730Salfred} 2093222786Shselasky 2094222786Shselasky/*------------------------------------------------------------------------* 2095222786Shselasky * usbd_req_reset_tt 2096222786Shselasky * 2097222786Shselasky * Returns: 2098222786Shselasky * 0: Success 2099222786Shselasky * Else: Failure 2100222786Shselasky *------------------------------------------------------------------------*/ 2101222786Shselaskyusb_error_t 2102222786Shselaskyusbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx, 2103222786Shselasky uint8_t port) 2104222786Shselasky{ 2105222786Shselasky struct usb_device_request req; 2106222786Shselasky 2107222786Shselasky /* For single TT HUBs the port should be 1 */ 2108222786Shselasky 2109222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2110222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2111222786Shselasky port = 1; 2112222786Shselasky 2113222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2114222786Shselasky req.bRequest = UR_RESET_TT; 2115222786Shselasky USETW(req.wValue, 0); 2116222786Shselasky req.wIndex[0] = port; 2117222786Shselasky req.wIndex[1] = 0; 2118222786Shselasky USETW(req.wLength, 0); 2119222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2120222786Shselasky} 2121222786Shselasky 2122222786Shselasky/*------------------------------------------------------------------------* 2123222786Shselasky * usbd_req_clear_tt_buffer 2124222786Shselasky * 2125222786Shselasky * For single TT HUBs the port should be 1. 2126222786Shselasky * 2127222786Shselasky * Returns: 2128222786Shselasky * 0: Success 2129222786Shselasky * Else: Failure 2130222786Shselasky *------------------------------------------------------------------------*/ 2131222786Shselaskyusb_error_t 2132222786Shselaskyusbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, 2133222786Shselasky uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint) 2134222786Shselasky{ 2135222786Shselasky struct usb_device_request req; 2136222786Shselasky uint16_t wValue; 2137222786Shselasky 2138222786Shselasky /* For single TT HUBs the port should be 1 */ 2139222786Shselasky 2140222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2141222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2142222786Shselasky port = 1; 2143222786Shselasky 2144222786Shselasky wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) | 2145222786Shselasky ((endpoint & 0x80) << 8) | ((type & 3) << 12); 2146222786Shselasky 2147222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2148222786Shselasky req.bRequest = UR_CLEAR_TT_BUFFER; 2149222786Shselasky USETW(req.wValue, wValue); 2150222786Shselasky req.wIndex[0] = port; 2151222786Shselasky req.wIndex[1] = 0; 2152222786Shselasky USETW(req.wLength, 0); 2153222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2154222786Shselasky} 2155