usb_request.c revision 246759
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 246759 2013-02-13 12:35:17Z hselasky $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 4184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 5184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27190754Sthompsa */ 28184610Salfred 29246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 30246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 31246122Shselasky#else 32194677Sthompsa#include <sys/stdint.h> 33194677Sthompsa#include <sys/stddef.h> 34194677Sthompsa#include <sys/param.h> 35194677Sthompsa#include <sys/queue.h> 36194677Sthompsa#include <sys/types.h> 37194677Sthompsa#include <sys/systm.h> 38194677Sthompsa#include <sys/kernel.h> 39194677Sthompsa#include <sys/bus.h> 40194677Sthompsa#include <sys/module.h> 41194677Sthompsa#include <sys/lock.h> 42194677Sthompsa#include <sys/mutex.h> 43194677Sthompsa#include <sys/condvar.h> 44194677Sthompsa#include <sys/sysctl.h> 45194677Sthompsa#include <sys/sx.h> 46194677Sthompsa#include <sys/unistd.h> 47194677Sthompsa#include <sys/callout.h> 48194677Sthompsa#include <sys/malloc.h> 49194677Sthompsa#include <sys/priv.h> 50194677Sthompsa 51188942Sthompsa#include <dev/usb/usb.h> 52194677Sthompsa#include <dev/usb/usbdi.h> 53194677Sthompsa#include <dev/usb/usbdi_util.h> 54188942Sthompsa#include <dev/usb/usb_ioctl.h> 55188942Sthompsa#include <dev/usb/usbhid.h> 56184610Salfred 57194228Sthompsa#define USB_DEBUG_VAR usb_debug 58184610Salfred 59188942Sthompsa#include <dev/usb/usb_core.h> 60188942Sthompsa#include <dev/usb/usb_busdma.h> 61188942Sthompsa#include <dev/usb/usb_request.h> 62188942Sthompsa#include <dev/usb/usb_process.h> 63188942Sthompsa#include <dev/usb/usb_transfer.h> 64188942Sthompsa#include <dev/usb/usb_debug.h> 65188942Sthompsa#include <dev/usb/usb_device.h> 66188942Sthompsa#include <dev/usb/usb_util.h> 67188942Sthompsa#include <dev/usb/usb_dynamic.h> 68184610Salfred 69188942Sthompsa#include <dev/usb/usb_controller.h> 70188942Sthompsa#include <dev/usb/usb_bus.h> 71184610Salfred#include <sys/ctype.h> 72246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 73184610Salfred 74225000Shselaskystatic int usb_no_cs_fail; 75225000Shselasky 76225000ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW, 77225000Shselasky &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set"); 78225000Shselasky 79207077Sthompsa#ifdef USB_DEBUG 80208018Sthompsa#ifdef USB_REQ_DEBUG 81208018Sthompsa/* The following structures are used in connection to fault injection. */ 82208018Sthompsastruct usb_ctrl_debug { 83208018Sthompsa int bus_index; /* target bus */ 84208018Sthompsa int dev_index; /* target address */ 85208018Sthompsa int ds_fail; /* fail data stage */ 86240750Shselasky int ss_fail; /* fail status stage */ 87208018Sthompsa int ds_delay; /* data stage delay in ms */ 88208018Sthompsa int ss_delay; /* status stage delay in ms */ 89208018Sthompsa int bmRequestType_value; 90208018Sthompsa int bRequest_value; 91208018Sthompsa}; 92208018Sthompsa 93208018Sthompsastruct usb_ctrl_debug_bits { 94208018Sthompsa uint16_t ds_delay; 95208018Sthompsa uint16_t ss_delay; 96208018Sthompsa uint8_t ds_fail:1; 97208018Sthompsa uint8_t ss_fail:1; 98208018Sthompsa uint8_t enabled:1; 99208018Sthompsa}; 100208018Sthompsa 101208018Sthompsa/* The default is to disable fault injection. */ 102208018Sthompsa 103208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = { 104208018Sthompsa .bus_index = -1, 105208018Sthompsa .dev_index = -1, 106208018Sthompsa .bmRequestType_value = -1, 107208018Sthompsa .bRequest_value = -1, 108208018Sthompsa}; 109208018Sthompsa 110208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW, 111208018Sthompsa &usb_ctrl_debug.bus_index, 0, "USB controller index to fail"); 112208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW, 113208018Sthompsa &usb_ctrl_debug.dev_index, 0, "USB device address to fail"); 114208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW, 115208018Sthompsa &usb_ctrl_debug.ds_fail, 0, "USB fail data stage"); 116208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW, 117208018Sthompsa &usb_ctrl_debug.ss_fail, 0, "USB fail status stage"); 118208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW, 119208018Sthompsa &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms"); 120208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW, 121208018Sthompsa &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms"); 122208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW, 123208018Sthompsa &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail"); 124208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW, 125208018Sthompsa &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail"); 126208018Sthompsa 127184610Salfred/*------------------------------------------------------------------------* 128208018Sthompsa * usbd_get_debug_bits 129208018Sthompsa * 130208018Sthompsa * This function is only useful in USB host mode. 131208018Sthompsa *------------------------------------------------------------------------*/ 132208018Sthompsastatic void 133208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, 134208018Sthompsa struct usb_ctrl_debug_bits *dbg) 135208018Sthompsa{ 136208018Sthompsa int temp; 137208018Sthompsa 138208018Sthompsa memset(dbg, 0, sizeof(*dbg)); 139208018Sthompsa 140208018Sthompsa /* Compute data stage delay */ 141208018Sthompsa 142208018Sthompsa temp = usb_ctrl_debug.ds_delay; 143208018Sthompsa if (temp < 0) 144208018Sthompsa temp = 0; 145208018Sthompsa else if (temp > (16*1024)) 146208018Sthompsa temp = (16*1024); 147208018Sthompsa 148208018Sthompsa dbg->ds_delay = temp; 149208018Sthompsa 150208018Sthompsa /* Compute status stage delay */ 151208018Sthompsa 152208018Sthompsa temp = usb_ctrl_debug.ss_delay; 153208018Sthompsa if (temp < 0) 154208018Sthompsa temp = 0; 155208018Sthompsa else if (temp > (16*1024)) 156208018Sthompsa temp = (16*1024); 157208018Sthompsa 158208018Sthompsa dbg->ss_delay = temp; 159208018Sthompsa 160208018Sthompsa /* Check if this control request should be failed */ 161208018Sthompsa 162208018Sthompsa if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) 163208018Sthompsa return; 164208018Sthompsa 165208018Sthompsa if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) 166208018Sthompsa return; 167208018Sthompsa 168208018Sthompsa temp = usb_ctrl_debug.bmRequestType_value; 169208018Sthompsa 170208018Sthompsa if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) 171208018Sthompsa return; 172208018Sthompsa 173208018Sthompsa temp = usb_ctrl_debug.bRequest_value; 174208018Sthompsa 175208018Sthompsa if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) 176208018Sthompsa return; 177208018Sthompsa 178208018Sthompsa temp = usb_ctrl_debug.ds_fail; 179208018Sthompsa if (temp) 180208018Sthompsa dbg->ds_fail = 1; 181208018Sthompsa 182208018Sthompsa temp = usb_ctrl_debug.ss_fail; 183208018Sthompsa if (temp) 184208018Sthompsa dbg->ss_fail = 1; 185208018Sthompsa 186208018Sthompsa dbg->enabled = 1; 187208018Sthompsa} 188208018Sthompsa#endif /* USB_REQ_DEBUG */ 189208018Sthompsa#endif /* USB_DEBUG */ 190208018Sthompsa 191208018Sthompsa/*------------------------------------------------------------------------* 192194228Sthompsa * usbd_do_request_callback 193184610Salfred * 194184610Salfred * This function is the USB callback for generic USB Host control 195184610Salfred * transfers. 196184610Salfred *------------------------------------------------------------------------*/ 197184610Salfredvoid 198194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error) 199184610Salfred{ 200184610Salfred ; /* workaround for a bug in "indent" */ 201184610Salfred 202184610Salfred DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 203184610Salfred 204184610Salfred switch (USB_GET_STATE(xfer)) { 205184610Salfred case USB_ST_SETUP: 206194228Sthompsa usbd_transfer_submit(xfer); 207184610Salfred break; 208184610Salfred default: 209207079Sthompsa cv_signal(&xfer->xroot->udev->ctrlreq_cv); 210184610Salfred break; 211184610Salfred } 212184610Salfred} 213184610Salfred 214184610Salfred/*------------------------------------------------------------------------* 215194228Sthompsa * usb_do_clear_stall_callback 216184610Salfred * 217184610Salfred * This function is the USB callback for generic clear stall requests. 218184610Salfred *------------------------------------------------------------------------*/ 219184610Salfredvoid 220194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 221184610Salfred{ 222192984Sthompsa struct usb_device_request req; 223192984Sthompsa struct usb_device *udev; 224193644Sthompsa struct usb_endpoint *ep; 225193644Sthompsa struct usb_endpoint *ep_end; 226193644Sthompsa struct usb_endpoint *ep_first; 227239214Shselasky usb_stream_t x; 228190731Sthompsa uint8_t to; 229184610Salfred 230187173Sthompsa udev = xfer->xroot->udev; 231184610Salfred 232187173Sthompsa USB_BUS_LOCK(udev->bus); 233187173Sthompsa 234193644Sthompsa /* round robin endpoint clear stall */ 235184610Salfred 236193644Sthompsa ep = udev->ep_curr; 237193644Sthompsa ep_end = udev->endpoints + udev->endpoints_max; 238193644Sthompsa ep_first = udev->endpoints; 239193644Sthompsa to = udev->endpoints_max; 240193318Sthompsa 241184610Salfred switch (USB_GET_STATE(xfer)) { 242184610Salfred case USB_ST_TRANSFERRED: 243225000Shselaskytr_transferred: 244222786Shselasky /* reset error counter */ 245222786Shselasky udev->clear_stall_errors = 0; 246222786Shselasky 247193644Sthompsa if (ep == NULL) 248193318Sthompsa goto tr_setup; /* device was unconfigured */ 249193644Sthompsa if (ep->edesc && 250193644Sthompsa ep->is_stalled) { 251193644Sthompsa ep->toggle_next = 0; 252193644Sthompsa ep->is_stalled = 0; 253213435Shselasky /* some hardware needs a callback to clear the data toggle */ 254213435Shselasky usbd_clear_stall_locked(udev, ep); 255239214Shselasky for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 256239214Shselasky /* start the current or next transfer, if any */ 257239214Shselasky usb_command_wrapper(&ep->endpoint_q[x], 258239214Shselasky ep->endpoint_q[x].curr); 259239214Shselasky } 260184610Salfred } 261193644Sthompsa ep++; 262184610Salfred 263184610Salfred case USB_ST_SETUP: 264184610Salfredtr_setup: 265193318Sthompsa if (to == 0) 266193644Sthompsa break; /* no endpoints - nothing to do */ 267193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 268193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 269193644Sthompsa if (ep->edesc && 270193644Sthompsa ep->is_stalled) { 271184610Salfred 272184610Salfred /* setup a clear-stall packet */ 273184610Salfred 274184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 275184610Salfred req.bRequest = UR_CLEAR_FEATURE; 276184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 277193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 278184610Salfred req.wIndex[1] = 0; 279184610Salfred USETW(req.wLength, 0); 280184610Salfred 281184610Salfred /* copy in the transfer */ 282184610Salfred 283194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 284184610Salfred 285184610Salfred /* set length */ 286194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 287184610Salfred xfer->nframes = 1; 288187173Sthompsa USB_BUS_UNLOCK(udev->bus); 289184610Salfred 290194228Sthompsa usbd_transfer_submit(xfer); 291184610Salfred 292187173Sthompsa USB_BUS_LOCK(udev->bus); 293184610Salfred break; 294184610Salfred } 295193644Sthompsa ep++; 296193318Sthompsa to--; 297193318Sthompsa goto tr_setup; 298184610Salfred 299184610Salfred default: 300222786Shselasky if (error == USB_ERR_CANCELLED) 301184610Salfred break; 302222786Shselasky 303222786Shselasky DPRINTF("Clear stall failed.\n"); 304225000Shselasky 305225000Shselasky /* 306225000Shselasky * Some VMs like VirtualBox always return failure on 307225000Shselasky * clear-stall which we sometimes should just ignore. 308225000Shselasky */ 309225000Shselasky if (usb_no_cs_fail) 310225000Shselasky goto tr_transferred; 311222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) 312222786Shselasky goto tr_setup; 313222786Shselasky 314222786Shselasky if (error == USB_ERR_TIMEOUT) { 315222786Shselasky udev->clear_stall_errors = USB_CS_RESET_LIMIT; 316222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 317222786Shselasky usbd_start_re_enumerate(udev); 318222786Shselasky } else { 319222786Shselasky udev->clear_stall_errors++; 320222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) { 321222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 322222786Shselasky usbd_start_re_enumerate(udev); 323222786Shselasky } 324184610Salfred } 325184610Salfred goto tr_setup; 326184610Salfred } 327184610Salfred 328193644Sthompsa /* store current endpoint */ 329193644Sthompsa udev->ep_curr = ep; 330187173Sthompsa USB_BUS_UNLOCK(udev->bus); 331184610Salfred} 332184610Salfred 333193045Sthompsastatic usb_handle_req_t * 334194228Sthompsausbd_get_hr_func(struct usb_device *udev) 335191402Sthompsa{ 336191402Sthompsa /* figure out if there is a Handle Request function */ 337192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 338194228Sthompsa return (usb_temp_get_desc_p); 339191402Sthompsa else if (udev->parent_hub == NULL) 340191402Sthompsa return (udev->bus->methods->roothub_exec); 341191402Sthompsa else 342191402Sthompsa return (NULL); 343191402Sthompsa} 344191402Sthompsa 345184610Salfred/*------------------------------------------------------------------------* 346194228Sthompsa * usbd_do_request_flags and usbd_do_request 347184610Salfred * 348184610Salfred * Description of arguments passed to these functions: 349184610Salfred * 350192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 351184610Salfred * request should be performed. It is possible to call this function 352184610Salfred * in both Host Side mode and Device Side mode. 353184610Salfred * 354184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 355184610Salfred * will get dropped and picked up during the execution of this 356184610Salfred * function, hence this function sometimes needs to sleep. If this 357184610Salfred * argument is NULL it has no effect. 358184610Salfred * 359184610Salfred * "req" - this argument must always be non-NULL and points to an 360184610Salfred * 8-byte structure holding the USB request to be done. The USB 361184610Salfred * request structure has a bit telling the direction of the USB 362184610Salfred * request, if it is a read or a write. 363184610Salfred * 364184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 365184610Salfred * is non-zero this argument must point to a valid kernel buffer which 366184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 367184610Salfred * be NULL. 368184610Salfred * 369184610Salfred * "flags" - here is a list of valid flags: 370184610Salfred * 371184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 372184610Salfred * specified 373184610Salfred * 374184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 375184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 376184610Salfred * sysctl. This flag is mostly useful for debugging. 377184610Salfred * 378184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 379184610Salfred * pointer. 380184610Salfred * 381184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 382184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 383184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 384184610Salfred * used. 385184610Salfred * 386184610Salfred * "timeout" - gives the timeout for the control transfer in 387184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 388184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 389184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 390184610Salfred * does not allow control requests without a timeout. 391184610Salfred * 392246759Shselasky * NOTE: This function is thread safe. All calls to "usbd_do_request_flags" 393246759Shselasky * will be serialized by the use of the USB device enumeration lock. 394184610Salfred * 395184610Salfred * Returns: 396184610Salfred * 0: Success 397184610Salfred * Else: Failure 398184610Salfred *------------------------------------------------------------------------*/ 399193045Sthompsausb_error_t 400194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 401192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 402193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 403184610Salfred{ 404208018Sthompsa#ifdef USB_REQ_DEBUG 405208018Sthompsa struct usb_ctrl_debug_bits dbg; 406208018Sthompsa#endif 407193045Sthompsa usb_handle_req_t *hr_func; 408192984Sthompsa struct usb_xfer *xfer; 409184610Salfred const void *desc; 410184610Salfred int err = 0; 411193045Sthompsa usb_ticks_t start_ticks; 412193045Sthompsa usb_ticks_t delta_ticks; 413193045Sthompsa usb_ticks_t max_ticks; 414184610Salfred uint16_t length; 415184610Salfred uint16_t temp; 416208018Sthompsa uint16_t acttemp; 417246759Shselasky uint8_t do_unlock; 418184610Salfred 419184610Salfred if (timeout < 50) { 420184610Salfred /* timeout is too small */ 421184610Salfred timeout = 50; 422184610Salfred } 423184610Salfred if (timeout > 30000) { 424184610Salfred /* timeout is too big */ 425184610Salfred timeout = 30000; 426184610Salfred } 427184610Salfred length = UGETW(req->wLength); 428184610Salfred 429184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 430184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 431184610Salfred udev, req->bmRequestType, req->bRequest, 432184610Salfred req->wValue[1], req->wValue[0], 433184610Salfred req->wIndex[1], req->wIndex[0], 434184610Salfred req->wLength[1], req->wLength[0]); 435184610Salfred 436191494Sthompsa /* Check if the device is still alive */ 437191494Sthompsa if (udev->state < USB_STATE_POWERED) { 438191494Sthompsa DPRINTF("usb device has gone\n"); 439191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 440191494Sthompsa } 441191494Sthompsa 442184610Salfred /* 443184610Salfred * Set "actlen" to a known value in case the caller does not 444184610Salfred * check the return value: 445184610Salfred */ 446190735Sthompsa if (actlen) 447184610Salfred *actlen = 0; 448190735Sthompsa 449190180Sthompsa#if (USB_HAVE_USER_IO == 0) 450190180Sthompsa if (flags & USB_USER_DATA_PTR) 451190180Sthompsa return (USB_ERR_INVAL); 452190180Sthompsa#endif 453208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) { 454184610Salfred mtx_unlock(mtx); 455208008Sthompsa mtx_assert(mtx, MA_NOTOWNED); 456184610Salfred } 457208008Sthompsa 458184610Salfred /* 459246759Shselasky * Grab the USB device enumeration SX-lock serialization is 460246759Shselasky * achieved when multiple threads are involved: 461208008Sthompsa */ 462246759Shselasky do_unlock = usbd_enum_lock(udev); 463208008Sthompsa 464208008Sthompsa /* 465246759Shselasky * We need to allow suspend and resume at this point, else the 466246759Shselasky * control transfer will timeout if the device is suspended! 467184610Salfred */ 468246759Shselasky usbd_sr_unlock(udev); 469184610Salfred 470194228Sthompsa hr_func = usbd_get_hr_func(udev); 471190735Sthompsa 472191402Sthompsa if (hr_func != NULL) { 473191402Sthompsa DPRINTF("Handle Request function is set\n"); 474190735Sthompsa 475191402Sthompsa desc = NULL; 476191402Sthompsa temp = 0; 477191402Sthompsa 478191402Sthompsa if (!(req->bmRequestType & UT_READ)) { 479190735Sthompsa if (length != 0) { 480191402Sthompsa DPRINTFN(1, "The handle request function " 481191402Sthompsa "does not support writing data!\n"); 482191402Sthompsa err = USB_ERR_INVAL; 483191402Sthompsa goto done; 484190735Sthompsa } 485190735Sthompsa } 486190735Sthompsa 487191402Sthompsa /* The root HUB code needs the BUS lock locked */ 488191402Sthompsa 489190735Sthompsa USB_BUS_LOCK(udev->bus); 490191402Sthompsa err = (hr_func) (udev, req, &desc, &temp); 491190735Sthompsa USB_BUS_UNLOCK(udev->bus); 492190735Sthompsa 493190735Sthompsa if (err) 494190735Sthompsa goto done; 495190735Sthompsa 496191402Sthompsa if (length > temp) { 497190735Sthompsa if (!(flags & USB_SHORT_XFER_OK)) { 498190735Sthompsa err = USB_ERR_SHORT_XFER; 499190735Sthompsa goto done; 500190735Sthompsa } 501191402Sthompsa length = temp; 502190735Sthompsa } 503190735Sthompsa if (actlen) 504190735Sthompsa *actlen = length; 505190735Sthompsa 506190735Sthompsa if (length > 0) { 507190735Sthompsa#if USB_HAVE_USER_IO 508190735Sthompsa if (flags & USB_USER_DATA_PTR) { 509191402Sthompsa if (copyout(desc, data, length)) { 510190735Sthompsa err = USB_ERR_INVAL; 511190735Sthompsa goto done; 512190735Sthompsa } 513190735Sthompsa } else 514190735Sthompsa#endif 515227461Shselasky memcpy(data, desc, length); 516190735Sthompsa } 517191402Sthompsa goto done; /* success */ 518190735Sthompsa } 519190735Sthompsa 520184610Salfred /* 521184610Salfred * Setup a new USB transfer or use the existing one, if any: 522184610Salfred */ 523207080Sthompsa usbd_ctrl_transfer_setup(udev); 524184610Salfred 525207080Sthompsa xfer = udev->ctrl_xfer[0]; 526184610Salfred if (xfer == NULL) { 527184610Salfred /* most likely out of memory */ 528184610Salfred err = USB_ERR_NOMEM; 529184610Salfred goto done; 530184610Salfred } 531208018Sthompsa 532208018Sthompsa#ifdef USB_REQ_DEBUG 533208018Sthompsa /* Get debug bits */ 534208018Sthompsa usbd_get_debug_bits(udev, req, &dbg); 535208018Sthompsa 536208018Sthompsa /* Check for fault injection */ 537208018Sthompsa if (dbg.enabled) 538208018Sthompsa flags |= USB_DELAY_STATUS_STAGE; 539208018Sthompsa#endif 540184824Sthompsa USB_XFER_LOCK(xfer); 541184610Salfred 542190734Sthompsa if (flags & USB_DELAY_STATUS_STAGE) 543184610Salfred xfer->flags.manual_status = 1; 544190734Sthompsa else 545184610Salfred xfer->flags.manual_status = 0; 546184610Salfred 547190734Sthompsa if (flags & USB_SHORT_XFER_OK) 548190734Sthompsa xfer->flags.short_xfer_ok = 1; 549190734Sthompsa else 550190734Sthompsa xfer->flags.short_xfer_ok = 0; 551190734Sthompsa 552184610Salfred xfer->timeout = timeout; 553184610Salfred 554184610Salfred start_ticks = ticks; 555184610Salfred 556184610Salfred max_ticks = USB_MS_TO_TICKS(timeout); 557184610Salfred 558194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 559184610Salfred 560194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); 561184610Salfred 562184610Salfred while (1) { 563184610Salfred temp = length; 564208018Sthompsa if (temp > usbd_xfer_max_len(xfer)) { 565194677Sthompsa temp = usbd_xfer_max_len(xfer); 566184610Salfred } 567208018Sthompsa#ifdef USB_REQ_DEBUG 568208018Sthompsa if (xfer->flags.manual_status) { 569208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) != 0) { 570208018Sthompsa /* Execute data stage separately */ 571208018Sthompsa temp = 0; 572208018Sthompsa } else if (temp > 0) { 573208018Sthompsa if (dbg.ds_fail) { 574208018Sthompsa err = USB_ERR_INVAL; 575208018Sthompsa break; 576208018Sthompsa } 577208018Sthompsa if (dbg.ds_delay > 0) { 578208018Sthompsa usb_pause_mtx( 579208018Sthompsa xfer->xroot->xfer_mtx, 580208018Sthompsa USB_MS_TO_TICKS(dbg.ds_delay)); 581208018Sthompsa /* make sure we don't time out */ 582208018Sthompsa start_ticks = ticks; 583208018Sthompsa } 584208018Sthompsa } 585208018Sthompsa } 586208018Sthompsa#endif 587194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, temp); 588184610Salfred 589184610Salfred if (temp > 0) { 590184610Salfred if (!(req->bmRequestType & UT_READ)) { 591190180Sthompsa#if USB_HAVE_USER_IO 592184610Salfred if (flags & USB_USER_DATA_PTR) { 593184824Sthompsa USB_XFER_UNLOCK(xfer); 594194228Sthompsa err = usbd_copy_in_user(xfer->frbuffers + 1, 595184610Salfred 0, data, temp); 596184824Sthompsa USB_XFER_LOCK(xfer); 597184610Salfred if (err) { 598184610Salfred err = USB_ERR_INVAL; 599184610Salfred break; 600184610Salfred } 601190180Sthompsa } else 602190180Sthompsa#endif 603194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 604190180Sthompsa 0, data, temp); 605184610Salfred } 606208018Sthompsa usbd_xfer_set_frames(xfer, 2); 607184610Salfred } else { 608208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) == 0) { 609184610Salfred if (xfer->flags.manual_status) { 610208018Sthompsa#ifdef USB_REQ_DEBUG 611208018Sthompsa if (dbg.ss_fail) { 612208018Sthompsa err = USB_ERR_INVAL; 613208018Sthompsa break; 614184610Salfred } 615208018Sthompsa if (dbg.ss_delay > 0) { 616194228Sthompsa usb_pause_mtx( 617187173Sthompsa xfer->xroot->xfer_mtx, 618208018Sthompsa USB_MS_TO_TICKS(dbg.ss_delay)); 619208018Sthompsa /* make sure we don't time out */ 620208018Sthompsa start_ticks = ticks; 621184610Salfred } 622184610Salfred#endif 623184610Salfred xfer->flags.manual_status = 0; 624184610Salfred } else { 625184610Salfred break; 626184610Salfred } 627184610Salfred } 628208018Sthompsa usbd_xfer_set_frames(xfer, 1); 629184610Salfred } 630184610Salfred 631194228Sthompsa usbd_transfer_start(xfer); 632184610Salfred 633194228Sthompsa while (usbd_transfer_pending(xfer)) { 634207079Sthompsa cv_wait(&udev->ctrlreq_cv, 635188983Sthompsa xfer->xroot->xfer_mtx); 636184610Salfred } 637184610Salfred 638184610Salfred err = xfer->error; 639184610Salfred 640184610Salfred if (err) { 641184610Salfred break; 642184610Salfred } 643184610Salfred 644208018Sthompsa /* get actual length of DATA stage */ 645208018Sthompsa 646208018Sthompsa if (xfer->aframes < 2) { 647208018Sthompsa acttemp = 0; 648184610Salfred } else { 649208018Sthompsa acttemp = usbd_xfer_frame_len(xfer, 1); 650184610Salfred } 651184610Salfred 652184610Salfred /* check for short packet */ 653184610Salfred 654208018Sthompsa if (temp > acttemp) { 655208018Sthompsa temp = acttemp; 656184610Salfred length = temp; 657184610Salfred } 658184610Salfred if (temp > 0) { 659184610Salfred if (req->bmRequestType & UT_READ) { 660190180Sthompsa#if USB_HAVE_USER_IO 661184610Salfred if (flags & USB_USER_DATA_PTR) { 662184824Sthompsa USB_XFER_UNLOCK(xfer); 663194228Sthompsa err = usbd_copy_out_user(xfer->frbuffers + 1, 664184610Salfred 0, data, temp); 665184824Sthompsa USB_XFER_LOCK(xfer); 666184610Salfred if (err) { 667184610Salfred err = USB_ERR_INVAL; 668184610Salfred break; 669184610Salfred } 670190180Sthompsa } else 671190180Sthompsa#endif 672194228Sthompsa usbd_copy_out(xfer->frbuffers + 1, 673184610Salfred 0, data, temp); 674184610Salfred } 675184610Salfred } 676184610Salfred /* 677184610Salfred * Clear "frlengths[0]" so that we don't send the setup 678184610Salfred * packet again: 679184610Salfred */ 680194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, 0); 681184610Salfred 682184610Salfred /* update length and data pointer */ 683184610Salfred length -= temp; 684184610Salfred data = USB_ADD_BYTES(data, temp); 685184610Salfred 686184610Salfred if (actlen) { 687184610Salfred (*actlen) += temp; 688184610Salfred } 689184610Salfred /* check for timeout */ 690184610Salfred 691184610Salfred delta_ticks = ticks - start_ticks; 692184610Salfred if (delta_ticks > max_ticks) { 693184610Salfred if (!err) { 694184610Salfred err = USB_ERR_TIMEOUT; 695184610Salfred } 696184610Salfred } 697184610Salfred if (err) { 698184610Salfred break; 699184610Salfred } 700184610Salfred } 701184610Salfred 702184610Salfred if (err) { 703184610Salfred /* 704184610Salfred * Make sure that the control endpoint is no longer 705184610Salfred * blocked in case of a non-transfer related error: 706184610Salfred */ 707194228Sthompsa usbd_transfer_stop(xfer); 708184610Salfred } 709184824Sthompsa USB_XFER_UNLOCK(xfer); 710184610Salfred 711184610Salfreddone: 712246759Shselasky usbd_sr_lock(udev); 713184610Salfred 714246759Shselasky if (do_unlock) 715246759Shselasky usbd_enum_unlock(udev); 716208008Sthompsa 717208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) 718184610Salfred mtx_lock(mtx); 719208008Sthompsa 720193045Sthompsa return ((usb_error_t)err); 721184610Salfred} 722184610Salfred 723184610Salfred/*------------------------------------------------------------------------* 724194228Sthompsa * usbd_do_request_proc - factored out code 725188411Sthompsa * 726188411Sthompsa * This function is factored out code. It does basically the same like 727194228Sthompsa * usbd_do_request_flags, except it will check the status of the 728188411Sthompsa * passed process argument before doing the USB request. If the 729188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It 730188411Sthompsa * is assumed that the mutex associated with the process is locked 731188411Sthompsa * when calling this function. 732188411Sthompsa *------------------------------------------------------------------------*/ 733193045Sthompsausb_error_t 734194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 735192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 736193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 737188411Sthompsa{ 738193045Sthompsa usb_error_t err; 739188411Sthompsa uint16_t len; 740188411Sthompsa 741188411Sthompsa /* get request data length */ 742188411Sthompsa len = UGETW(req->wLength); 743188411Sthompsa 744188411Sthompsa /* check if the device is being detached */ 745194228Sthompsa if (usb_proc_is_gone(pproc)) { 746188411Sthompsa err = USB_ERR_IOERROR; 747188411Sthompsa goto done; 748188411Sthompsa } 749188411Sthompsa 750188411Sthompsa /* forward the USB request */ 751194228Sthompsa err = usbd_do_request_flags(udev, pproc->up_mtx, 752188411Sthompsa req, data, flags, actlen, timeout); 753188411Sthompsa 754188411Sthompsadone: 755188411Sthompsa /* on failure we zero the data */ 756188411Sthompsa /* on short packet we zero the unused data */ 757188411Sthompsa if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 758188411Sthompsa if (err) 759188411Sthompsa memset(data, 0, len); 760188411Sthompsa else if (actlen && *actlen != len) 761188411Sthompsa memset(((uint8_t *)data) + *actlen, 0, len - *actlen); 762188411Sthompsa } 763188411Sthompsa return (err); 764188411Sthompsa} 765188411Sthompsa 766188411Sthompsa/*------------------------------------------------------------------------* 767194228Sthompsa * usbd_req_reset_port 768184610Salfred * 769214804Shselasky * This function will instruct a USB HUB to perform a reset sequence 770184610Salfred * on the specified port number. 771184610Salfred * 772184610Salfred * Returns: 773184610Salfred * 0: Success. The USB device should now be at address zero. 774184610Salfred * Else: Failure. No USB device is present and the USB port should be 775184610Salfred * disabled. 776184610Salfred *------------------------------------------------------------------------*/ 777193045Sthompsausb_error_t 778194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 779184610Salfred{ 780192984Sthompsa struct usb_port_status ps; 781193045Sthompsa usb_error_t err; 782184610Salfred uint16_t n; 783230091Shselasky uint16_t status; 784230091Shselasky uint16_t change; 785184610Salfred 786230091Shselasky DPRINTF("\n"); 787230091Shselasky 788224095Shselasky /* clear any leftover port reset changes first */ 789224095Shselasky usbd_req_clear_port_feature( 790224095Shselasky udev, mtx, port, UHF_C_PORT_RESET); 791224095Shselasky 792224095Shselasky /* assert port reset on the given port */ 793224095Shselasky err = usbd_req_set_port_feature( 794224095Shselasky udev, mtx, port, UHF_PORT_RESET); 795224095Shselasky 796224095Shselasky /* check for errors */ 797224095Shselasky if (err) 798184610Salfred goto done; 799184610Salfred n = 0; 800184610Salfred while (1) { 801184610Salfred /* wait for the device to recover from reset */ 802241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay)); 803241987Shselasky n += usb_port_reset_delay; 804194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 805230091Shselasky if (err) 806184610Salfred goto done; 807230091Shselasky 808224095Shselasky status = UGETW(ps.wPortStatus); 809224095Shselasky change = UGETW(ps.wPortChange); 810224095Shselasky 811216249Shselasky /* if the device disappeared, just give up */ 812224095Shselasky if (!(status & UPS_CURRENT_CONNECT_STATUS)) 813216249Shselasky goto done; 814224095Shselasky 815214804Shselasky /* check if reset is complete */ 816224095Shselasky if (change & UPS_C_PORT_RESET) 817214804Shselasky break; 818224095Shselasky 819224095Shselasky /* 820224095Shselasky * Some Virtual Machines like VirtualBox 4.x fail to 821224095Shselasky * generate a port reset change event. Check if reset 822224095Shselasky * is no longer asserted. 823224095Shselasky */ 824224095Shselasky if (!(status & UPS_RESET)) 825224095Shselasky break; 826224095Shselasky 827214804Shselasky /* check for timeout */ 828214804Shselasky if (n > 1000) { 829214804Shselasky n = 0; 830214804Shselasky break; 831214804Shselasky } 832214804Shselasky } 833214804Shselasky 834214804Shselasky /* clear port reset first */ 835214804Shselasky err = usbd_req_clear_port_feature( 836214804Shselasky udev, mtx, port, UHF_C_PORT_RESET); 837230091Shselasky if (err) 838214804Shselasky goto done; 839230091Shselasky 840214804Shselasky /* check for timeout */ 841214804Shselasky if (n == 0) { 842214804Shselasky err = USB_ERR_TIMEOUT; 843214804Shselasky goto done; 844214804Shselasky } 845214804Shselasky /* wait for the device to recover from reset */ 846241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery)); 847214804Shselasky 848214804Shselaskydone: 849214804Shselasky DPRINTFN(2, "port %d reset returning error=%s\n", 850214804Shselasky port, usbd_errstr(err)); 851214804Shselasky return (err); 852214804Shselasky} 853214804Shselasky 854214804Shselasky/*------------------------------------------------------------------------* 855214804Shselasky * usbd_req_warm_reset_port 856214804Shselasky * 857214804Shselasky * This function will instruct an USB HUB to perform a warm reset 858214804Shselasky * sequence on the specified port number. This kind of reset is not 859214804Shselasky * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted 860214804Shselasky * for SUPER-speed USB HUBs. 861214804Shselasky * 862214804Shselasky * Returns: 863214804Shselasky * 0: Success. The USB device should now be available again. 864214804Shselasky * Else: Failure. No USB device is present and the USB port should be 865214804Shselasky * disabled. 866214804Shselasky *------------------------------------------------------------------------*/ 867214804Shselaskyusb_error_t 868230091Shselaskyusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, 869230091Shselasky uint8_t port) 870214804Shselasky{ 871214804Shselasky struct usb_port_status ps; 872214804Shselasky usb_error_t err; 873214804Shselasky uint16_t n; 874230091Shselasky uint16_t status; 875230091Shselasky uint16_t change; 876214804Shselasky 877230091Shselasky DPRINTF("\n"); 878230091Shselasky 879230091Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 880230091Shselasky if (err) 881214804Shselasky goto done; 882230091Shselasky 883230091Shselasky status = UGETW(ps.wPortStatus); 884230091Shselasky 885230091Shselasky switch (UPS_PORT_LINK_STATE_GET(status)) { 886230091Shselasky case UPS_PORT_LS_U3: 887230091Shselasky case UPS_PORT_LS_COMP_MODE: 888230091Shselasky case UPS_PORT_LS_LOOPBACK: 889230091Shselasky case UPS_PORT_LS_SS_INA: 890230091Shselasky break; 891230091Shselasky default: 892230091Shselasky DPRINTF("Wrong state for warm reset\n"); 893230091Shselasky return (0); 894214804Shselasky } 895230091Shselasky 896230091Shselasky /* clear any leftover warm port reset changes first */ 897230091Shselasky usbd_req_clear_port_feature(udev, mtx, 898230091Shselasky port, UHF_C_BH_PORT_RESET); 899230091Shselasky 900230091Shselasky /* set warm port reset */ 901230091Shselasky err = usbd_req_set_port_feature(udev, mtx, 902230091Shselasky port, UHF_BH_PORT_RESET); 903230091Shselasky if (err) 904230091Shselasky goto done; 905230091Shselasky 906214804Shselasky n = 0; 907214804Shselasky while (1) { 908214804Shselasky /* wait for the device to recover from reset */ 909241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay)); 910241987Shselasky n += usb_port_reset_delay; 911214804Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 912230091Shselasky if (err) 913214804Shselasky goto done; 914230091Shselasky 915230091Shselasky status = UGETW(ps.wPortStatus); 916230091Shselasky change = UGETW(ps.wPortChange); 917230091Shselasky 918184610Salfred /* if the device disappeared, just give up */ 919230091Shselasky if (!(status & UPS_CURRENT_CONNECT_STATUS)) 920184610Salfred goto done; 921230091Shselasky 922184610Salfred /* check if reset is complete */ 923230091Shselasky if (change & UPS_C_BH_PORT_RESET) 924184610Salfred break; 925230091Shselasky 926184610Salfred /* check for timeout */ 927184610Salfred if (n > 1000) { 928184610Salfred n = 0; 929184610Salfred break; 930184610Salfred } 931184610Salfred } 932184610Salfred 933184610Salfred /* clear port reset first */ 934194228Sthompsa err = usbd_req_clear_port_feature( 935214804Shselasky udev, mtx, port, UHF_C_BH_PORT_RESET); 936230091Shselasky if (err) 937184610Salfred goto done; 938230091Shselasky 939184610Salfred /* check for timeout */ 940184610Salfred if (n == 0) { 941184610Salfred err = USB_ERR_TIMEOUT; 942184610Salfred goto done; 943184610Salfred } 944184610Salfred /* wait for the device to recover from reset */ 945241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery)); 946184610Salfred 947184610Salfreddone: 948214804Shselasky DPRINTFN(2, "port %d warm reset returning error=%s\n", 949194228Sthompsa port, usbd_errstr(err)); 950184610Salfred return (err); 951184610Salfred} 952184610Salfred 953184610Salfred/*------------------------------------------------------------------------* 954194228Sthompsa * usbd_req_get_desc 955184610Salfred * 956184610Salfred * This function can be used to retrieve USB descriptors. It contains 957184610Salfred * some additional logic like zeroing of missing descriptor bytes and 958184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 959184610Salfred * argument specifies the minimum descriptor length. The "max_len" 960184610Salfred * argument specifies the maximum descriptor length. If the real 961184610Salfred * descriptor length is less than the minimum length the missing 962188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 963188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 964188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 965188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 966188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 967188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 968188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 969188985Sthompsa * "max_len" then this function will try to retrive the beginning of 970188985Sthompsa * the descriptor and base the maximum length on the first byte of the 971188985Sthompsa * descriptor. 972184610Salfred * 973184610Salfred * Returns: 974184610Salfred * 0: Success 975184610Salfred * Else: Failure 976184610Salfred *------------------------------------------------------------------------*/ 977193045Sthompsausb_error_t 978194228Sthompsausbd_req_get_desc(struct usb_device *udev, 979188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 980184610Salfred uint16_t min_len, uint16_t max_len, 981184610Salfred uint16_t id, uint8_t type, uint8_t index, 982184610Salfred uint8_t retries) 983184610Salfred{ 984192984Sthompsa struct usb_device_request req; 985184610Salfred uint8_t *buf; 986193045Sthompsa usb_error_t err; 987184610Salfred 988184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 989184610Salfred id, type, index, max_len); 990184610Salfred 991184610Salfred req.bmRequestType = UT_READ_DEVICE; 992184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 993184610Salfred USETW2(req.wValue, type, index); 994184610Salfred USETW(req.wIndex, id); 995184610Salfred 996184610Salfred while (1) { 997184610Salfred 998184610Salfred if ((min_len < 2) || (max_len < 2)) { 999184610Salfred err = USB_ERR_INVAL; 1000184610Salfred goto done; 1001184610Salfred } 1002184610Salfred USETW(req.wLength, min_len); 1003184610Salfred 1004194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 1005186730Salfred desc, 0, NULL, 1000); 1006184610Salfred 1007184610Salfred if (err) { 1008184610Salfred if (!retries) { 1009184610Salfred goto done; 1010184610Salfred } 1011184610Salfred retries--; 1012184610Salfred 1013194228Sthompsa usb_pause_mtx(mtx, hz / 5); 1014184610Salfred 1015184610Salfred continue; 1016184610Salfred } 1017184610Salfred buf = desc; 1018184610Salfred 1019184610Salfred if (min_len == max_len) { 1020184610Salfred 1021188985Sthompsa /* enforce correct length */ 1022188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 1023188985Sthompsa buf[0] = min_len; 1024184610Salfred 1025188985Sthompsa /* enforce correct type */ 1026184610Salfred buf[1] = type; 1027184610Salfred 1028184610Salfred goto done; 1029184610Salfred } 1030184610Salfred /* range check */ 1031184610Salfred 1032184610Salfred if (max_len > buf[0]) { 1033184610Salfred max_len = buf[0]; 1034184610Salfred } 1035184610Salfred /* zero minimum data */ 1036184610Salfred 1037184610Salfred while (min_len > max_len) { 1038184610Salfred min_len--; 1039184610Salfred buf[min_len] = 0; 1040184610Salfred } 1041184610Salfred 1042184610Salfred /* set new minimum length */ 1043184610Salfred 1044184610Salfred min_len = max_len; 1045184610Salfred } 1046184610Salfreddone: 1047188985Sthompsa if (actlen != NULL) { 1048188985Sthompsa if (err) 1049188985Sthompsa *actlen = 0; 1050188985Sthompsa else 1051188985Sthompsa *actlen = min_len; 1052188985Sthompsa } 1053184610Salfred return (err); 1054184610Salfred} 1055184610Salfred 1056184610Salfred/*------------------------------------------------------------------------* 1057194228Sthompsa * usbd_req_get_string_any 1058184610Salfred * 1059184610Salfred * This function will return the string given by "string_index" 1060184610Salfred * using the first language ID. The maximum length "len" includes 1061184610Salfred * the terminating zero. The "len" argument should be twice as 1062184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 1063184610Salfred * 1064184610Salfred * Returns: 1065184610Salfred * 0: Success 1066184610Salfred * Else: Failure 1067184610Salfred *------------------------------------------------------------------------*/ 1068193045Sthompsausb_error_t 1069194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 1070184610Salfred uint16_t len, uint8_t string_index) 1071184610Salfred{ 1072184610Salfred char *s; 1073184610Salfred uint8_t *temp; 1074184610Salfred uint16_t i; 1075184610Salfred uint16_t n; 1076184610Salfred uint16_t c; 1077184610Salfred uint8_t swap; 1078193045Sthompsa usb_error_t err; 1079184610Salfred 1080184610Salfred if (len == 0) { 1081184610Salfred /* should not happen */ 1082184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1083184610Salfred } 1084184610Salfred if (string_index == 0) { 1085184610Salfred /* this is the language table */ 1086185087Salfred buf[0] = 0; 1087184610Salfred return (USB_ERR_INVAL); 1088184610Salfred } 1089184610Salfred if (udev->flags.no_strings) { 1090185087Salfred buf[0] = 0; 1091184610Salfred return (USB_ERR_STALLED); 1092184610Salfred } 1093194228Sthompsa err = usbd_req_get_string_desc 1094184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 1095184610Salfred if (err) { 1096185087Salfred buf[0] = 0; 1097184610Salfred return (err); 1098184610Salfred } 1099184610Salfred temp = (uint8_t *)buf; 1100184610Salfred 1101184610Salfred if (temp[0] < 2) { 1102184610Salfred /* string length is too short */ 1103185087Salfred buf[0] = 0; 1104184610Salfred return (USB_ERR_INVAL); 1105184610Salfred } 1106184610Salfred /* reserve one byte for terminating zero */ 1107184610Salfred len--; 1108184610Salfred 1109184610Salfred /* find maximum length */ 1110184610Salfred s = buf; 1111184610Salfred n = (temp[0] / 2) - 1; 1112184610Salfred if (n > len) { 1113184610Salfred n = len; 1114184610Salfred } 1115184610Salfred /* skip descriptor header */ 1116184610Salfred temp += 2; 1117184610Salfred 1118184610Salfred /* reset swap state */ 1119184610Salfred swap = 3; 1120184610Salfred 1121184610Salfred /* convert and filter */ 1122184610Salfred for (i = 0; (i != n); i++) { 1123184610Salfred c = UGETW(temp + (2 * i)); 1124184610Salfred 1125184610Salfred /* convert from Unicode, handle buggy strings */ 1126184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 1127184610Salfred /* Little Endian, default */ 1128184610Salfred *s = c; 1129184610Salfred swap = 1; 1130184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1131184610Salfred /* Big Endian */ 1132184610Salfred *s = c >> 8; 1133184610Salfred swap = 2; 1134184610Salfred } else { 1135185087Salfred /* silently skip bad character */ 1136185087Salfred continue; 1137184610Salfred } 1138184610Salfred 1139184610Salfred /* 1140213433Shselasky * Filter by default - We only allow alphanumerical 1141213433Shselasky * and a few more to avoid any problems with scripts 1142213433Shselasky * and daemons. 1143184610Salfred */ 1144213433Shselasky if (isalpha(*s) || 1145213433Shselasky isdigit(*s) || 1146213433Shselasky *s == '-' || 1147213433Shselasky *s == '+' || 1148213433Shselasky *s == ' ' || 1149213433Shselasky *s == '.' || 1150213433Shselasky *s == ',') { 1151213433Shselasky /* allowed */ 1152213433Shselasky s++; 1153184610Salfred } 1154213433Shselasky /* silently skip bad character */ 1155184610Salfred } 1156185087Salfred *s = 0; /* zero terminate resulting string */ 1157184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1158184610Salfred} 1159184610Salfred 1160184610Salfred/*------------------------------------------------------------------------* 1161194228Sthompsa * usbd_req_get_string_desc 1162184610Salfred * 1163184610Salfred * If you don't know the language ID, consider using 1164194228Sthompsa * "usbd_req_get_string_any()". 1165184610Salfred * 1166184610Salfred * Returns: 1167184610Salfred * 0: Success 1168184610Salfred * Else: Failure 1169184610Salfred *------------------------------------------------------------------------*/ 1170193045Sthompsausb_error_t 1171194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1172184610Salfred uint16_t max_len, uint16_t lang_id, 1173184610Salfred uint8_t string_index) 1174184610Salfred{ 1175194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1176184610Salfred UDESC_STRING, string_index, 0)); 1177184610Salfred} 1178184610Salfred 1179184610Salfred/*------------------------------------------------------------------------* 1180194228Sthompsa * usbd_req_get_config_desc_ptr 1181190727Sthompsa * 1182190727Sthompsa * This function is used in device side mode to retrieve the pointer 1183190727Sthompsa * to the generated config descriptor. This saves allocating space for 1184190727Sthompsa * an additional config descriptor when setting the configuration. 1185190727Sthompsa * 1186190727Sthompsa * Returns: 1187190727Sthompsa * 0: Success 1188190727Sthompsa * Else: Failure 1189190727Sthompsa *------------------------------------------------------------------------*/ 1190193045Sthompsausb_error_t 1191194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 1192192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 1193190727Sthompsa{ 1194192984Sthompsa struct usb_device_request req; 1195193045Sthompsa usb_handle_req_t *hr_func; 1196191402Sthompsa const void *ptr; 1197190727Sthompsa uint16_t len; 1198193045Sthompsa usb_error_t err; 1199190727Sthompsa 1200190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 1201190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 1202191402Sthompsa USETW(req.wValue, wValue); 1203190727Sthompsa USETW(req.wIndex, 0); 1204190727Sthompsa USETW(req.wLength, 0); 1205190727Sthompsa 1206191402Sthompsa ptr = NULL; 1207191402Sthompsa len = 0; 1208190727Sthompsa 1209194228Sthompsa hr_func = usbd_get_hr_func(udev); 1210191402Sthompsa 1211191402Sthompsa if (hr_func == NULL) 1212191402Sthompsa err = USB_ERR_INVAL; 1213191402Sthompsa else { 1214191402Sthompsa USB_BUS_LOCK(udev->bus); 1215191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 1216191402Sthompsa USB_BUS_UNLOCK(udev->bus); 1217191402Sthompsa } 1218191402Sthompsa 1219191402Sthompsa if (err) 1220191402Sthompsa ptr = NULL; 1221191402Sthompsa else if (ptr == NULL) 1222191402Sthompsa err = USB_ERR_INVAL; 1223191402Sthompsa 1224192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1225191402Sthompsa 1226191402Sthompsa return (err); 1227190727Sthompsa} 1228190727Sthompsa 1229190727Sthompsa/*------------------------------------------------------------------------* 1230194228Sthompsa * usbd_req_get_config_desc 1231184610Salfred * 1232184610Salfred * Returns: 1233184610Salfred * 0: Success 1234184610Salfred * Else: Failure 1235184610Salfred *------------------------------------------------------------------------*/ 1236193045Sthompsausb_error_t 1237194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1238192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 1239184610Salfred{ 1240193045Sthompsa usb_error_t err; 1241184610Salfred 1242184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 1243184610Salfred 1244194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1245184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1246184610Salfred if (err) { 1247184610Salfred goto done; 1248184610Salfred } 1249184610Salfred /* Extra sanity checking */ 1250233774Shselasky if (UGETW(d->wTotalLength) < (uint16_t)sizeof(*d)) { 1251184610Salfred err = USB_ERR_INVAL; 1252184610Salfred } 1253184610Salfreddone: 1254184610Salfred return (err); 1255184610Salfred} 1256184610Salfred 1257184610Salfred/*------------------------------------------------------------------------* 1258194228Sthompsa * usbd_req_get_config_desc_full 1259184610Salfred * 1260184610Salfred * This function gets the complete USB configuration descriptor and 1261184610Salfred * ensures that "wTotalLength" is correct. 1262184610Salfred * 1263184610Salfred * Returns: 1264184610Salfred * 0: Success 1265184610Salfred * Else: Failure 1266184610Salfred *------------------------------------------------------------------------*/ 1267193045Sthompsausb_error_t 1268194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1269192984Sthompsa struct usb_config_descriptor **ppcd, struct malloc_type *mtype, 1270184610Salfred uint8_t index) 1271184610Salfred{ 1272192984Sthompsa struct usb_config_descriptor cd; 1273192984Sthompsa struct usb_config_descriptor *cdesc; 1274184610Salfred uint16_t len; 1275193045Sthompsa usb_error_t err; 1276184610Salfred 1277184610Salfred DPRINTFN(4, "index=%d\n", index); 1278184610Salfred 1279184610Salfred *ppcd = NULL; 1280184610Salfred 1281194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1282184610Salfred if (err) { 1283184610Salfred return (err); 1284184610Salfred } 1285184610Salfred /* get full descriptor */ 1286184610Salfred len = UGETW(cd.wTotalLength); 1287184610Salfred if (len < sizeof(*cdesc)) { 1288184610Salfred /* corrupt descriptor */ 1289184610Salfred return (USB_ERR_INVAL); 1290184610Salfred } 1291184610Salfred cdesc = malloc(len, mtype, M_WAITOK); 1292184610Salfred if (cdesc == NULL) { 1293184610Salfred return (USB_ERR_NOMEM); 1294184610Salfred } 1295194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1296184610Salfred UDESC_CONFIG, index, 3); 1297184610Salfred if (err) { 1298184610Salfred free(cdesc, mtype); 1299184610Salfred return (err); 1300184610Salfred } 1301184610Salfred /* make sure that the device is not fooling us: */ 1302184610Salfred USETW(cdesc->wTotalLength, len); 1303184610Salfred 1304184610Salfred *ppcd = cdesc; 1305184610Salfred 1306184610Salfred return (0); /* success */ 1307184610Salfred} 1308184610Salfred 1309184610Salfred/*------------------------------------------------------------------------* 1310194228Sthompsa * usbd_req_get_device_desc 1311184610Salfred * 1312184610Salfred * Returns: 1313184610Salfred * 0: Success 1314184610Salfred * Else: Failure 1315184610Salfred *------------------------------------------------------------------------*/ 1316193045Sthompsausb_error_t 1317194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1318192984Sthompsa struct usb_device_descriptor *d) 1319184610Salfred{ 1320184610Salfred DPRINTFN(4, "\n"); 1321194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1322184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1323184610Salfred} 1324184610Salfred 1325184610Salfred/*------------------------------------------------------------------------* 1326194228Sthompsa * usbd_req_get_alt_interface_no 1327184610Salfred * 1328184610Salfred * Returns: 1329184610Salfred * 0: Success 1330184610Salfred * Else: Failure 1331184610Salfred *------------------------------------------------------------------------*/ 1332193045Sthompsausb_error_t 1333194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1334184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 1335184610Salfred{ 1336194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1337192984Sthompsa struct usb_device_request req; 1338184610Salfred 1339195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1340184610Salfred return (USB_ERR_INVAL); 1341195963Salfred 1342184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1343184610Salfred req.bRequest = UR_GET_INTERFACE; 1344184610Salfred USETW(req.wValue, 0); 1345184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1346184610Salfred req.wIndex[1] = 0; 1347184610Salfred USETW(req.wLength, 1); 1348194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1349184610Salfred} 1350184610Salfred 1351184610Salfred/*------------------------------------------------------------------------* 1352194228Sthompsa * usbd_req_set_alt_interface_no 1353184610Salfred * 1354184610Salfred * Returns: 1355184610Salfred * 0: Success 1356184610Salfred * Else: Failure 1357184610Salfred *------------------------------------------------------------------------*/ 1358193045Sthompsausb_error_t 1359194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1360184610Salfred uint8_t iface_index, uint8_t alt_no) 1361184610Salfred{ 1362194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1363192984Sthompsa struct usb_device_request req; 1364184610Salfred 1365195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1366184610Salfred return (USB_ERR_INVAL); 1367195963Salfred 1368184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1369184610Salfred req.bRequest = UR_SET_INTERFACE; 1370184610Salfred req.wValue[0] = alt_no; 1371184610Salfred req.wValue[1] = 0; 1372184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1373184610Salfred req.wIndex[1] = 0; 1374184610Salfred USETW(req.wLength, 0); 1375194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1376184610Salfred} 1377184610Salfred 1378184610Salfred/*------------------------------------------------------------------------* 1379194228Sthompsa * usbd_req_get_device_status 1380184610Salfred * 1381184610Salfred * Returns: 1382184610Salfred * 0: Success 1383184610Salfred * Else: Failure 1384184610Salfred *------------------------------------------------------------------------*/ 1385193045Sthompsausb_error_t 1386194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1387192984Sthompsa struct usb_status *st) 1388184610Salfred{ 1389192984Sthompsa struct usb_device_request req; 1390184610Salfred 1391184610Salfred req.bmRequestType = UT_READ_DEVICE; 1392184610Salfred req.bRequest = UR_GET_STATUS; 1393184610Salfred USETW(req.wValue, 0); 1394184610Salfred USETW(req.wIndex, 0); 1395184610Salfred USETW(req.wLength, sizeof(*st)); 1396194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1397184610Salfred} 1398184610Salfred 1399184610Salfred/*------------------------------------------------------------------------* 1400194228Sthompsa * usbd_req_get_hub_descriptor 1401184610Salfred * 1402184610Salfred * Returns: 1403184610Salfred * 0: Success 1404184610Salfred * Else: Failure 1405184610Salfred *------------------------------------------------------------------------*/ 1406193045Sthompsausb_error_t 1407194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1408192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1409184610Salfred{ 1410192984Sthompsa struct usb_device_request req; 1411184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1412184610Salfred 1413184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1414184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1415184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1416184610Salfred USETW(req.wIndex, 0); 1417184610Salfred USETW(req.wLength, len); 1418194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1419184610Salfred} 1420184610Salfred 1421184610Salfred/*------------------------------------------------------------------------* 1422213435Shselasky * usbd_req_get_ss_hub_descriptor 1423213435Shselasky * 1424213435Shselasky * Returns: 1425213435Shselasky * 0: Success 1426213435Shselasky * Else: Failure 1427213435Shselasky *------------------------------------------------------------------------*/ 1428213435Shselaskyusb_error_t 1429213435Shselaskyusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1430213435Shselasky struct usb_hub_ss_descriptor *hd, uint8_t nports) 1431213435Shselasky{ 1432213435Shselasky struct usb_device_request req; 1433213435Shselasky uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); 1434213435Shselasky 1435213435Shselasky req.bmRequestType = UT_READ_CLASS_DEVICE; 1436213435Shselasky req.bRequest = UR_GET_DESCRIPTOR; 1437213435Shselasky USETW2(req.wValue, UDESC_SS_HUB, 0); 1438213435Shselasky USETW(req.wIndex, 0); 1439213435Shselasky USETW(req.wLength, len); 1440213435Shselasky return (usbd_do_request(udev, mtx, &req, hd)); 1441213435Shselasky} 1442213435Shselasky 1443213435Shselasky/*------------------------------------------------------------------------* 1444194228Sthompsa * usbd_req_get_hub_status 1445184610Salfred * 1446184610Salfred * Returns: 1447184610Salfred * 0: Success 1448184610Salfred * Else: Failure 1449184610Salfred *------------------------------------------------------------------------*/ 1450193045Sthompsausb_error_t 1451194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1452192984Sthompsa struct usb_hub_status *st) 1453184610Salfred{ 1454192984Sthompsa struct usb_device_request req; 1455184610Salfred 1456184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1457184610Salfred req.bRequest = UR_GET_STATUS; 1458184610Salfred USETW(req.wValue, 0); 1459184610Salfred USETW(req.wIndex, 0); 1460192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1461194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1462184610Salfred} 1463184610Salfred 1464184610Salfred/*------------------------------------------------------------------------* 1465194228Sthompsa * usbd_req_set_address 1466184610Salfred * 1467184610Salfred * This function is used to set the address for an USB device. After 1468184610Salfred * port reset the USB device will respond at address zero. 1469184610Salfred * 1470184610Salfred * Returns: 1471184610Salfred * 0: Success 1472184610Salfred * Else: Failure 1473184610Salfred *------------------------------------------------------------------------*/ 1474193045Sthompsausb_error_t 1475194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1476184610Salfred{ 1477192984Sthompsa struct usb_device_request req; 1478213435Shselasky usb_error_t err; 1479184610Salfred 1480184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1481184610Salfred 1482184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1483184610Salfred req.bRequest = UR_SET_ADDRESS; 1484184610Salfred USETW(req.wValue, addr); 1485184610Salfred USETW(req.wIndex, 0); 1486184610Salfred USETW(req.wLength, 0); 1487184610Salfred 1488213435Shselasky err = USB_ERR_INVAL; 1489213435Shselasky 1490213435Shselasky /* check if USB controller handles set address */ 1491213435Shselasky if (udev->bus->methods->set_address != NULL) 1492213435Shselasky err = (udev->bus->methods->set_address) (udev, mtx, addr); 1493213435Shselasky 1494213435Shselasky if (err != USB_ERR_INVAL) 1495213435Shselasky goto done; 1496213435Shselasky 1497184610Salfred /* Setting the address should not take more than 1 second ! */ 1498213435Shselasky err = usbd_do_request_flags(udev, mtx, &req, NULL, 1499213435Shselasky USB_DELAY_STATUS_STAGE, NULL, 1000); 1500213435Shselasky 1501213435Shselaskydone: 1502213435Shselasky /* allow device time to set new address */ 1503213435Shselasky usb_pause_mtx(mtx, 1504241987Shselasky USB_MS_TO_TICKS(usb_set_address_settle)); 1505213435Shselasky 1506213435Shselasky return (err); 1507184610Salfred} 1508184610Salfred 1509184610Salfred/*------------------------------------------------------------------------* 1510194228Sthompsa * usbd_req_get_port_status 1511184610Salfred * 1512184610Salfred * Returns: 1513184610Salfred * 0: Success 1514184610Salfred * Else: Failure 1515184610Salfred *------------------------------------------------------------------------*/ 1516193045Sthompsausb_error_t 1517194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1518192984Sthompsa struct usb_port_status *ps, uint8_t port) 1519184610Salfred{ 1520192984Sthompsa struct usb_device_request req; 1521184610Salfred 1522184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1523184610Salfred req.bRequest = UR_GET_STATUS; 1524184610Salfred USETW(req.wValue, 0); 1525184610Salfred req.wIndex[0] = port; 1526184610Salfred req.wIndex[1] = 0; 1527184610Salfred USETW(req.wLength, sizeof *ps); 1528194228Sthompsa return (usbd_do_request(udev, mtx, &req, ps)); 1529184610Salfred} 1530184610Salfred 1531184610Salfred/*------------------------------------------------------------------------* 1532194228Sthompsa * usbd_req_clear_hub_feature 1533184610Salfred * 1534184610Salfred * Returns: 1535184610Salfred * 0: Success 1536184610Salfred * Else: Failure 1537184610Salfred *------------------------------------------------------------------------*/ 1538193045Sthompsausb_error_t 1539194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1540184610Salfred uint16_t sel) 1541184610Salfred{ 1542192984Sthompsa struct usb_device_request req; 1543184610Salfred 1544184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1545184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1546184610Salfred USETW(req.wValue, sel); 1547184610Salfred USETW(req.wIndex, 0); 1548184610Salfred USETW(req.wLength, 0); 1549194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1550184610Salfred} 1551184610Salfred 1552184610Salfred/*------------------------------------------------------------------------* 1553194228Sthompsa * usbd_req_set_hub_feature 1554184610Salfred * 1555184610Salfred * Returns: 1556184610Salfred * 0: Success 1557184610Salfred * Else: Failure 1558184610Salfred *------------------------------------------------------------------------*/ 1559193045Sthompsausb_error_t 1560194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1561184610Salfred uint16_t sel) 1562184610Salfred{ 1563192984Sthompsa struct usb_device_request req; 1564184610Salfred 1565184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1566184610Salfred req.bRequest = UR_SET_FEATURE; 1567184610Salfred USETW(req.wValue, sel); 1568184610Salfred USETW(req.wIndex, 0); 1569184610Salfred USETW(req.wLength, 0); 1570194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1571184610Salfred} 1572184610Salfred 1573184610Salfred/*------------------------------------------------------------------------* 1574213435Shselasky * usbd_req_set_hub_u1_timeout 1575213435Shselasky * 1576213435Shselasky * Returns: 1577213435Shselasky * 0: Success 1578213435Shselasky * Else: Failure 1579213435Shselasky *------------------------------------------------------------------------*/ 1580213435Shselaskyusb_error_t 1581213435Shselaskyusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, 1582213435Shselasky uint8_t port, uint8_t timeout) 1583213435Shselasky{ 1584213435Shselasky struct usb_device_request req; 1585213435Shselasky 1586213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1587213435Shselasky req.bRequest = UR_SET_FEATURE; 1588213435Shselasky USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 1589213435Shselasky req.wIndex[0] = port; 1590213435Shselasky req.wIndex[1] = timeout; 1591213435Shselasky USETW(req.wLength, 0); 1592213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1593213435Shselasky} 1594213435Shselasky 1595213435Shselasky/*------------------------------------------------------------------------* 1596213435Shselasky * usbd_req_set_hub_u2_timeout 1597213435Shselasky * 1598213435Shselasky * Returns: 1599213435Shselasky * 0: Success 1600213435Shselasky * Else: Failure 1601213435Shselasky *------------------------------------------------------------------------*/ 1602213435Shselaskyusb_error_t 1603213435Shselaskyusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, 1604213435Shselasky uint8_t port, uint8_t timeout) 1605213435Shselasky{ 1606213435Shselasky struct usb_device_request req; 1607213435Shselasky 1608213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1609213435Shselasky req.bRequest = UR_SET_FEATURE; 1610213435Shselasky USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 1611213435Shselasky req.wIndex[0] = port; 1612213435Shselasky req.wIndex[1] = timeout; 1613213435Shselasky USETW(req.wLength, 0); 1614213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1615213435Shselasky} 1616213435Shselasky 1617213435Shselasky/*------------------------------------------------------------------------* 1618213435Shselasky * usbd_req_set_hub_depth 1619213435Shselasky * 1620213435Shselasky * Returns: 1621213435Shselasky * 0: Success 1622213435Shselasky * Else: Failure 1623213435Shselasky *------------------------------------------------------------------------*/ 1624213435Shselaskyusb_error_t 1625213435Shselaskyusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, 1626213435Shselasky uint16_t depth) 1627213435Shselasky{ 1628213435Shselasky struct usb_device_request req; 1629213435Shselasky 1630213435Shselasky req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1631213435Shselasky req.bRequest = UR_SET_HUB_DEPTH; 1632213435Shselasky USETW(req.wValue, depth); 1633213435Shselasky USETW(req.wIndex, 0); 1634213435Shselasky USETW(req.wLength, 0); 1635213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1636213435Shselasky} 1637213435Shselasky 1638213435Shselasky/*------------------------------------------------------------------------* 1639194228Sthompsa * usbd_req_clear_port_feature 1640184610Salfred * 1641184610Salfred * Returns: 1642184610Salfred * 0: Success 1643184610Salfred * Else: Failure 1644184610Salfred *------------------------------------------------------------------------*/ 1645193045Sthompsausb_error_t 1646194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1647184610Salfred uint8_t port, uint16_t sel) 1648184610Salfred{ 1649192984Sthompsa struct usb_device_request req; 1650184610Salfred 1651184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1652184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1653184610Salfred USETW(req.wValue, sel); 1654184610Salfred req.wIndex[0] = port; 1655184610Salfred req.wIndex[1] = 0; 1656184610Salfred USETW(req.wLength, 0); 1657194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1658184610Salfred} 1659184610Salfred 1660184610Salfred/*------------------------------------------------------------------------* 1661194228Sthompsa * usbd_req_set_port_feature 1662184610Salfred * 1663184610Salfred * Returns: 1664184610Salfred * 0: Success 1665184610Salfred * Else: Failure 1666184610Salfred *------------------------------------------------------------------------*/ 1667193045Sthompsausb_error_t 1668194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1669184610Salfred uint8_t port, uint16_t sel) 1670184610Salfred{ 1671192984Sthompsa struct usb_device_request req; 1672184610Salfred 1673184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1674184610Salfred req.bRequest = UR_SET_FEATURE; 1675184610Salfred USETW(req.wValue, sel); 1676184610Salfred req.wIndex[0] = port; 1677184610Salfred req.wIndex[1] = 0; 1678184610Salfred USETW(req.wLength, 0); 1679194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1680184610Salfred} 1681184610Salfred 1682184610Salfred/*------------------------------------------------------------------------* 1683194228Sthompsa * usbd_req_set_protocol 1684184610Salfred * 1685184610Salfred * Returns: 1686184610Salfred * 0: Success 1687184610Salfred * Else: Failure 1688184610Salfred *------------------------------------------------------------------------*/ 1689193045Sthompsausb_error_t 1690194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1691184610Salfred uint8_t iface_index, uint16_t report) 1692184610Salfred{ 1693194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1694192984Sthompsa struct usb_device_request req; 1695184610Salfred 1696184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1697184610Salfred return (USB_ERR_INVAL); 1698184610Salfred } 1699184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1700184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1701184610Salfred 1702184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1703184610Salfred req.bRequest = UR_SET_PROTOCOL; 1704184610Salfred USETW(req.wValue, report); 1705184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1706184610Salfred req.wIndex[1] = 0; 1707184610Salfred USETW(req.wLength, 0); 1708194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1709184610Salfred} 1710184610Salfred 1711184610Salfred/*------------------------------------------------------------------------* 1712194228Sthompsa * usbd_req_set_report 1713184610Salfred * 1714184610Salfred * Returns: 1715184610Salfred * 0: Success 1716184610Salfred * Else: Failure 1717184610Salfred *------------------------------------------------------------------------*/ 1718193045Sthompsausb_error_t 1719194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1720184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 1721184610Salfred{ 1722194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1723192984Sthompsa struct usb_device_request req; 1724184610Salfred 1725184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1726184610Salfred return (USB_ERR_INVAL); 1727184610Salfred } 1728184610Salfred DPRINTFN(5, "len=%d\n", len); 1729184610Salfred 1730184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1731184610Salfred req.bRequest = UR_SET_REPORT; 1732184610Salfred USETW2(req.wValue, type, id); 1733184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1734184610Salfred req.wIndex[1] = 0; 1735184610Salfred USETW(req.wLength, len); 1736194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1737184610Salfred} 1738184610Salfred 1739184610Salfred/*------------------------------------------------------------------------* 1740194228Sthompsa * usbd_req_get_report 1741184610Salfred * 1742184610Salfred * Returns: 1743184610Salfred * 0: Success 1744184610Salfred * Else: Failure 1745184610Salfred *------------------------------------------------------------------------*/ 1746193045Sthompsausb_error_t 1747194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1748184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1749184610Salfred{ 1750194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1751192984Sthompsa struct usb_device_request req; 1752184610Salfred 1753224728Smav if ((iface == NULL) || (iface->idesc == NULL)) { 1754184610Salfred return (USB_ERR_INVAL); 1755184610Salfred } 1756184610Salfred DPRINTFN(5, "len=%d\n", len); 1757184610Salfred 1758184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1759184610Salfred req.bRequest = UR_GET_REPORT; 1760184610Salfred USETW2(req.wValue, type, id); 1761184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1762184610Salfred req.wIndex[1] = 0; 1763184610Salfred USETW(req.wLength, len); 1764194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1765184610Salfred} 1766184610Salfred 1767184610Salfred/*------------------------------------------------------------------------* 1768194228Sthompsa * usbd_req_set_idle 1769184610Salfred * 1770184610Salfred * Returns: 1771184610Salfred * 0: Success 1772184610Salfred * Else: Failure 1773184610Salfred *------------------------------------------------------------------------*/ 1774193045Sthompsausb_error_t 1775194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1776184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1777184610Salfred{ 1778194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1779192984Sthompsa struct usb_device_request req; 1780184610Salfred 1781184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1782184610Salfred return (USB_ERR_INVAL); 1783184610Salfred } 1784184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1785184610Salfred 1786184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1787184610Salfred req.bRequest = UR_SET_IDLE; 1788184610Salfred USETW2(req.wValue, duration, id); 1789184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1790184610Salfred req.wIndex[1] = 0; 1791184610Salfred USETW(req.wLength, 0); 1792194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1793184610Salfred} 1794184610Salfred 1795184610Salfred/*------------------------------------------------------------------------* 1796194228Sthompsa * usbd_req_get_report_descriptor 1797184610Salfred * 1798184610Salfred * Returns: 1799184610Salfred * 0: Success 1800184610Salfred * Else: Failure 1801184610Salfred *------------------------------------------------------------------------*/ 1802193045Sthompsausb_error_t 1803194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1804184610Salfred void *d, uint16_t size, uint8_t iface_index) 1805184610Salfred{ 1806194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1807192984Sthompsa struct usb_device_request req; 1808184610Salfred 1809184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1810184610Salfred return (USB_ERR_INVAL); 1811184610Salfred } 1812184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1813184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1814184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1815184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1816184610Salfred req.wIndex[1] = 0; 1817184610Salfred USETW(req.wLength, size); 1818194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1819184610Salfred} 1820184610Salfred 1821184610Salfred/*------------------------------------------------------------------------* 1822194228Sthompsa * usbd_req_set_config 1823184610Salfred * 1824184610Salfred * This function is used to select the current configuration number in 1825184610Salfred * both USB device side mode and USB host side mode. When setting the 1826184610Salfred * configuration the function of the interfaces can change. 1827184610Salfred * 1828184610Salfred * Returns: 1829184610Salfred * 0: Success 1830184610Salfred * Else: Failure 1831184610Salfred *------------------------------------------------------------------------*/ 1832193045Sthompsausb_error_t 1833194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1834184610Salfred{ 1835192984Sthompsa struct usb_device_request req; 1836184610Salfred 1837184610Salfred DPRINTF("setting config %d\n", conf); 1838184610Salfred 1839184610Salfred /* do "set configuration" request */ 1840184610Salfred 1841184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1842184610Salfred req.bRequest = UR_SET_CONFIG; 1843184610Salfred req.wValue[0] = conf; 1844184610Salfred req.wValue[1] = 0; 1845184610Salfred USETW(req.wIndex, 0); 1846184610Salfred USETW(req.wLength, 0); 1847194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1848184610Salfred} 1849184610Salfred 1850184610Salfred/*------------------------------------------------------------------------* 1851194228Sthompsa * usbd_req_get_config 1852184610Salfred * 1853184610Salfred * Returns: 1854184610Salfred * 0: Success 1855184610Salfred * Else: Failure 1856184610Salfred *------------------------------------------------------------------------*/ 1857193045Sthompsausb_error_t 1858194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1859184610Salfred{ 1860192984Sthompsa struct usb_device_request req; 1861184610Salfred 1862184610Salfred req.bmRequestType = UT_READ_DEVICE; 1863184610Salfred req.bRequest = UR_GET_CONFIG; 1864184610Salfred USETW(req.wValue, 0); 1865184610Salfred USETW(req.wIndex, 0); 1866184610Salfred USETW(req.wLength, 1); 1867194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1868184610Salfred} 1869184610Salfred 1870184610Salfred/*------------------------------------------------------------------------* 1871213435Shselasky * usbd_setup_device_desc 1872213435Shselasky *------------------------------------------------------------------------*/ 1873213435Shselaskyusb_error_t 1874213435Shselaskyusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) 1875213435Shselasky{ 1876213435Shselasky usb_error_t err; 1877213435Shselasky 1878213435Shselasky /* 1879213435Shselasky * Get the first 8 bytes of the device descriptor ! 1880213435Shselasky * 1881213435Shselasky * NOTE: "usbd_do_request()" will check the device descriptor 1882213435Shselasky * next time we do a request to see if the maximum packet size 1883213435Shselasky * changed! The 8 first bytes of the device descriptor 1884213435Shselasky * contains the maximum packet size to use on control endpoint 1885213435Shselasky * 0. If this value is different from "USB_MAX_IPACKET" a new 1886213435Shselasky * USB control request will be setup! 1887213435Shselasky */ 1888213435Shselasky switch (udev->speed) { 1889213435Shselasky case USB_SPEED_FULL: 1890213435Shselasky case USB_SPEED_LOW: 1891213435Shselasky err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1892213435Shselasky USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1893213435Shselasky if (err != 0) { 1894213435Shselasky DPRINTFN(0, "getting device descriptor " 1895213435Shselasky "at addr %d failed, %s\n", udev->address, 1896213435Shselasky usbd_errstr(err)); 1897213435Shselasky return (err); 1898213435Shselasky } 1899213435Shselasky break; 1900213435Shselasky default: 1901213435Shselasky DPRINTF("Minimum MaxPacketSize is large enough " 1902213435Shselasky "to hold the complete device descriptor\n"); 1903213435Shselasky break; 1904213435Shselasky } 1905213435Shselasky 1906213435Shselasky /* get the full device descriptor */ 1907213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1908213435Shselasky 1909213435Shselasky /* try one more time, if error */ 1910213435Shselasky if (err) 1911213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1912213435Shselasky 1913213435Shselasky if (err) { 1914213435Shselasky DPRINTF("addr=%d, getting full desc failed\n", 1915213435Shselasky udev->address); 1916213435Shselasky return (err); 1917213435Shselasky } 1918213435Shselasky 1919213435Shselasky DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " 1920213435Shselasky "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", 1921213435Shselasky udev->address, UGETW(udev->ddesc.bcdUSB), 1922213435Shselasky udev->ddesc.bDeviceClass, 1923213435Shselasky udev->ddesc.bDeviceSubClass, 1924213435Shselasky udev->ddesc.bDeviceProtocol, 1925213435Shselasky udev->ddesc.bMaxPacketSize, 1926213435Shselasky udev->ddesc.bLength, 1927213435Shselasky udev->speed); 1928213435Shselasky 1929213435Shselasky return (err); 1930213435Shselasky} 1931213435Shselasky 1932213435Shselasky/*------------------------------------------------------------------------* 1933194228Sthompsa * usbd_req_re_enumerate 1934184610Salfred * 1935185087Salfred * NOTE: After this function returns the hardware is in the 1936185087Salfred * unconfigured state! The application is responsible for setting a 1937185087Salfred * new configuration. 1938185087Salfred * 1939184610Salfred * Returns: 1940184610Salfred * 0: Success 1941184610Salfred * Else: Failure 1942184610Salfred *------------------------------------------------------------------------*/ 1943193045Sthompsausb_error_t 1944194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 1945184610Salfred{ 1946192984Sthompsa struct usb_device *parent_hub; 1947193045Sthompsa usb_error_t err; 1948184610Salfred uint8_t old_addr; 1949186730Salfred uint8_t do_retry = 1; 1950184610Salfred 1951192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 1952185290Salfred return (USB_ERR_INVAL); 1953185290Salfred } 1954184610Salfred old_addr = udev->address; 1955184610Salfred parent_hub = udev->parent_hub; 1956184610Salfred if (parent_hub == NULL) { 1957185290Salfred return (USB_ERR_INVAL); 1958184610Salfred } 1959186730Salfredretry: 1960222786Shselasky /* 1961222786Shselasky * Try to reset the High Speed parent HUB of a LOW- or FULL- 1962222786Shselasky * speed device, if any. 1963222786Shselasky */ 1964222786Shselasky if (udev->parent_hs_hub != NULL && 1965222786Shselasky udev->speed != USB_SPEED_HIGH) { 1966222786Shselasky DPRINTF("Trying to reset parent High Speed TT.\n"); 1967222786Shselasky err = usbd_req_reset_tt(udev->parent_hs_hub, NULL, 1968222786Shselasky udev->hs_port_no); 1969222786Shselasky if (err) { 1970222786Shselasky DPRINTF("Resetting parent High " 1971222786Shselasky "Speed TT failed (%s).\n", 1972222786Shselasky usbd_errstr(err)); 1973222786Shselasky } 1974222786Shselasky } 1975222786Shselasky 1976230091Shselasky /* Try to warm reset first */ 1977230091Shselasky if (parent_hub->speed == USB_SPEED_SUPER) 1978230091Shselasky usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no); 1979230091Shselasky 1980222786Shselasky /* Try to reset the parent HUB port. */ 1981194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 1982184610Salfred if (err) { 1983190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 1984194228Sthompsa old_addr, usbd_errstr(err)); 1985184610Salfred goto done; 1986184610Salfred } 1987213435Shselasky 1988184610Salfred /* 1989184610Salfred * After that the port has been reset our device should be at 1990184610Salfred * address zero: 1991184610Salfred */ 1992184610Salfred udev->address = USB_START_ADDR; 1993184610Salfred 1994185290Salfred /* reset "bMaxPacketSize" */ 1995185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 1996185290Salfred 1997213435Shselasky /* reset USB state */ 1998213435Shselasky usb_set_device_state(udev, USB_STATE_POWERED); 1999213435Shselasky 2000184610Salfred /* 2001184610Salfred * Restore device address: 2002184610Salfred */ 2003194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 2004184610Salfred if (err) { 2005184610Salfred /* XXX ignore any errors! */ 2006190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 2007194228Sthompsa old_addr, usbd_errstr(err)); 2008184610Salfred } 2009213435Shselasky /* 2010213435Shselasky * Restore device address, if the controller driver did not 2011213435Shselasky * set a new one: 2012213435Shselasky */ 2013213435Shselasky if (udev->address == USB_START_ADDR) 2014213435Shselasky udev->address = old_addr; 2015184610Salfred 2016213435Shselasky /* setup the device descriptor and the initial "wMaxPacketSize" */ 2017213435Shselasky err = usbd_setup_device_desc(udev, mtx); 2018184610Salfred 2019184610Salfreddone: 2020186730Salfred if (err && do_retry) { 2021186730Salfred /* give the USB firmware some time to load */ 2022194228Sthompsa usb_pause_mtx(mtx, hz / 2); 2023186730Salfred /* no more retries after this retry */ 2024186730Salfred do_retry = 0; 2025186730Salfred /* try again */ 2026186730Salfred goto retry; 2027186730Salfred } 2028184610Salfred /* restore address */ 2029213435Shselasky if (udev->address == USB_START_ADDR) 2030213435Shselasky udev->address = old_addr; 2031213435Shselasky /* update state, if successful */ 2032213435Shselasky if (err == 0) 2033213435Shselasky usb_set_device_state(udev, USB_STATE_ADDRESSED); 2034184610Salfred return (err); 2035184610Salfred} 2036186730Salfred 2037186730Salfred/*------------------------------------------------------------------------* 2038194228Sthompsa * usbd_req_clear_device_feature 2039186730Salfred * 2040186730Salfred * Returns: 2041186730Salfred * 0: Success 2042186730Salfred * Else: Failure 2043186730Salfred *------------------------------------------------------------------------*/ 2044193045Sthompsausb_error_t 2045194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 2046186730Salfred uint16_t sel) 2047186730Salfred{ 2048192984Sthompsa struct usb_device_request req; 2049186730Salfred 2050186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2051186730Salfred req.bRequest = UR_CLEAR_FEATURE; 2052186730Salfred USETW(req.wValue, sel); 2053186730Salfred USETW(req.wIndex, 0); 2054186730Salfred USETW(req.wLength, 0); 2055194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2056186730Salfred} 2057186730Salfred 2058186730Salfred/*------------------------------------------------------------------------* 2059194228Sthompsa * usbd_req_set_device_feature 2060186730Salfred * 2061186730Salfred * Returns: 2062186730Salfred * 0: Success 2063186730Salfred * Else: Failure 2064186730Salfred *------------------------------------------------------------------------*/ 2065193045Sthompsausb_error_t 2066194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 2067186730Salfred uint16_t sel) 2068186730Salfred{ 2069192984Sthompsa struct usb_device_request req; 2070186730Salfred 2071186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2072186730Salfred req.bRequest = UR_SET_FEATURE; 2073186730Salfred USETW(req.wValue, sel); 2074186730Salfred USETW(req.wIndex, 0); 2075186730Salfred USETW(req.wLength, 0); 2076194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2077186730Salfred} 2078222786Shselasky 2079222786Shselasky/*------------------------------------------------------------------------* 2080222786Shselasky * usbd_req_reset_tt 2081222786Shselasky * 2082222786Shselasky * Returns: 2083222786Shselasky * 0: Success 2084222786Shselasky * Else: Failure 2085222786Shselasky *------------------------------------------------------------------------*/ 2086222786Shselaskyusb_error_t 2087222786Shselaskyusbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx, 2088222786Shselasky uint8_t port) 2089222786Shselasky{ 2090222786Shselasky struct usb_device_request req; 2091222786Shselasky 2092222786Shselasky /* For single TT HUBs the port should be 1 */ 2093222786Shselasky 2094222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2095222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2096222786Shselasky port = 1; 2097222786Shselasky 2098222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2099222786Shselasky req.bRequest = UR_RESET_TT; 2100222786Shselasky USETW(req.wValue, 0); 2101222786Shselasky req.wIndex[0] = port; 2102222786Shselasky req.wIndex[1] = 0; 2103222786Shselasky USETW(req.wLength, 0); 2104222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2105222786Shselasky} 2106222786Shselasky 2107222786Shselasky/*------------------------------------------------------------------------* 2108222786Shselasky * usbd_req_clear_tt_buffer 2109222786Shselasky * 2110222786Shselasky * For single TT HUBs the port should be 1. 2111222786Shselasky * 2112222786Shselasky * Returns: 2113222786Shselasky * 0: Success 2114222786Shselasky * Else: Failure 2115222786Shselasky *------------------------------------------------------------------------*/ 2116222786Shselaskyusb_error_t 2117222786Shselaskyusbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, 2118222786Shselasky uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint) 2119222786Shselasky{ 2120222786Shselasky struct usb_device_request req; 2121222786Shselasky uint16_t wValue; 2122222786Shselasky 2123222786Shselasky /* For single TT HUBs the port should be 1 */ 2124222786Shselasky 2125222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2126222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2127222786Shselasky port = 1; 2128222786Shselasky 2129222786Shselasky wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) | 2130222786Shselasky ((endpoint & 0x80) << 8) | ((type & 3) << 12); 2131222786Shselasky 2132222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2133222786Shselasky req.bRequest = UR_CLEAR_TT_BUFFER; 2134222786Shselasky USETW(req.wValue, wValue); 2135222786Shselasky req.wIndex[0] = port; 2136222786Shselasky req.wIndex[1] = 0; 2137222786Shselasky USETW(req.wLength, 0); 2138222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2139222786Shselasky} 2140230032Shselasky 2141230032Shselasky/*------------------------------------------------------------------------* 2142230032Shselasky * usbd_req_set_port_link_state 2143230032Shselasky * 2144230032Shselasky * USB 3.0 specific request 2145230032Shselasky * 2146230032Shselasky * Returns: 2147230032Shselasky * 0: Success 2148230032Shselasky * Else: Failure 2149230032Shselasky *------------------------------------------------------------------------*/ 2150230032Shselaskyusb_error_t 2151230032Shselaskyusbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx, 2152230032Shselasky uint8_t port, uint8_t link_state) 2153230032Shselasky{ 2154230032Shselasky struct usb_device_request req; 2155230032Shselasky 2156230032Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2157230032Shselasky req.bRequest = UR_SET_FEATURE; 2158230032Shselasky USETW(req.wValue, UHF_PORT_LINK_STATE); 2159230032Shselasky req.wIndex[0] = port; 2160230032Shselasky req.wIndex[1] = link_state; 2161230032Shselasky USETW(req.wLength, 0); 2162230032Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2163230032Shselasky} 2164233771Shselasky 2165233771Shselasky/*------------------------------------------------------------------------* 2166233771Shselasky * usbd_req_set_lpm_info 2167233771Shselasky * 2168233771Shselasky * USB 2.0 specific request for Link Power Management. 2169233771Shselasky * 2170233771Shselasky * Returns: 2171233771Shselasky * 0: Success 2172233771Shselasky * USB_ERR_PENDING_REQUESTS: NYET 2173233771Shselasky * USB_ERR_TIMEOUT: TIMEOUT 2174233771Shselasky * USB_ERR_STALL: STALL 2175233771Shselasky * Else: Failure 2176233771Shselasky *------------------------------------------------------------------------*/ 2177233771Shselaskyusb_error_t 2178233771Shselaskyusbd_req_set_lpm_info(struct usb_device *udev, struct mtx *mtx, 2179233771Shselasky uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe) 2180233771Shselasky{ 2181233771Shselasky struct usb_device_request req; 2182233771Shselasky usb_error_t err; 2183233771Shselasky uint8_t buf[1]; 2184233771Shselasky 2185233771Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2186233771Shselasky req.bRequest = UR_SET_AND_TEST; 2187233771Shselasky USETW(req.wValue, UHF_PORT_L1); 2188233771Shselasky req.wIndex[0] = (port & 0xF) | ((besl & 0xF) << 4); 2189233771Shselasky req.wIndex[1] = (addr & 0x7F) | (rwe ? 0x80 : 0x00); 2190233771Shselasky USETW(req.wLength, sizeof(buf)); 2191233771Shselasky 2192233771Shselasky /* set default value in case of short transfer */ 2193233771Shselasky buf[0] = 0x00; 2194233771Shselasky 2195233771Shselasky err = usbd_do_request(udev, mtx, &req, buf); 2196233771Shselasky if (err) 2197233771Shselasky return (err); 2198233771Shselasky 2199233771Shselasky switch (buf[0]) { 2200233771Shselasky case 0x00: /* SUCCESS */ 2201233771Shselasky break; 2202233771Shselasky case 0x10: /* NYET */ 2203233771Shselasky err = USB_ERR_PENDING_REQUESTS; 2204233771Shselasky break; 2205233771Shselasky case 0x11: /* TIMEOUT */ 2206233771Shselasky err = USB_ERR_TIMEOUT; 2207233771Shselasky break; 2208233771Shselasky case 0x30: /* STALL */ 2209233771Shselasky err = USB_ERR_STALLED; 2210233771Shselasky break; 2211233771Shselasky default: /* reserved */ 2212233771Shselasky err = USB_ERR_IOERROR; 2213233771Shselasky break; 2214233771Shselasky } 2215233771Shselasky return (err); 2216233771Shselasky} 2217233771Shselasky 2218