1184610Salfred/* $FreeBSD: stable/11/sys/dev/usb/usb_request.c 368827 2020-12-30 01:11:12Z hselasky $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 4184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 5368827Shselasky * Copyright (c) 2008-2020 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/usbhid.h> 55184610Salfred 56194228Sthompsa#define USB_DEBUG_VAR usb_debug 57184610Salfred 58188942Sthompsa#include <dev/usb/usb_core.h> 59188942Sthompsa#include <dev/usb/usb_busdma.h> 60188942Sthompsa#include <dev/usb/usb_request.h> 61188942Sthompsa#include <dev/usb/usb_process.h> 62188942Sthompsa#include <dev/usb/usb_transfer.h> 63188942Sthompsa#include <dev/usb/usb_debug.h> 64188942Sthompsa#include <dev/usb/usb_device.h> 65188942Sthompsa#include <dev/usb/usb_util.h> 66188942Sthompsa#include <dev/usb/usb_dynamic.h> 67184610Salfred 68188942Sthompsa#include <dev/usb/usb_controller.h> 69188942Sthompsa#include <dev/usb/usb_bus.h> 70184610Salfred#include <sys/ctype.h> 71246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 72184610Salfred 73225000Shselaskystatic int usb_no_cs_fail; 74225000Shselasky 75276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RWTUN, 76225000Shselasky &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set"); 77225000Shselasky 78248246Shselaskystatic int usb_full_ddesc; 79248246Shselasky 80276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, full_ddesc, CTLFLAG_RWTUN, 81248246Shselasky &usb_full_ddesc, 0, "USB always read complete device descriptor, if set"); 82248246Shselasky 83207077Sthompsa#ifdef USB_DEBUG 84208018Sthompsa#ifdef USB_REQ_DEBUG 85208018Sthompsa/* The following structures are used in connection to fault injection. */ 86208018Sthompsastruct usb_ctrl_debug { 87208018Sthompsa int bus_index; /* target bus */ 88208018Sthompsa int dev_index; /* target address */ 89208018Sthompsa int ds_fail; /* fail data stage */ 90240750Shselasky int ss_fail; /* fail status stage */ 91208018Sthompsa int ds_delay; /* data stage delay in ms */ 92208018Sthompsa int ss_delay; /* status stage delay in ms */ 93208018Sthompsa int bmRequestType_value; 94208018Sthompsa int bRequest_value; 95208018Sthompsa}; 96208018Sthompsa 97208018Sthompsastruct usb_ctrl_debug_bits { 98208018Sthompsa uint16_t ds_delay; 99208018Sthompsa uint16_t ss_delay; 100208018Sthompsa uint8_t ds_fail:1; 101208018Sthompsa uint8_t ss_fail:1; 102208018Sthompsa uint8_t enabled:1; 103208018Sthompsa}; 104208018Sthompsa 105208018Sthompsa/* The default is to disable fault injection. */ 106208018Sthompsa 107208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = { 108208018Sthompsa .bus_index = -1, 109208018Sthompsa .dev_index = -1, 110208018Sthompsa .bmRequestType_value = -1, 111208018Sthompsa .bRequest_value = -1, 112208018Sthompsa}; 113208018Sthompsa 114276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RWTUN, 115208018Sthompsa &usb_ctrl_debug.bus_index, 0, "USB controller index to fail"); 116276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RWTUN, 117208018Sthompsa &usb_ctrl_debug.dev_index, 0, "USB device address to fail"); 118276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RWTUN, 119208018Sthompsa &usb_ctrl_debug.ds_fail, 0, "USB fail data stage"); 120276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RWTUN, 121208018Sthompsa &usb_ctrl_debug.ss_fail, 0, "USB fail status stage"); 122276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RWTUN, 123208018Sthompsa &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms"); 124276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RWTUN, 125208018Sthompsa &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms"); 126276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RWTUN, 127208018Sthompsa &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail"); 128276701ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RWTUN, 129208018Sthompsa &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail"); 130208018Sthompsa 131184610Salfred/*------------------------------------------------------------------------* 132208018Sthompsa * usbd_get_debug_bits 133208018Sthompsa * 134208018Sthompsa * This function is only useful in USB host mode. 135208018Sthompsa *------------------------------------------------------------------------*/ 136208018Sthompsastatic void 137208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, 138208018Sthompsa struct usb_ctrl_debug_bits *dbg) 139208018Sthompsa{ 140208018Sthompsa int temp; 141208018Sthompsa 142208018Sthompsa memset(dbg, 0, sizeof(*dbg)); 143208018Sthompsa 144208018Sthompsa /* Compute data stage delay */ 145208018Sthompsa 146208018Sthompsa temp = usb_ctrl_debug.ds_delay; 147208018Sthompsa if (temp < 0) 148208018Sthompsa temp = 0; 149208018Sthompsa else if (temp > (16*1024)) 150208018Sthompsa temp = (16*1024); 151208018Sthompsa 152208018Sthompsa dbg->ds_delay = temp; 153208018Sthompsa 154208018Sthompsa /* Compute status stage delay */ 155208018Sthompsa 156208018Sthompsa temp = usb_ctrl_debug.ss_delay; 157208018Sthompsa if (temp < 0) 158208018Sthompsa temp = 0; 159208018Sthompsa else if (temp > (16*1024)) 160208018Sthompsa temp = (16*1024); 161208018Sthompsa 162208018Sthompsa dbg->ss_delay = temp; 163208018Sthompsa 164208018Sthompsa /* Check if this control request should be failed */ 165208018Sthompsa 166208018Sthompsa if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) 167208018Sthompsa return; 168208018Sthompsa 169208018Sthompsa if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) 170208018Sthompsa return; 171208018Sthompsa 172208018Sthompsa temp = usb_ctrl_debug.bmRequestType_value; 173208018Sthompsa 174208018Sthompsa if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) 175208018Sthompsa return; 176208018Sthompsa 177208018Sthompsa temp = usb_ctrl_debug.bRequest_value; 178208018Sthompsa 179208018Sthompsa if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) 180208018Sthompsa return; 181208018Sthompsa 182208018Sthompsa temp = usb_ctrl_debug.ds_fail; 183208018Sthompsa if (temp) 184208018Sthompsa dbg->ds_fail = 1; 185208018Sthompsa 186208018Sthompsa temp = usb_ctrl_debug.ss_fail; 187208018Sthompsa if (temp) 188208018Sthompsa dbg->ss_fail = 1; 189208018Sthompsa 190208018Sthompsa dbg->enabled = 1; 191208018Sthompsa} 192208018Sthompsa#endif /* USB_REQ_DEBUG */ 193208018Sthompsa#endif /* USB_DEBUG */ 194208018Sthompsa 195208018Sthompsa/*------------------------------------------------------------------------* 196194228Sthompsa * usbd_do_request_callback 197184610Salfred * 198184610Salfred * This function is the USB callback for generic USB Host control 199184610Salfred * transfers. 200184610Salfred *------------------------------------------------------------------------*/ 201184610Salfredvoid 202194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error) 203184610Salfred{ 204184610Salfred ; /* workaround for a bug in "indent" */ 205184610Salfred 206184610Salfred DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 207184610Salfred 208184610Salfred switch (USB_GET_STATE(xfer)) { 209184610Salfred case USB_ST_SETUP: 210194228Sthompsa usbd_transfer_submit(xfer); 211184610Salfred break; 212184610Salfred default: 213207079Sthompsa cv_signal(&xfer->xroot->udev->ctrlreq_cv); 214184610Salfred break; 215184610Salfred } 216184610Salfred} 217184610Salfred 218184610Salfred/*------------------------------------------------------------------------* 219194228Sthompsa * usb_do_clear_stall_callback 220184610Salfred * 221184610Salfred * This function is the USB callback for generic clear stall requests. 222184610Salfred *------------------------------------------------------------------------*/ 223184610Salfredvoid 224194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 225184610Salfred{ 226192984Sthompsa struct usb_device_request req; 227192984Sthompsa struct usb_device *udev; 228193644Sthompsa struct usb_endpoint *ep; 229193644Sthompsa struct usb_endpoint *ep_end; 230193644Sthompsa struct usb_endpoint *ep_first; 231239214Shselasky usb_stream_t x; 232190731Sthompsa uint8_t to; 233184610Salfred 234187173Sthompsa udev = xfer->xroot->udev; 235184610Salfred 236187173Sthompsa USB_BUS_LOCK(udev->bus); 237187173Sthompsa 238193644Sthompsa /* round robin endpoint clear stall */ 239184610Salfred 240193644Sthompsa ep = udev->ep_curr; 241193644Sthompsa ep_end = udev->endpoints + udev->endpoints_max; 242193644Sthompsa ep_first = udev->endpoints; 243193644Sthompsa to = udev->endpoints_max; 244193318Sthompsa 245184610Salfred switch (USB_GET_STATE(xfer)) { 246184610Salfred case USB_ST_TRANSFERRED: 247225000Shselaskytr_transferred: 248222786Shselasky /* reset error counter */ 249222786Shselasky udev->clear_stall_errors = 0; 250222786Shselasky 251193644Sthompsa if (ep == NULL) 252193318Sthompsa goto tr_setup; /* device was unconfigured */ 253193644Sthompsa if (ep->edesc && 254193644Sthompsa ep->is_stalled) { 255193644Sthompsa ep->toggle_next = 0; 256193644Sthompsa ep->is_stalled = 0; 257213435Shselasky /* some hardware needs a callback to clear the data toggle */ 258213435Shselasky usbd_clear_stall_locked(udev, ep); 259239214Shselasky for (x = 0; x != USB_MAX_EP_STREAMS; x++) { 260239214Shselasky /* start the current or next transfer, if any */ 261239214Shselasky usb_command_wrapper(&ep->endpoint_q[x], 262239214Shselasky ep->endpoint_q[x].curr); 263239214Shselasky } 264184610Salfred } 265193644Sthompsa ep++; 266184610Salfred 267184610Salfred case USB_ST_SETUP: 268184610Salfredtr_setup: 269193318Sthompsa if (to == 0) 270193644Sthompsa break; /* no endpoints - nothing to do */ 271193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 272193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 273193644Sthompsa if (ep->edesc && 274193644Sthompsa ep->is_stalled) { 275184610Salfred 276184610Salfred /* setup a clear-stall packet */ 277184610Salfred 278184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 279184610Salfred req.bRequest = UR_CLEAR_FEATURE; 280184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 281193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 282184610Salfred req.wIndex[1] = 0; 283184610Salfred USETW(req.wLength, 0); 284184610Salfred 285184610Salfred /* copy in the transfer */ 286184610Salfred 287194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 288184610Salfred 289184610Salfred /* set length */ 290194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 291184610Salfred xfer->nframes = 1; 292187173Sthompsa USB_BUS_UNLOCK(udev->bus); 293184610Salfred 294194228Sthompsa usbd_transfer_submit(xfer); 295184610Salfred 296187173Sthompsa USB_BUS_LOCK(udev->bus); 297184610Salfred break; 298184610Salfred } 299193644Sthompsa ep++; 300193318Sthompsa to--; 301193318Sthompsa goto tr_setup; 302184610Salfred 303184610Salfred default: 304222786Shselasky if (error == USB_ERR_CANCELLED) 305184610Salfred break; 306222786Shselasky 307222786Shselasky DPRINTF("Clear stall failed.\n"); 308225000Shselasky 309225000Shselasky /* 310225000Shselasky * Some VMs like VirtualBox always return failure on 311225000Shselasky * clear-stall which we sometimes should just ignore. 312225000Shselasky */ 313225000Shselasky if (usb_no_cs_fail) 314225000Shselasky goto tr_transferred; 315222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) 316222786Shselasky goto tr_setup; 317222786Shselasky 318222786Shselasky if (error == USB_ERR_TIMEOUT) { 319222786Shselasky udev->clear_stall_errors = USB_CS_RESET_LIMIT; 320222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 321222786Shselasky usbd_start_re_enumerate(udev); 322222786Shselasky } else { 323222786Shselasky udev->clear_stall_errors++; 324222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) { 325222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 326222786Shselasky usbd_start_re_enumerate(udev); 327222786Shselasky } 328184610Salfred } 329184610Salfred goto tr_setup; 330184610Salfred } 331184610Salfred 332193644Sthompsa /* store current endpoint */ 333193644Sthompsa udev->ep_curr = ep; 334187173Sthompsa USB_BUS_UNLOCK(udev->bus); 335184610Salfred} 336184610Salfred 337193045Sthompsastatic usb_handle_req_t * 338194228Sthompsausbd_get_hr_func(struct usb_device *udev) 339191402Sthompsa{ 340191402Sthompsa /* figure out if there is a Handle Request function */ 341192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 342194228Sthompsa return (usb_temp_get_desc_p); 343191402Sthompsa else if (udev->parent_hub == NULL) 344191402Sthompsa return (udev->bus->methods->roothub_exec); 345191402Sthompsa else 346191402Sthompsa return (NULL); 347191402Sthompsa} 348191402Sthompsa 349184610Salfred/*------------------------------------------------------------------------* 350194228Sthompsa * usbd_do_request_flags and usbd_do_request 351184610Salfred * 352184610Salfred * Description of arguments passed to these functions: 353184610Salfred * 354192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 355184610Salfred * request should be performed. It is possible to call this function 356184610Salfred * in both Host Side mode and Device Side mode. 357184610Salfred * 358184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 359184610Salfred * will get dropped and picked up during the execution of this 360184610Salfred * function, hence this function sometimes needs to sleep. If this 361184610Salfred * argument is NULL it has no effect. 362184610Salfred * 363184610Salfred * "req" - this argument must always be non-NULL and points to an 364184610Salfred * 8-byte structure holding the USB request to be done. The USB 365184610Salfred * request structure has a bit telling the direction of the USB 366184610Salfred * request, if it is a read or a write. 367184610Salfred * 368184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 369184610Salfred * is non-zero this argument must point to a valid kernel buffer which 370184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 371184610Salfred * be NULL. 372184610Salfred * 373184610Salfred * "flags" - here is a list of valid flags: 374184610Salfred * 375184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 376184610Salfred * specified 377184610Salfred * 378184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 379184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 380184610Salfred * sysctl. This flag is mostly useful for debugging. 381184610Salfred * 382184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 383184610Salfred * pointer. 384184610Salfred * 385184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 386184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 387184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 388184610Salfred * used. 389184610Salfred * 390184610Salfred * "timeout" - gives the timeout for the control transfer in 391184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 392184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 393184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 394184610Salfred * does not allow control requests without a timeout. 395184610Salfred * 396246759Shselasky * NOTE: This function is thread safe. All calls to "usbd_do_request_flags" 397246759Shselasky * will be serialized by the use of the USB device enumeration lock. 398184610Salfred * 399184610Salfred * Returns: 400184610Salfred * 0: Success 401184610Salfred * Else: Failure 402184610Salfred *------------------------------------------------------------------------*/ 403193045Sthompsausb_error_t 404194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 405192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 406193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 407184610Salfred{ 408208018Sthompsa#ifdef USB_REQ_DEBUG 409208018Sthompsa struct usb_ctrl_debug_bits dbg; 410208018Sthompsa#endif 411193045Sthompsa usb_handle_req_t *hr_func; 412192984Sthompsa struct usb_xfer *xfer; 413184610Salfred const void *desc; 414184610Salfred int err = 0; 415193045Sthompsa usb_ticks_t start_ticks; 416193045Sthompsa usb_ticks_t delta_ticks; 417193045Sthompsa usb_ticks_t max_ticks; 418184610Salfred uint16_t length; 419184610Salfred uint16_t temp; 420208018Sthompsa uint16_t acttemp; 421246759Shselasky uint8_t do_unlock; 422184610Salfred 423184610Salfred if (timeout < 50) { 424184610Salfred /* timeout is too small */ 425184610Salfred timeout = 50; 426184610Salfred } 427184610Salfred if (timeout > 30000) { 428184610Salfred /* timeout is too big */ 429184610Salfred timeout = 30000; 430184610Salfred } 431184610Salfred length = UGETW(req->wLength); 432184610Salfred 433184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 434184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 435184610Salfred udev, req->bmRequestType, req->bRequest, 436184610Salfred req->wValue[1], req->wValue[0], 437184610Salfred req->wIndex[1], req->wIndex[0], 438184610Salfred req->wLength[1], req->wLength[0]); 439184610Salfred 440191494Sthompsa /* Check if the device is still alive */ 441191494Sthompsa if (udev->state < USB_STATE_POWERED) { 442191494Sthompsa DPRINTF("usb device has gone\n"); 443191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 444191494Sthompsa } 445191494Sthompsa 446184610Salfred /* 447184610Salfred * Set "actlen" to a known value in case the caller does not 448184610Salfred * check the return value: 449184610Salfred */ 450190735Sthompsa if (actlen) 451184610Salfred *actlen = 0; 452190735Sthompsa 453190180Sthompsa#if (USB_HAVE_USER_IO == 0) 454190180Sthompsa if (flags & USB_USER_DATA_PTR) 455190180Sthompsa return (USB_ERR_INVAL); 456190180Sthompsa#endif 457208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) { 458184610Salfred mtx_unlock(mtx); 459208008Sthompsa mtx_assert(mtx, MA_NOTOWNED); 460184610Salfred } 461208008Sthompsa 462184610Salfred /* 463305733Shselasky * Serialize access to this function: 464208008Sthompsa */ 465305733Shselasky do_unlock = usbd_ctrl_lock(udev); 466208008Sthompsa 467194228Sthompsa hr_func = usbd_get_hr_func(udev); 468190735Sthompsa 469191402Sthompsa if (hr_func != NULL) { 470191402Sthompsa DPRINTF("Handle Request function is set\n"); 471190735Sthompsa 472191402Sthompsa desc = NULL; 473191402Sthompsa temp = 0; 474191402Sthompsa 475191402Sthompsa if (!(req->bmRequestType & UT_READ)) { 476190735Sthompsa if (length != 0) { 477191402Sthompsa DPRINTFN(1, "The handle request function " 478191402Sthompsa "does not support writing data!\n"); 479191402Sthompsa err = USB_ERR_INVAL; 480191402Sthompsa goto done; 481190735Sthompsa } 482190735Sthompsa } 483190735Sthompsa 484191402Sthompsa /* The root HUB code needs the BUS lock locked */ 485191402Sthompsa 486190735Sthompsa USB_BUS_LOCK(udev->bus); 487191402Sthompsa err = (hr_func) (udev, req, &desc, &temp); 488190735Sthompsa USB_BUS_UNLOCK(udev->bus); 489190735Sthompsa 490190735Sthompsa if (err) 491190735Sthompsa goto done; 492190735Sthompsa 493191402Sthompsa if (length > temp) { 494190735Sthompsa if (!(flags & USB_SHORT_XFER_OK)) { 495190735Sthompsa err = USB_ERR_SHORT_XFER; 496190735Sthompsa goto done; 497190735Sthompsa } 498191402Sthompsa length = temp; 499190735Sthompsa } 500190735Sthompsa if (actlen) 501190735Sthompsa *actlen = length; 502190735Sthompsa 503190735Sthompsa if (length > 0) { 504190735Sthompsa#if USB_HAVE_USER_IO 505190735Sthompsa if (flags & USB_USER_DATA_PTR) { 506191402Sthompsa if (copyout(desc, data, length)) { 507190735Sthompsa err = USB_ERR_INVAL; 508190735Sthompsa goto done; 509190735Sthompsa } 510190735Sthompsa } else 511190735Sthompsa#endif 512227461Shselasky memcpy(data, desc, length); 513190735Sthompsa } 514191402Sthompsa goto done; /* success */ 515190735Sthompsa } 516190735Sthompsa 517184610Salfred /* 518184610Salfred * Setup a new USB transfer or use the existing one, if any: 519184610Salfred */ 520207080Sthompsa usbd_ctrl_transfer_setup(udev); 521184610Salfred 522207080Sthompsa xfer = udev->ctrl_xfer[0]; 523184610Salfred if (xfer == NULL) { 524184610Salfred /* most likely out of memory */ 525184610Salfred err = USB_ERR_NOMEM; 526184610Salfred goto done; 527184610Salfred } 528208018Sthompsa 529208018Sthompsa#ifdef USB_REQ_DEBUG 530208018Sthompsa /* Get debug bits */ 531208018Sthompsa usbd_get_debug_bits(udev, req, &dbg); 532208018Sthompsa 533208018Sthompsa /* Check for fault injection */ 534208018Sthompsa if (dbg.enabled) 535208018Sthompsa flags |= USB_DELAY_STATUS_STAGE; 536208018Sthompsa#endif 537184824Sthompsa USB_XFER_LOCK(xfer); 538184610Salfred 539190734Sthompsa if (flags & USB_DELAY_STATUS_STAGE) 540184610Salfred xfer->flags.manual_status = 1; 541190734Sthompsa else 542184610Salfred xfer->flags.manual_status = 0; 543184610Salfred 544190734Sthompsa if (flags & USB_SHORT_XFER_OK) 545190734Sthompsa xfer->flags.short_xfer_ok = 1; 546190734Sthompsa else 547190734Sthompsa xfer->flags.short_xfer_ok = 0; 548190734Sthompsa 549184610Salfred xfer->timeout = timeout; 550184610Salfred 551184610Salfred start_ticks = ticks; 552184610Salfred 553184610Salfred max_ticks = USB_MS_TO_TICKS(timeout); 554184610Salfred 555194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 556184610Salfred 557194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); 558184610Salfred 559184610Salfred while (1) { 560184610Salfred temp = length; 561208018Sthompsa if (temp > usbd_xfer_max_len(xfer)) { 562194677Sthompsa temp = usbd_xfer_max_len(xfer); 563184610Salfred } 564208018Sthompsa#ifdef USB_REQ_DEBUG 565208018Sthompsa if (xfer->flags.manual_status) { 566208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) != 0) { 567208018Sthompsa /* Execute data stage separately */ 568208018Sthompsa temp = 0; 569208018Sthompsa } else if (temp > 0) { 570208018Sthompsa if (dbg.ds_fail) { 571208018Sthompsa err = USB_ERR_INVAL; 572208018Sthompsa break; 573208018Sthompsa } 574208018Sthompsa if (dbg.ds_delay > 0) { 575208018Sthompsa usb_pause_mtx( 576208018Sthompsa xfer->xroot->xfer_mtx, 577208018Sthompsa USB_MS_TO_TICKS(dbg.ds_delay)); 578208018Sthompsa /* make sure we don't time out */ 579208018Sthompsa start_ticks = ticks; 580208018Sthompsa } 581208018Sthompsa } 582208018Sthompsa } 583208018Sthompsa#endif 584194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, temp); 585184610Salfred 586184610Salfred if (temp > 0) { 587184610Salfred if (!(req->bmRequestType & UT_READ)) { 588190180Sthompsa#if USB_HAVE_USER_IO 589184610Salfred if (flags & USB_USER_DATA_PTR) { 590184824Sthompsa USB_XFER_UNLOCK(xfer); 591194228Sthompsa err = usbd_copy_in_user(xfer->frbuffers + 1, 592184610Salfred 0, data, temp); 593184824Sthompsa USB_XFER_LOCK(xfer); 594184610Salfred if (err) { 595184610Salfred err = USB_ERR_INVAL; 596184610Salfred break; 597184610Salfred } 598190180Sthompsa } else 599190180Sthompsa#endif 600194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 601190180Sthompsa 0, data, temp); 602184610Salfred } 603208018Sthompsa usbd_xfer_set_frames(xfer, 2); 604184610Salfred } else { 605208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) == 0) { 606184610Salfred if (xfer->flags.manual_status) { 607208018Sthompsa#ifdef USB_REQ_DEBUG 608208018Sthompsa if (dbg.ss_fail) { 609208018Sthompsa err = USB_ERR_INVAL; 610208018Sthompsa break; 611184610Salfred } 612208018Sthompsa if (dbg.ss_delay > 0) { 613194228Sthompsa usb_pause_mtx( 614187173Sthompsa xfer->xroot->xfer_mtx, 615208018Sthompsa USB_MS_TO_TICKS(dbg.ss_delay)); 616208018Sthompsa /* make sure we don't time out */ 617208018Sthompsa start_ticks = ticks; 618184610Salfred } 619184610Salfred#endif 620184610Salfred xfer->flags.manual_status = 0; 621184610Salfred } else { 622184610Salfred break; 623184610Salfred } 624184610Salfred } 625208018Sthompsa usbd_xfer_set_frames(xfer, 1); 626184610Salfred } 627184610Salfred 628194228Sthompsa usbd_transfer_start(xfer); 629184610Salfred 630194228Sthompsa while (usbd_transfer_pending(xfer)) { 631207079Sthompsa cv_wait(&udev->ctrlreq_cv, 632188983Sthompsa xfer->xroot->xfer_mtx); 633184610Salfred } 634184610Salfred 635184610Salfred err = xfer->error; 636184610Salfred 637184610Salfred if (err) { 638184610Salfred break; 639184610Salfred } 640184610Salfred 641208018Sthompsa /* get actual length of DATA stage */ 642208018Sthompsa 643208018Sthompsa if (xfer->aframes < 2) { 644208018Sthompsa acttemp = 0; 645184610Salfred } else { 646208018Sthompsa acttemp = usbd_xfer_frame_len(xfer, 1); 647184610Salfred } 648184610Salfred 649184610Salfred /* check for short packet */ 650184610Salfred 651208018Sthompsa if (temp > acttemp) { 652208018Sthompsa temp = acttemp; 653184610Salfred length = temp; 654184610Salfred } 655184610Salfred if (temp > 0) { 656184610Salfred if (req->bmRequestType & UT_READ) { 657190180Sthompsa#if USB_HAVE_USER_IO 658184610Salfred if (flags & USB_USER_DATA_PTR) { 659184824Sthompsa USB_XFER_UNLOCK(xfer); 660194228Sthompsa err = usbd_copy_out_user(xfer->frbuffers + 1, 661184610Salfred 0, data, temp); 662184824Sthompsa USB_XFER_LOCK(xfer); 663184610Salfred if (err) { 664184610Salfred err = USB_ERR_INVAL; 665184610Salfred break; 666184610Salfred } 667190180Sthompsa } else 668190180Sthompsa#endif 669194228Sthompsa usbd_copy_out(xfer->frbuffers + 1, 670184610Salfred 0, data, temp); 671184610Salfred } 672184610Salfred } 673184610Salfred /* 674184610Salfred * Clear "frlengths[0]" so that we don't send the setup 675184610Salfred * packet again: 676184610Salfred */ 677194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, 0); 678184610Salfred 679184610Salfred /* update length and data pointer */ 680184610Salfred length -= temp; 681184610Salfred data = USB_ADD_BYTES(data, temp); 682184610Salfred 683184610Salfred if (actlen) { 684184610Salfred (*actlen) += temp; 685184610Salfred } 686184610Salfred /* check for timeout */ 687184610Salfred 688184610Salfred delta_ticks = ticks - start_ticks; 689184610Salfred if (delta_ticks > max_ticks) { 690184610Salfred if (!err) { 691184610Salfred err = USB_ERR_TIMEOUT; 692184610Salfred } 693184610Salfred } 694184610Salfred if (err) { 695184610Salfred break; 696184610Salfred } 697184610Salfred } 698184610Salfred 699184610Salfred if (err) { 700184610Salfred /* 701184610Salfred * Make sure that the control endpoint is no longer 702184610Salfred * blocked in case of a non-transfer related error: 703184610Salfred */ 704194228Sthompsa usbd_transfer_stop(xfer); 705184610Salfred } 706184824Sthompsa USB_XFER_UNLOCK(xfer); 707184610Salfred 708184610Salfreddone: 709246759Shselasky if (do_unlock) 710305733Shselasky usbd_ctrl_unlock(udev); 711208008Sthompsa 712208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) 713184610Salfred mtx_lock(mtx); 714208008Sthompsa 715260589Shselasky switch (err) { 716260589Shselasky case USB_ERR_NORMAL_COMPLETION: 717260589Shselasky case USB_ERR_SHORT_XFER: 718260589Shselasky case USB_ERR_STALLED: 719260589Shselasky case USB_ERR_CANCELLED: 720260589Shselasky break; 721260589Shselasky default: 722365965Shselasky DPRINTF("error=%s - waiting a bit for TT cleanup\n", 723365965Shselasky usbd_errstr(err)); 724260589Shselasky usb_pause_mtx(mtx, hz / 16); 725260589Shselasky break; 726260589Shselasky } 727193045Sthompsa return ((usb_error_t)err); 728184610Salfred} 729184610Salfred 730184610Salfred/*------------------------------------------------------------------------* 731194228Sthompsa * usbd_do_request_proc - factored out code 732188411Sthompsa * 733188411Sthompsa * This function is factored out code. It does basically the same like 734194228Sthompsa * usbd_do_request_flags, except it will check the status of the 735188411Sthompsa * passed process argument before doing the USB request. If the 736188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It 737188411Sthompsa * is assumed that the mutex associated with the process is locked 738188411Sthompsa * when calling this function. 739188411Sthompsa *------------------------------------------------------------------------*/ 740193045Sthompsausb_error_t 741194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 742192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 743193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 744188411Sthompsa{ 745193045Sthompsa usb_error_t err; 746188411Sthompsa uint16_t len; 747188411Sthompsa 748188411Sthompsa /* get request data length */ 749188411Sthompsa len = UGETW(req->wLength); 750188411Sthompsa 751188411Sthompsa /* check if the device is being detached */ 752194228Sthompsa if (usb_proc_is_gone(pproc)) { 753188411Sthompsa err = USB_ERR_IOERROR; 754188411Sthompsa goto done; 755188411Sthompsa } 756188411Sthompsa 757188411Sthompsa /* forward the USB request */ 758194228Sthompsa err = usbd_do_request_flags(udev, pproc->up_mtx, 759188411Sthompsa req, data, flags, actlen, timeout); 760188411Sthompsa 761188411Sthompsadone: 762188411Sthompsa /* on failure we zero the data */ 763188411Sthompsa /* on short packet we zero the unused data */ 764188411Sthompsa if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 765188411Sthompsa if (err) 766188411Sthompsa memset(data, 0, len); 767188411Sthompsa else if (actlen && *actlen != len) 768188411Sthompsa memset(((uint8_t *)data) + *actlen, 0, len - *actlen); 769188411Sthompsa } 770188411Sthompsa return (err); 771188411Sthompsa} 772188411Sthompsa 773188411Sthompsa/*------------------------------------------------------------------------* 774194228Sthompsa * usbd_req_reset_port 775184610Salfred * 776214804Shselasky * This function will instruct a USB HUB to perform a reset sequence 777184610Salfred * on the specified port number. 778184610Salfred * 779184610Salfred * Returns: 780184610Salfred * 0: Success. The USB device should now be at address zero. 781184610Salfred * Else: Failure. No USB device is present and the USB port should be 782184610Salfred * disabled. 783184610Salfred *------------------------------------------------------------------------*/ 784193045Sthompsausb_error_t 785194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 786184610Salfred{ 787192984Sthompsa struct usb_port_status ps; 788193045Sthompsa usb_error_t err; 789184610Salfred uint16_t n; 790230091Shselasky uint16_t status; 791230091Shselasky uint16_t change; 792184610Salfred 793230091Shselasky DPRINTF("\n"); 794230091Shselasky 795224095Shselasky /* clear any leftover port reset changes first */ 796224095Shselasky usbd_req_clear_port_feature( 797224095Shselasky udev, mtx, port, UHF_C_PORT_RESET); 798224095Shselasky 799224095Shselasky /* assert port reset on the given port */ 800224095Shselasky err = usbd_req_set_port_feature( 801224095Shselasky udev, mtx, port, UHF_PORT_RESET); 802224095Shselasky 803224095Shselasky /* check for errors */ 804224095Shselasky if (err) 805184610Salfred goto done; 806184610Salfred n = 0; 807184610Salfred while (1) { 808184610Salfred /* wait for the device to recover from reset */ 809241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay)); 810241987Shselasky n += usb_port_reset_delay; 811194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 812230091Shselasky if (err) 813184610Salfred goto done; 814230091Shselasky 815224095Shselasky status = UGETW(ps.wPortStatus); 816224095Shselasky change = UGETW(ps.wPortChange); 817224095Shselasky 818216249Shselasky /* if the device disappeared, just give up */ 819224095Shselasky if (!(status & UPS_CURRENT_CONNECT_STATUS)) 820216249Shselasky goto done; 821224095Shselasky 822214804Shselasky /* check if reset is complete */ 823224095Shselasky if (change & UPS_C_PORT_RESET) 824214804Shselasky break; 825224095Shselasky 826224095Shselasky /* 827224095Shselasky * Some Virtual Machines like VirtualBox 4.x fail to 828224095Shselasky * generate a port reset change event. Check if reset 829224095Shselasky * is no longer asserted. 830224095Shselasky */ 831224095Shselasky if (!(status & UPS_RESET)) 832224095Shselasky break; 833224095Shselasky 834214804Shselasky /* check for timeout */ 835214804Shselasky if (n > 1000) { 836214804Shselasky n = 0; 837214804Shselasky break; 838214804Shselasky } 839214804Shselasky } 840214804Shselasky 841214804Shselasky /* clear port reset first */ 842214804Shselasky err = usbd_req_clear_port_feature( 843214804Shselasky udev, mtx, port, UHF_C_PORT_RESET); 844230091Shselasky if (err) 845214804Shselasky goto done; 846230091Shselasky 847214804Shselasky /* check for timeout */ 848214804Shselasky if (n == 0) { 849214804Shselasky err = USB_ERR_TIMEOUT; 850214804Shselasky goto done; 851214804Shselasky } 852214804Shselasky /* wait for the device to recover from reset */ 853241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery)); 854214804Shselasky 855214804Shselaskydone: 856214804Shselasky DPRINTFN(2, "port %d reset returning error=%s\n", 857214804Shselasky port, usbd_errstr(err)); 858214804Shselasky return (err); 859214804Shselasky} 860214804Shselasky 861214804Shselasky/*------------------------------------------------------------------------* 862214804Shselasky * usbd_req_warm_reset_port 863214804Shselasky * 864214804Shselasky * This function will instruct an USB HUB to perform a warm reset 865214804Shselasky * sequence on the specified port number. This kind of reset is not 866214804Shselasky * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted 867214804Shselasky * for SUPER-speed USB HUBs. 868214804Shselasky * 869214804Shselasky * Returns: 870214804Shselasky * 0: Success. The USB device should now be available again. 871214804Shselasky * Else: Failure. No USB device is present and the USB port should be 872214804Shselasky * disabled. 873214804Shselasky *------------------------------------------------------------------------*/ 874214804Shselaskyusb_error_t 875230091Shselaskyusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, 876230091Shselasky uint8_t port) 877214804Shselasky{ 878214804Shselasky struct usb_port_status ps; 879214804Shselasky usb_error_t err; 880214804Shselasky uint16_t n; 881230091Shselasky uint16_t status; 882230091Shselasky uint16_t change; 883214804Shselasky 884230091Shselasky DPRINTF("\n"); 885230091Shselasky 886230091Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 887230091Shselasky if (err) 888214804Shselasky goto done; 889230091Shselasky 890230091Shselasky status = UGETW(ps.wPortStatus); 891230091Shselasky 892230091Shselasky switch (UPS_PORT_LINK_STATE_GET(status)) { 893230091Shselasky case UPS_PORT_LS_U3: 894230091Shselasky case UPS_PORT_LS_COMP_MODE: 895230091Shselasky case UPS_PORT_LS_LOOPBACK: 896230091Shselasky case UPS_PORT_LS_SS_INA: 897230091Shselasky break; 898230091Shselasky default: 899230091Shselasky DPRINTF("Wrong state for warm reset\n"); 900230091Shselasky return (0); 901214804Shselasky } 902230091Shselasky 903230091Shselasky /* clear any leftover warm port reset changes first */ 904230091Shselasky usbd_req_clear_port_feature(udev, mtx, 905230091Shselasky port, UHF_C_BH_PORT_RESET); 906230091Shselasky 907230091Shselasky /* set warm port reset */ 908230091Shselasky err = usbd_req_set_port_feature(udev, mtx, 909230091Shselasky port, UHF_BH_PORT_RESET); 910230091Shselasky if (err) 911230091Shselasky goto done; 912230091Shselasky 913214804Shselasky n = 0; 914214804Shselasky while (1) { 915214804Shselasky /* wait for the device to recover from reset */ 916241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_delay)); 917241987Shselasky n += usb_port_reset_delay; 918214804Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 919230091Shselasky if (err) 920214804Shselasky goto done; 921230091Shselasky 922230091Shselasky status = UGETW(ps.wPortStatus); 923230091Shselasky change = UGETW(ps.wPortChange); 924230091Shselasky 925184610Salfred /* if the device disappeared, just give up */ 926230091Shselasky if (!(status & UPS_CURRENT_CONNECT_STATUS)) 927184610Salfred goto done; 928230091Shselasky 929184610Salfred /* check if reset is complete */ 930230091Shselasky if (change & UPS_C_BH_PORT_RESET) 931184610Salfred break; 932230091Shselasky 933184610Salfred /* check for timeout */ 934184610Salfred if (n > 1000) { 935184610Salfred n = 0; 936184610Salfred break; 937184610Salfred } 938184610Salfred } 939184610Salfred 940184610Salfred /* clear port reset first */ 941194228Sthompsa err = usbd_req_clear_port_feature( 942214804Shselasky udev, mtx, port, UHF_C_BH_PORT_RESET); 943230091Shselasky if (err) 944184610Salfred goto done; 945230091Shselasky 946184610Salfred /* check for timeout */ 947184610Salfred if (n == 0) { 948184610Salfred err = USB_ERR_TIMEOUT; 949184610Salfred goto done; 950184610Salfred } 951184610Salfred /* wait for the device to recover from reset */ 952241987Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(usb_port_reset_recovery)); 953184610Salfred 954184610Salfreddone: 955214804Shselasky DPRINTFN(2, "port %d warm reset returning error=%s\n", 956194228Sthompsa port, usbd_errstr(err)); 957184610Salfred return (err); 958184610Salfred} 959184610Salfred 960184610Salfred/*------------------------------------------------------------------------* 961194228Sthompsa * usbd_req_get_desc 962184610Salfred * 963184610Salfred * This function can be used to retrieve USB descriptors. It contains 964184610Salfred * some additional logic like zeroing of missing descriptor bytes and 965184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 966184610Salfred * argument specifies the minimum descriptor length. The "max_len" 967184610Salfred * argument specifies the maximum descriptor length. If the real 968184610Salfred * descriptor length is less than the minimum length the missing 969188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 970188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 971188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 972188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 973188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 974188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 975188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 976188985Sthompsa * "max_len" then this function will try to retrive the beginning of 977188985Sthompsa * the descriptor and base the maximum length on the first byte of the 978188985Sthompsa * descriptor. 979184610Salfred * 980184610Salfred * Returns: 981184610Salfred * 0: Success 982184610Salfred * Else: Failure 983184610Salfred *------------------------------------------------------------------------*/ 984193045Sthompsausb_error_t 985194228Sthompsausbd_req_get_desc(struct usb_device *udev, 986188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 987184610Salfred uint16_t min_len, uint16_t max_len, 988184610Salfred uint16_t id, uint8_t type, uint8_t index, 989184610Salfred uint8_t retries) 990184610Salfred{ 991192984Sthompsa struct usb_device_request req; 992336886Shselasky uint8_t *buf = desc; 993193045Sthompsa usb_error_t err; 994184610Salfred 995184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 996184610Salfred id, type, index, max_len); 997184610Salfred 998184610Salfred req.bmRequestType = UT_READ_DEVICE; 999184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1000184610Salfred USETW2(req.wValue, type, index); 1001184610Salfred USETW(req.wIndex, id); 1002184610Salfred 1003184610Salfred while (1) { 1004184610Salfred 1005184610Salfred if ((min_len < 2) || (max_len < 2)) { 1006184610Salfred err = USB_ERR_INVAL; 1007184610Salfred goto done; 1008184610Salfred } 1009184610Salfred USETW(req.wLength, min_len); 1010184610Salfred 1011194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 1012365965Shselasky desc, 0, NULL, 1000 /* ms */); 1013184610Salfred 1014336886Shselasky if (err != 0 && err != USB_ERR_TIMEOUT && 1015336886Shselasky min_len != max_len) { 1016336886Shselasky /* clear descriptor data */ 1017336886Shselasky memset(desc, 0, max_len); 1018336886Shselasky 1019336886Shselasky /* try to read full descriptor length */ 1020336886Shselasky USETW(req.wLength, max_len); 1021336886Shselasky 1022336886Shselasky err = usbd_do_request_flags(udev, mtx, &req, 1023365965Shselasky desc, USB_SHORT_XFER_OK, NULL, 1000 /* ms */); 1024336886Shselasky 1025336886Shselasky if (err == 0) { 1026336886Shselasky /* verify length */ 1027336886Shselasky if (buf[0] > max_len) 1028336886Shselasky buf[0] = max_len; 1029336886Shselasky else if (buf[0] < 2) 1030336886Shselasky err = USB_ERR_INVAL; 1031336886Shselasky 1032336886Shselasky min_len = buf[0]; 1033336886Shselasky 1034336886Shselasky /* enforce descriptor type */ 1035336886Shselasky buf[1] = type; 1036336886Shselasky goto done; 1037336886Shselasky } 1038336886Shselasky } 1039336886Shselasky 1040184610Salfred if (err) { 1041184610Salfred if (!retries) { 1042184610Salfred goto done; 1043184610Salfred } 1044184610Salfred retries--; 1045184610Salfred 1046194228Sthompsa usb_pause_mtx(mtx, hz / 5); 1047184610Salfred 1048184610Salfred continue; 1049184610Salfred } 1050184610Salfred 1051184610Salfred if (min_len == max_len) { 1052184610Salfred 1053188985Sthompsa /* enforce correct length */ 1054188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 1055188985Sthompsa buf[0] = min_len; 1056184610Salfred 1057188985Sthompsa /* enforce correct type */ 1058184610Salfred buf[1] = type; 1059184610Salfred 1060184610Salfred goto done; 1061184610Salfred } 1062184610Salfred /* range check */ 1063184610Salfred 1064184610Salfred if (max_len > buf[0]) { 1065184610Salfred max_len = buf[0]; 1066184610Salfred } 1067184610Salfred /* zero minimum data */ 1068184610Salfred 1069184610Salfred while (min_len > max_len) { 1070184610Salfred min_len--; 1071184610Salfred buf[min_len] = 0; 1072184610Salfred } 1073184610Salfred 1074184610Salfred /* set new minimum length */ 1075184610Salfred 1076184610Salfred min_len = max_len; 1077184610Salfred } 1078184610Salfreddone: 1079188985Sthompsa if (actlen != NULL) { 1080188985Sthompsa if (err) 1081188985Sthompsa *actlen = 0; 1082188985Sthompsa else 1083188985Sthompsa *actlen = min_len; 1084188985Sthompsa } 1085184610Salfred return (err); 1086184610Salfred} 1087184610Salfred 1088184610Salfred/*------------------------------------------------------------------------* 1089194228Sthompsa * usbd_req_get_string_any 1090184610Salfred * 1091184610Salfred * This function will return the string given by "string_index" 1092184610Salfred * using the first language ID. The maximum length "len" includes 1093184610Salfred * the terminating zero. The "len" argument should be twice as 1094184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 1095184610Salfred * 1096184610Salfred * Returns: 1097184610Salfred * 0: Success 1098184610Salfred * Else: Failure 1099184610Salfred *------------------------------------------------------------------------*/ 1100193045Sthompsausb_error_t 1101194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 1102184610Salfred uint16_t len, uint8_t string_index) 1103184610Salfred{ 1104184610Salfred char *s; 1105184610Salfred uint8_t *temp; 1106184610Salfred uint16_t i; 1107184610Salfred uint16_t n; 1108184610Salfred uint16_t c; 1109184610Salfred uint8_t swap; 1110193045Sthompsa usb_error_t err; 1111184610Salfred 1112184610Salfred if (len == 0) { 1113184610Salfred /* should not happen */ 1114184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1115184610Salfred } 1116184610Salfred if (string_index == 0) { 1117184610Salfred /* this is the language table */ 1118185087Salfred buf[0] = 0; 1119184610Salfred return (USB_ERR_INVAL); 1120184610Salfred } 1121184610Salfred if (udev->flags.no_strings) { 1122185087Salfred buf[0] = 0; 1123184610Salfred return (USB_ERR_STALLED); 1124184610Salfred } 1125194228Sthompsa err = usbd_req_get_string_desc 1126184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 1127184610Salfred if (err) { 1128185087Salfred buf[0] = 0; 1129184610Salfred return (err); 1130184610Salfred } 1131184610Salfred temp = (uint8_t *)buf; 1132184610Salfred 1133184610Salfred if (temp[0] < 2) { 1134184610Salfred /* string length is too short */ 1135185087Salfred buf[0] = 0; 1136184610Salfred return (USB_ERR_INVAL); 1137184610Salfred } 1138184610Salfred /* reserve one byte for terminating zero */ 1139184610Salfred len--; 1140184610Salfred 1141184610Salfred /* find maximum length */ 1142184610Salfred s = buf; 1143184610Salfred n = (temp[0] / 2) - 1; 1144184610Salfred if (n > len) { 1145184610Salfred n = len; 1146184610Salfred } 1147184610Salfred /* skip descriptor header */ 1148184610Salfred temp += 2; 1149184610Salfred 1150184610Salfred /* reset swap state */ 1151184610Salfred swap = 3; 1152184610Salfred 1153184610Salfred /* convert and filter */ 1154184610Salfred for (i = 0; (i != n); i++) { 1155184610Salfred c = UGETW(temp + (2 * i)); 1156184610Salfred 1157184610Salfred /* convert from Unicode, handle buggy strings */ 1158184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 1159184610Salfred /* Little Endian, default */ 1160184610Salfred *s = c; 1161184610Salfred swap = 1; 1162184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1163184610Salfred /* Big Endian */ 1164184610Salfred *s = c >> 8; 1165184610Salfred swap = 2; 1166184610Salfred } else { 1167185087Salfred /* silently skip bad character */ 1168185087Salfred continue; 1169184610Salfred } 1170184610Salfred 1171184610Salfred /* 1172213433Shselasky * Filter by default - We only allow alphanumerical 1173213433Shselasky * and a few more to avoid any problems with scripts 1174213433Shselasky * and daemons. 1175184610Salfred */ 1176213433Shselasky if (isalpha(*s) || 1177213433Shselasky isdigit(*s) || 1178213433Shselasky *s == '-' || 1179213433Shselasky *s == '+' || 1180213433Shselasky *s == ' ' || 1181213433Shselasky *s == '.' || 1182213433Shselasky *s == ',') { 1183213433Shselasky /* allowed */ 1184213433Shselasky s++; 1185184610Salfred } 1186213433Shselasky /* silently skip bad character */ 1187184610Salfred } 1188185087Salfred *s = 0; /* zero terminate resulting string */ 1189184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1190184610Salfred} 1191184610Salfred 1192184610Salfred/*------------------------------------------------------------------------* 1193194228Sthompsa * usbd_req_get_string_desc 1194184610Salfred * 1195184610Salfred * If you don't know the language ID, consider using 1196194228Sthompsa * "usbd_req_get_string_any()". 1197184610Salfred * 1198184610Salfred * Returns: 1199184610Salfred * 0: Success 1200184610Salfred * Else: Failure 1201184610Salfred *------------------------------------------------------------------------*/ 1202193045Sthompsausb_error_t 1203194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1204184610Salfred uint16_t max_len, uint16_t lang_id, 1205184610Salfred uint8_t string_index) 1206184610Salfred{ 1207194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1208184610Salfred UDESC_STRING, string_index, 0)); 1209184610Salfred} 1210184610Salfred 1211184610Salfred/*------------------------------------------------------------------------* 1212194228Sthompsa * usbd_req_get_config_desc_ptr 1213190727Sthompsa * 1214190727Sthompsa * This function is used in device side mode to retrieve the pointer 1215190727Sthompsa * to the generated config descriptor. This saves allocating space for 1216190727Sthompsa * an additional config descriptor when setting the configuration. 1217190727Sthompsa * 1218190727Sthompsa * Returns: 1219190727Sthompsa * 0: Success 1220190727Sthompsa * Else: Failure 1221190727Sthompsa *------------------------------------------------------------------------*/ 1222193045Sthompsausb_error_t 1223194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 1224192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 1225190727Sthompsa{ 1226192984Sthompsa struct usb_device_request req; 1227193045Sthompsa usb_handle_req_t *hr_func; 1228191402Sthompsa const void *ptr; 1229190727Sthompsa uint16_t len; 1230193045Sthompsa usb_error_t err; 1231190727Sthompsa 1232190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 1233190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 1234191402Sthompsa USETW(req.wValue, wValue); 1235190727Sthompsa USETW(req.wIndex, 0); 1236190727Sthompsa USETW(req.wLength, 0); 1237190727Sthompsa 1238191402Sthompsa ptr = NULL; 1239191402Sthompsa len = 0; 1240190727Sthompsa 1241194228Sthompsa hr_func = usbd_get_hr_func(udev); 1242191402Sthompsa 1243191402Sthompsa if (hr_func == NULL) 1244191402Sthompsa err = USB_ERR_INVAL; 1245191402Sthompsa else { 1246191402Sthompsa USB_BUS_LOCK(udev->bus); 1247191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 1248191402Sthompsa USB_BUS_UNLOCK(udev->bus); 1249191402Sthompsa } 1250191402Sthompsa 1251191402Sthompsa if (err) 1252191402Sthompsa ptr = NULL; 1253191402Sthompsa else if (ptr == NULL) 1254191402Sthompsa err = USB_ERR_INVAL; 1255191402Sthompsa 1256192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1257191402Sthompsa 1258191402Sthompsa return (err); 1259190727Sthompsa} 1260190727Sthompsa 1261190727Sthompsa/*------------------------------------------------------------------------* 1262194228Sthompsa * usbd_req_get_config_desc 1263184610Salfred * 1264184610Salfred * Returns: 1265184610Salfred * 0: Success 1266184610Salfred * Else: Failure 1267184610Salfred *------------------------------------------------------------------------*/ 1268193045Sthompsausb_error_t 1269194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1270192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 1271184610Salfred{ 1272193045Sthompsa usb_error_t err; 1273184610Salfred 1274184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 1275184610Salfred 1276194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1277184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1278184610Salfred if (err) { 1279184610Salfred goto done; 1280184610Salfred } 1281184610Salfred /* Extra sanity checking */ 1282233774Shselasky if (UGETW(d->wTotalLength) < (uint16_t)sizeof(*d)) { 1283184610Salfred err = USB_ERR_INVAL; 1284184610Salfred } 1285184610Salfreddone: 1286184610Salfred return (err); 1287184610Salfred} 1288184610Salfred 1289184610Salfred/*------------------------------------------------------------------------* 1290250207Shselasky * usbd_alloc_config_desc 1291250207Shselasky * 1292250207Shselasky * This function is used to allocate a zeroed configuration 1293250207Shselasky * descriptor. 1294250207Shselasky * 1295250207Shselasky * Returns: 1296250207Shselasky * NULL: Failure 1297250207Shselasky * Else: Success 1298250207Shselasky *------------------------------------------------------------------------*/ 1299250207Shselaskyvoid * 1300250207Shselaskyusbd_alloc_config_desc(struct usb_device *udev, uint32_t size) 1301250207Shselasky{ 1302250207Shselasky if (size > USB_CONFIG_MAX) { 1303250207Shselasky DPRINTF("Configuration descriptor too big\n"); 1304250207Shselasky return (NULL); 1305250207Shselasky } 1306250207Shselasky#if (USB_HAVE_FIXED_CONFIG == 0) 1307250207Shselasky return (malloc(size, M_USBDEV, M_ZERO | M_WAITOK)); 1308250207Shselasky#else 1309250207Shselasky memset(udev->config_data, 0, sizeof(udev->config_data)); 1310250207Shselasky return (udev->config_data); 1311250207Shselasky#endif 1312250207Shselasky} 1313250207Shselasky 1314250207Shselasky/*------------------------------------------------------------------------* 1315250207Shselasky * usbd_alloc_config_desc 1316250207Shselasky * 1317250207Shselasky * This function is used to free a configuration descriptor. 1318250207Shselasky *------------------------------------------------------------------------*/ 1319250207Shselaskyvoid 1320250207Shselaskyusbd_free_config_desc(struct usb_device *udev, void *ptr) 1321250207Shselasky{ 1322250207Shselasky#if (USB_HAVE_FIXED_CONFIG == 0) 1323250207Shselasky free(ptr, M_USBDEV); 1324250207Shselasky#endif 1325250207Shselasky} 1326250207Shselasky 1327250207Shselasky/*------------------------------------------------------------------------* 1328194228Sthompsa * usbd_req_get_config_desc_full 1329184610Salfred * 1330184610Salfred * This function gets the complete USB configuration descriptor and 1331250207Shselasky * ensures that "wTotalLength" is correct. The returned configuration 1332250207Shselasky * descriptor is freed by calling "usbd_free_config_desc()". 1333184610Salfred * 1334184610Salfred * Returns: 1335184610Salfred * 0: Success 1336184610Salfred * Else: Failure 1337184610Salfred *------------------------------------------------------------------------*/ 1338193045Sthompsausb_error_t 1339194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1340250207Shselasky struct usb_config_descriptor **ppcd, uint8_t index) 1341184610Salfred{ 1342192984Sthompsa struct usb_config_descriptor cd; 1343192984Sthompsa struct usb_config_descriptor *cdesc; 1344250204Shselasky uint32_t len; 1345193045Sthompsa usb_error_t err; 1346184610Salfred 1347184610Salfred DPRINTFN(4, "index=%d\n", index); 1348184610Salfred 1349184610Salfred *ppcd = NULL; 1350184610Salfred 1351194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1352250204Shselasky if (err) 1353184610Salfred return (err); 1354250204Shselasky 1355184610Salfred /* get full descriptor */ 1356184610Salfred len = UGETW(cd.wTotalLength); 1357250204Shselasky if (len < (uint32_t)sizeof(*cdesc)) { 1358184610Salfred /* corrupt descriptor */ 1359184610Salfred return (USB_ERR_INVAL); 1360250204Shselasky } else if (len > USB_CONFIG_MAX) { 1361250204Shselasky DPRINTF("Configuration descriptor was truncated\n"); 1362250204Shselasky len = USB_CONFIG_MAX; 1363184610Salfred } 1364250207Shselasky cdesc = usbd_alloc_config_desc(udev, len); 1365250204Shselasky if (cdesc == NULL) 1366184610Salfred return (USB_ERR_NOMEM); 1367194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1368184610Salfred UDESC_CONFIG, index, 3); 1369184610Salfred if (err) { 1370250207Shselasky usbd_free_config_desc(udev, cdesc); 1371184610Salfred return (err); 1372184610Salfred } 1373184610Salfred /* make sure that the device is not fooling us: */ 1374184610Salfred USETW(cdesc->wTotalLength, len); 1375184610Salfred 1376184610Salfred *ppcd = cdesc; 1377184610Salfred 1378184610Salfred return (0); /* success */ 1379184610Salfred} 1380184610Salfred 1381184610Salfred/*------------------------------------------------------------------------* 1382194228Sthompsa * usbd_req_get_device_desc 1383184610Salfred * 1384184610Salfred * Returns: 1385184610Salfred * 0: Success 1386184610Salfred * Else: Failure 1387184610Salfred *------------------------------------------------------------------------*/ 1388193045Sthompsausb_error_t 1389194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1390192984Sthompsa struct usb_device_descriptor *d) 1391184610Salfred{ 1392184610Salfred DPRINTFN(4, "\n"); 1393194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1394184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1395184610Salfred} 1396184610Salfred 1397184610Salfred/*------------------------------------------------------------------------* 1398194228Sthompsa * usbd_req_get_alt_interface_no 1399184610Salfred * 1400184610Salfred * Returns: 1401184610Salfred * 0: Success 1402184610Salfred * Else: Failure 1403184610Salfred *------------------------------------------------------------------------*/ 1404193045Sthompsausb_error_t 1405194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1406184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 1407184610Salfred{ 1408194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1409192984Sthompsa struct usb_device_request req; 1410184610Salfred 1411195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1412184610Salfred return (USB_ERR_INVAL); 1413195963Salfred 1414184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1415184610Salfred req.bRequest = UR_GET_INTERFACE; 1416184610Salfred USETW(req.wValue, 0); 1417184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1418184610Salfred req.wIndex[1] = 0; 1419184610Salfred USETW(req.wLength, 1); 1420194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1421184610Salfred} 1422184610Salfred 1423184610Salfred/*------------------------------------------------------------------------* 1424194228Sthompsa * usbd_req_set_alt_interface_no 1425184610Salfred * 1426184610Salfred * Returns: 1427184610Salfred * 0: Success 1428184610Salfred * Else: Failure 1429184610Salfred *------------------------------------------------------------------------*/ 1430193045Sthompsausb_error_t 1431194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1432184610Salfred uint8_t iface_index, uint8_t alt_no) 1433184610Salfred{ 1434194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1435192984Sthompsa struct usb_device_request req; 1436368827Shselasky usb_error_t err; 1437184610Salfred 1438195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1439184610Salfred return (USB_ERR_INVAL); 1440195963Salfred 1441184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1442184610Salfred req.bRequest = UR_SET_INTERFACE; 1443184610Salfred req.wValue[0] = alt_no; 1444184610Salfred req.wValue[1] = 0; 1445184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1446184610Salfred req.wIndex[1] = 0; 1447184610Salfred USETW(req.wLength, 0); 1448368827Shselasky err = usbd_do_request(udev, mtx, &req, 0); 1449368827Shselasky if (err == USB_ERR_STALLED && iface->num_altsetting == 1) { 1450368827Shselasky /* 1451368827Shselasky * The USB specification chapter 9.4.10 says that USB 1452368827Shselasky * devices having only one alternate setting are 1453368827Shselasky * allowed to STALL this request. Ignore this failure. 1454368827Shselasky */ 1455368827Shselasky err = 0; 1456368827Shselasky DPRINTF("Setting default alternate number failed. (ignored)\n"); 1457368827Shselasky } 1458368827Shselasky return (err); 1459184610Salfred} 1460184610Salfred 1461184610Salfred/*------------------------------------------------------------------------* 1462194228Sthompsa * usbd_req_get_device_status 1463184610Salfred * 1464184610Salfred * Returns: 1465184610Salfred * 0: Success 1466184610Salfred * Else: Failure 1467184610Salfred *------------------------------------------------------------------------*/ 1468193045Sthompsausb_error_t 1469194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1470192984Sthompsa struct usb_status *st) 1471184610Salfred{ 1472192984Sthompsa struct usb_device_request req; 1473184610Salfred 1474184610Salfred req.bmRequestType = UT_READ_DEVICE; 1475184610Salfred req.bRequest = UR_GET_STATUS; 1476184610Salfred USETW(req.wValue, 0); 1477184610Salfred USETW(req.wIndex, 0); 1478184610Salfred USETW(req.wLength, sizeof(*st)); 1479194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1480184610Salfred} 1481184610Salfred 1482184610Salfred/*------------------------------------------------------------------------* 1483194228Sthompsa * usbd_req_get_hub_descriptor 1484184610Salfred * 1485184610Salfred * Returns: 1486184610Salfred * 0: Success 1487184610Salfred * Else: Failure 1488184610Salfred *------------------------------------------------------------------------*/ 1489193045Sthompsausb_error_t 1490194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1491192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1492184610Salfred{ 1493192984Sthompsa struct usb_device_request req; 1494184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1495184610Salfred 1496184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1497184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1498184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1499184610Salfred USETW(req.wIndex, 0); 1500184610Salfred USETW(req.wLength, len); 1501194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1502184610Salfred} 1503184610Salfred 1504184610Salfred/*------------------------------------------------------------------------* 1505213435Shselasky * usbd_req_get_ss_hub_descriptor 1506213435Shselasky * 1507213435Shselasky * Returns: 1508213435Shselasky * 0: Success 1509213435Shselasky * Else: Failure 1510213435Shselasky *------------------------------------------------------------------------*/ 1511213435Shselaskyusb_error_t 1512213435Shselaskyusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1513213435Shselasky struct usb_hub_ss_descriptor *hd, uint8_t nports) 1514213435Shselasky{ 1515213435Shselasky struct usb_device_request req; 1516213435Shselasky uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); 1517213435Shselasky 1518213435Shselasky req.bmRequestType = UT_READ_CLASS_DEVICE; 1519213435Shselasky req.bRequest = UR_GET_DESCRIPTOR; 1520213435Shselasky USETW2(req.wValue, UDESC_SS_HUB, 0); 1521213435Shselasky USETW(req.wIndex, 0); 1522213435Shselasky USETW(req.wLength, len); 1523213435Shselasky return (usbd_do_request(udev, mtx, &req, hd)); 1524213435Shselasky} 1525213435Shselasky 1526213435Shselasky/*------------------------------------------------------------------------* 1527194228Sthompsa * usbd_req_get_hub_status 1528184610Salfred * 1529184610Salfred * Returns: 1530184610Salfred * 0: Success 1531184610Salfred * Else: Failure 1532184610Salfred *------------------------------------------------------------------------*/ 1533193045Sthompsausb_error_t 1534194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1535192984Sthompsa struct usb_hub_status *st) 1536184610Salfred{ 1537192984Sthompsa struct usb_device_request req; 1538184610Salfred 1539184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1540184610Salfred req.bRequest = UR_GET_STATUS; 1541184610Salfred USETW(req.wValue, 0); 1542184610Salfred USETW(req.wIndex, 0); 1543192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1544194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1545184610Salfred} 1546184610Salfred 1547184610Salfred/*------------------------------------------------------------------------* 1548194228Sthompsa * usbd_req_set_address 1549184610Salfred * 1550184610Salfred * This function is used to set the address for an USB device. After 1551184610Salfred * port reset the USB device will respond at address zero. 1552184610Salfred * 1553184610Salfred * Returns: 1554184610Salfred * 0: Success 1555184610Salfred * Else: Failure 1556184610Salfred *------------------------------------------------------------------------*/ 1557193045Sthompsausb_error_t 1558194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1559184610Salfred{ 1560192984Sthompsa struct usb_device_request req; 1561213435Shselasky usb_error_t err; 1562184610Salfred 1563184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1564184610Salfred 1565184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1566184610Salfred req.bRequest = UR_SET_ADDRESS; 1567184610Salfred USETW(req.wValue, addr); 1568184610Salfred USETW(req.wIndex, 0); 1569184610Salfred USETW(req.wLength, 0); 1570184610Salfred 1571213435Shselasky err = USB_ERR_INVAL; 1572213435Shselasky 1573213435Shselasky /* check if USB controller handles set address */ 1574213435Shselasky if (udev->bus->methods->set_address != NULL) 1575213435Shselasky err = (udev->bus->methods->set_address) (udev, mtx, addr); 1576213435Shselasky 1577213435Shselasky if (err != USB_ERR_INVAL) 1578213435Shselasky goto done; 1579213435Shselasky 1580184610Salfred /* Setting the address should not take more than 1 second ! */ 1581213435Shselasky err = usbd_do_request_flags(udev, mtx, &req, NULL, 1582213435Shselasky USB_DELAY_STATUS_STAGE, NULL, 1000); 1583213435Shselasky 1584213435Shselaskydone: 1585213435Shselasky /* allow device time to set new address */ 1586213435Shselasky usb_pause_mtx(mtx, 1587241987Shselasky USB_MS_TO_TICKS(usb_set_address_settle)); 1588213435Shselasky 1589213435Shselasky return (err); 1590184610Salfred} 1591184610Salfred 1592184610Salfred/*------------------------------------------------------------------------* 1593194228Sthompsa * usbd_req_get_port_status 1594184610Salfred * 1595184610Salfred * Returns: 1596184610Salfred * 0: Success 1597184610Salfred * Else: Failure 1598184610Salfred *------------------------------------------------------------------------*/ 1599193045Sthompsausb_error_t 1600194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1601192984Sthompsa struct usb_port_status *ps, uint8_t port) 1602184610Salfred{ 1603192984Sthompsa struct usb_device_request req; 1604184610Salfred 1605184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1606184610Salfred req.bRequest = UR_GET_STATUS; 1607184610Salfred USETW(req.wValue, 0); 1608184610Salfred req.wIndex[0] = port; 1609184610Salfred req.wIndex[1] = 0; 1610343135Shselasky USETW(req.wLength, sizeof(*ps)); 1611343135Shselasky 1612343135Shselasky return (usbd_do_request_flags(udev, mtx, &req, ps, 0, NULL, 1000)); 1613184610Salfred} 1614184610Salfred 1615184610Salfred/*------------------------------------------------------------------------* 1616194228Sthompsa * usbd_req_clear_hub_feature 1617184610Salfred * 1618184610Salfred * Returns: 1619184610Salfred * 0: Success 1620184610Salfred * Else: Failure 1621184610Salfred *------------------------------------------------------------------------*/ 1622193045Sthompsausb_error_t 1623194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1624184610Salfred uint16_t sel) 1625184610Salfred{ 1626192984Sthompsa struct usb_device_request req; 1627184610Salfred 1628184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1629184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1630184610Salfred USETW(req.wValue, sel); 1631184610Salfred USETW(req.wIndex, 0); 1632184610Salfred USETW(req.wLength, 0); 1633194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1634184610Salfred} 1635184610Salfred 1636184610Salfred/*------------------------------------------------------------------------* 1637194228Sthompsa * usbd_req_set_hub_feature 1638184610Salfred * 1639184610Salfred * Returns: 1640184610Salfred * 0: Success 1641184610Salfred * Else: Failure 1642184610Salfred *------------------------------------------------------------------------*/ 1643193045Sthompsausb_error_t 1644194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1645184610Salfred uint16_t sel) 1646184610Salfred{ 1647192984Sthompsa struct usb_device_request req; 1648184610Salfred 1649184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1650184610Salfred req.bRequest = UR_SET_FEATURE; 1651184610Salfred USETW(req.wValue, sel); 1652184610Salfred USETW(req.wIndex, 0); 1653184610Salfred USETW(req.wLength, 0); 1654194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1655184610Salfred} 1656184610Salfred 1657184610Salfred/*------------------------------------------------------------------------* 1658213435Shselasky * usbd_req_set_hub_u1_timeout 1659213435Shselasky * 1660213435Shselasky * Returns: 1661213435Shselasky * 0: Success 1662213435Shselasky * Else: Failure 1663213435Shselasky *------------------------------------------------------------------------*/ 1664213435Shselaskyusb_error_t 1665213435Shselaskyusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, 1666213435Shselasky uint8_t port, uint8_t timeout) 1667213435Shselasky{ 1668213435Shselasky struct usb_device_request req; 1669213435Shselasky 1670213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1671213435Shselasky req.bRequest = UR_SET_FEATURE; 1672213435Shselasky USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 1673213435Shselasky req.wIndex[0] = port; 1674213435Shselasky req.wIndex[1] = timeout; 1675213435Shselasky USETW(req.wLength, 0); 1676213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1677213435Shselasky} 1678213435Shselasky 1679213435Shselasky/*------------------------------------------------------------------------* 1680213435Shselasky * usbd_req_set_hub_u2_timeout 1681213435Shselasky * 1682213435Shselasky * Returns: 1683213435Shselasky * 0: Success 1684213435Shselasky * Else: Failure 1685213435Shselasky *------------------------------------------------------------------------*/ 1686213435Shselaskyusb_error_t 1687213435Shselaskyusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, 1688213435Shselasky uint8_t port, uint8_t timeout) 1689213435Shselasky{ 1690213435Shselasky struct usb_device_request req; 1691213435Shselasky 1692213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1693213435Shselasky req.bRequest = UR_SET_FEATURE; 1694213435Shselasky USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 1695213435Shselasky req.wIndex[0] = port; 1696213435Shselasky req.wIndex[1] = timeout; 1697213435Shselasky USETW(req.wLength, 0); 1698213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1699213435Shselasky} 1700213435Shselasky 1701213435Shselasky/*------------------------------------------------------------------------* 1702213435Shselasky * usbd_req_set_hub_depth 1703213435Shselasky * 1704213435Shselasky * Returns: 1705213435Shselasky * 0: Success 1706213435Shselasky * Else: Failure 1707213435Shselasky *------------------------------------------------------------------------*/ 1708213435Shselaskyusb_error_t 1709213435Shselaskyusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, 1710213435Shselasky uint16_t depth) 1711213435Shselasky{ 1712213435Shselasky struct usb_device_request req; 1713213435Shselasky 1714213435Shselasky req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1715213435Shselasky req.bRequest = UR_SET_HUB_DEPTH; 1716213435Shselasky USETW(req.wValue, depth); 1717213435Shselasky USETW(req.wIndex, 0); 1718213435Shselasky USETW(req.wLength, 0); 1719213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1720213435Shselasky} 1721213435Shselasky 1722213435Shselasky/*------------------------------------------------------------------------* 1723194228Sthompsa * usbd_req_clear_port_feature 1724184610Salfred * 1725184610Salfred * Returns: 1726184610Salfred * 0: Success 1727184610Salfred * Else: Failure 1728184610Salfred *------------------------------------------------------------------------*/ 1729193045Sthompsausb_error_t 1730194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1731184610Salfred uint8_t port, uint16_t sel) 1732184610Salfred{ 1733192984Sthompsa struct usb_device_request req; 1734184610Salfred 1735184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1736184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1737184610Salfred USETW(req.wValue, sel); 1738184610Salfred req.wIndex[0] = port; 1739184610Salfred req.wIndex[1] = 0; 1740184610Salfred USETW(req.wLength, 0); 1741194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1742184610Salfred} 1743184610Salfred 1744184610Salfred/*------------------------------------------------------------------------* 1745194228Sthompsa * usbd_req_set_port_feature 1746184610Salfred * 1747184610Salfred * Returns: 1748184610Salfred * 0: Success 1749184610Salfred * Else: Failure 1750184610Salfred *------------------------------------------------------------------------*/ 1751193045Sthompsausb_error_t 1752194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1753184610Salfred uint8_t port, uint16_t sel) 1754184610Salfred{ 1755192984Sthompsa struct usb_device_request req; 1756184610Salfred 1757184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1758184610Salfred req.bRequest = UR_SET_FEATURE; 1759184610Salfred USETW(req.wValue, sel); 1760184610Salfred req.wIndex[0] = port; 1761184610Salfred req.wIndex[1] = 0; 1762184610Salfred USETW(req.wLength, 0); 1763194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1764184610Salfred} 1765184610Salfred 1766184610Salfred/*------------------------------------------------------------------------* 1767194228Sthompsa * usbd_req_set_protocol 1768184610Salfred * 1769184610Salfred * Returns: 1770184610Salfred * 0: Success 1771184610Salfred * Else: Failure 1772184610Salfred *------------------------------------------------------------------------*/ 1773193045Sthompsausb_error_t 1774194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1775184610Salfred uint8_t iface_index, uint16_t report) 1776184610Salfred{ 1777194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1778192984Sthompsa struct usb_device_request req; 1779184610Salfred 1780184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1781184610Salfred return (USB_ERR_INVAL); 1782184610Salfred } 1783184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1784184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1785184610Salfred 1786184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1787184610Salfred req.bRequest = UR_SET_PROTOCOL; 1788184610Salfred USETW(req.wValue, report); 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_set_report 1797184610Salfred * 1798184610Salfred * Returns: 1799184610Salfred * 0: Success 1800184610Salfred * Else: Failure 1801184610Salfred *------------------------------------------------------------------------*/ 1802193045Sthompsausb_error_t 1803194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1804184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 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 DPRINTFN(5, "len=%d\n", len); 1813184610Salfred 1814184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1815184610Salfred req.bRequest = UR_SET_REPORT; 1816184610Salfred USETW2(req.wValue, type, id); 1817184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1818184610Salfred req.wIndex[1] = 0; 1819184610Salfred USETW(req.wLength, len); 1820194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1821184610Salfred} 1822184610Salfred 1823184610Salfred/*------------------------------------------------------------------------* 1824194228Sthompsa * usbd_req_get_report 1825184610Salfred * 1826184610Salfred * Returns: 1827184610Salfred * 0: Success 1828184610Salfred * Else: Failure 1829184610Salfred *------------------------------------------------------------------------*/ 1830193045Sthompsausb_error_t 1831194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1832184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1833184610Salfred{ 1834194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1835192984Sthompsa struct usb_device_request req; 1836184610Salfred 1837224728Smav if ((iface == NULL) || (iface->idesc == NULL)) { 1838184610Salfred return (USB_ERR_INVAL); 1839184610Salfred } 1840184610Salfred DPRINTFN(5, "len=%d\n", len); 1841184610Salfred 1842184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1843184610Salfred req.bRequest = UR_GET_REPORT; 1844184610Salfred USETW2(req.wValue, type, id); 1845184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1846184610Salfred req.wIndex[1] = 0; 1847184610Salfred USETW(req.wLength, len); 1848194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1849184610Salfred} 1850184610Salfred 1851184610Salfred/*------------------------------------------------------------------------* 1852194228Sthompsa * usbd_req_set_idle 1853184610Salfred * 1854184610Salfred * Returns: 1855184610Salfred * 0: Success 1856184610Salfred * Else: Failure 1857184610Salfred *------------------------------------------------------------------------*/ 1858193045Sthompsausb_error_t 1859194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1860184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1861184610Salfred{ 1862194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1863192984Sthompsa struct usb_device_request req; 1864184610Salfred 1865184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1866184610Salfred return (USB_ERR_INVAL); 1867184610Salfred } 1868184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1869184610Salfred 1870184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1871184610Salfred req.bRequest = UR_SET_IDLE; 1872184610Salfred USETW2(req.wValue, duration, id); 1873184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1874184610Salfred req.wIndex[1] = 0; 1875184610Salfred USETW(req.wLength, 0); 1876194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1877184610Salfred} 1878184610Salfred 1879184610Salfred/*------------------------------------------------------------------------* 1880194228Sthompsa * usbd_req_get_report_descriptor 1881184610Salfred * 1882184610Salfred * Returns: 1883184610Salfred * 0: Success 1884184610Salfred * Else: Failure 1885184610Salfred *------------------------------------------------------------------------*/ 1886193045Sthompsausb_error_t 1887194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1888184610Salfred void *d, uint16_t size, uint8_t iface_index) 1889184610Salfred{ 1890194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1891192984Sthompsa struct usb_device_request req; 1892184610Salfred 1893184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1894184610Salfred return (USB_ERR_INVAL); 1895184610Salfred } 1896184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1897184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1898184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1899184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1900184610Salfred req.wIndex[1] = 0; 1901184610Salfred USETW(req.wLength, size); 1902194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1903184610Salfred} 1904184610Salfred 1905184610Salfred/*------------------------------------------------------------------------* 1906194228Sthompsa * usbd_req_set_config 1907184610Salfred * 1908184610Salfred * This function is used to select the current configuration number in 1909184610Salfred * both USB device side mode and USB host side mode. When setting the 1910184610Salfred * configuration the function of the interfaces can change. 1911184610Salfred * 1912184610Salfred * Returns: 1913184610Salfred * 0: Success 1914184610Salfred * Else: Failure 1915184610Salfred *------------------------------------------------------------------------*/ 1916193045Sthompsausb_error_t 1917194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1918184610Salfred{ 1919192984Sthompsa struct usb_device_request req; 1920184610Salfred 1921184610Salfred DPRINTF("setting config %d\n", conf); 1922184610Salfred 1923184610Salfred /* do "set configuration" request */ 1924184610Salfred 1925184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1926184610Salfred req.bRequest = UR_SET_CONFIG; 1927184610Salfred req.wValue[0] = conf; 1928184610Salfred req.wValue[1] = 0; 1929184610Salfred USETW(req.wIndex, 0); 1930184610Salfred USETW(req.wLength, 0); 1931194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1932184610Salfred} 1933184610Salfred 1934184610Salfred/*------------------------------------------------------------------------* 1935194228Sthompsa * usbd_req_get_config 1936184610Salfred * 1937184610Salfred * Returns: 1938184610Salfred * 0: Success 1939184610Salfred * Else: Failure 1940184610Salfred *------------------------------------------------------------------------*/ 1941193045Sthompsausb_error_t 1942194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1943184610Salfred{ 1944192984Sthompsa struct usb_device_request req; 1945184610Salfred 1946184610Salfred req.bmRequestType = UT_READ_DEVICE; 1947184610Salfred req.bRequest = UR_GET_CONFIG; 1948184610Salfred USETW(req.wValue, 0); 1949184610Salfred USETW(req.wIndex, 0); 1950184610Salfred USETW(req.wLength, 1); 1951194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1952184610Salfred} 1953184610Salfred 1954184610Salfred/*------------------------------------------------------------------------* 1955213435Shselasky * usbd_setup_device_desc 1956213435Shselasky *------------------------------------------------------------------------*/ 1957213435Shselaskyusb_error_t 1958213435Shselaskyusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) 1959213435Shselasky{ 1960213435Shselasky usb_error_t err; 1961213435Shselasky 1962213435Shselasky /* 1963213435Shselasky * Get the first 8 bytes of the device descriptor ! 1964213435Shselasky * 1965213435Shselasky * NOTE: "usbd_do_request()" will check the device descriptor 1966213435Shselasky * next time we do a request to see if the maximum packet size 1967213435Shselasky * changed! The 8 first bytes of the device descriptor 1968213435Shselasky * contains the maximum packet size to use on control endpoint 1969213435Shselasky * 0. If this value is different from "USB_MAX_IPACKET" a new 1970213435Shselasky * USB control request will be setup! 1971213435Shselasky */ 1972213435Shselasky switch (udev->speed) { 1973213435Shselasky case USB_SPEED_FULL: 1974248246Shselasky if (usb_full_ddesc != 0) { 1975248246Shselasky /* get full device descriptor */ 1976248246Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1977248246Shselasky if (err == 0) 1978248246Shselasky break; 1979248246Shselasky } 1980248246Shselasky 1981248246Shselasky /* get partial device descriptor, some devices crash on this */ 1982213435Shselasky err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1983213435Shselasky USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1984366887Shselasky if (err != 0) { 1985366887Shselasky DPRINTF("Trying fallback for getting the USB device descriptor\n"); 1986366887Shselasky /* try 8 bytes bMaxPacketSize */ 1987366887Shselasky udev->ddesc.bMaxPacketSize = 8; 1988366887Shselasky /* get full device descriptor */ 1989366887Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1990366887Shselasky if (err == 0) 1991366887Shselasky break; 1992366887Shselasky /* try 16 bytes bMaxPacketSize */ 1993366887Shselasky udev->ddesc.bMaxPacketSize = 16; 1994366887Shselasky /* get full device descriptor */ 1995366887Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1996366887Shselasky if (err == 0) 1997366887Shselasky break; 1998366887Shselasky /* try 32/64 bytes bMaxPacketSize */ 1999366887Shselasky udev->ddesc.bMaxPacketSize = 32; 2000366887Shselasky } 2001248246Shselasky /* get the full device descriptor */ 2002248246Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 2003213435Shselasky break; 2004248246Shselasky 2005213435Shselasky default: 2006248247Shselasky DPRINTF("Minimum bMaxPacketSize is large enough " 2007248246Shselasky "to hold the complete device descriptor or " 2008248247Shselasky "only one bMaxPacketSize choice\n"); 2009248246Shselasky 2010248246Shselasky /* get the full device descriptor */ 2011248246Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 2012248246Shselasky 2013248246Shselasky /* try one more time, if error */ 2014248246Shselasky if (err != 0) 2015248246Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 2016213435Shselasky break; 2017213435Shselasky } 2018213435Shselasky 2019248246Shselasky if (err != 0) { 2020248246Shselasky DPRINTFN(0, "getting device descriptor " 2021248246Shselasky "at addr %d failed, %s\n", udev->address, 2022248246Shselasky usbd_errstr(err)); 2023213435Shselasky return (err); 2024213435Shselasky } 2025213435Shselasky 2026213435Shselasky DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " 2027213435Shselasky "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", 2028213435Shselasky udev->address, UGETW(udev->ddesc.bcdUSB), 2029213435Shselasky udev->ddesc.bDeviceClass, 2030213435Shselasky udev->ddesc.bDeviceSubClass, 2031213435Shselasky udev->ddesc.bDeviceProtocol, 2032213435Shselasky udev->ddesc.bMaxPacketSize, 2033213435Shselasky udev->ddesc.bLength, 2034213435Shselasky udev->speed); 2035213435Shselasky 2036213435Shselasky return (err); 2037213435Shselasky} 2038213435Shselasky 2039213435Shselasky/*------------------------------------------------------------------------* 2040194228Sthompsa * usbd_req_re_enumerate 2041184610Salfred * 2042185087Salfred * NOTE: After this function returns the hardware is in the 2043185087Salfred * unconfigured state! The application is responsible for setting a 2044185087Salfred * new configuration. 2045185087Salfred * 2046184610Salfred * Returns: 2047184610Salfred * 0: Success 2048184610Salfred * Else: Failure 2049184610Salfred *------------------------------------------------------------------------*/ 2050193045Sthompsausb_error_t 2051194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 2052184610Salfred{ 2053192984Sthompsa struct usb_device *parent_hub; 2054193045Sthompsa usb_error_t err; 2055184610Salfred uint8_t old_addr; 2056186730Salfred uint8_t do_retry = 1; 2057184610Salfred 2058192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 2059185290Salfred return (USB_ERR_INVAL); 2060185290Salfred } 2061184610Salfred old_addr = udev->address; 2062184610Salfred parent_hub = udev->parent_hub; 2063184610Salfred if (parent_hub == NULL) { 2064185290Salfred return (USB_ERR_INVAL); 2065184610Salfred } 2066186730Salfredretry: 2067260589Shselasky#if USB_HAVE_TT_SUPPORT 2068222786Shselasky /* 2069222786Shselasky * Try to reset the High Speed parent HUB of a LOW- or FULL- 2070222786Shselasky * speed device, if any. 2071222786Shselasky */ 2072222786Shselasky if (udev->parent_hs_hub != NULL && 2073222786Shselasky udev->speed != USB_SPEED_HIGH) { 2074222786Shselasky DPRINTF("Trying to reset parent High Speed TT.\n"); 2075260589Shselasky if (udev->parent_hs_hub == parent_hub && 2076260589Shselasky (uhub_count_active_host_ports(parent_hub, USB_SPEED_LOW) + 2077260589Shselasky uhub_count_active_host_ports(parent_hub, USB_SPEED_FULL)) == 1) { 2078260589Shselasky /* we can reset the whole TT */ 2079260589Shselasky err = usbd_req_reset_tt(parent_hub, NULL, 2080260589Shselasky udev->hs_port_no); 2081260589Shselasky } else { 2082260589Shselasky /* only reset a particular device and endpoint */ 2083260589Shselasky err = usbd_req_clear_tt_buffer(udev->parent_hs_hub, NULL, 2084260589Shselasky udev->hs_port_no, old_addr, UE_CONTROL, 0); 2085260589Shselasky } 2086222786Shselasky if (err) { 2087222786Shselasky DPRINTF("Resetting parent High " 2088222786Shselasky "Speed TT failed (%s).\n", 2089222786Shselasky usbd_errstr(err)); 2090222786Shselasky } 2091222786Shselasky } 2092260589Shselasky#endif 2093230091Shselasky /* Try to warm reset first */ 2094230091Shselasky if (parent_hub->speed == USB_SPEED_SUPER) 2095230091Shselasky usbd_req_warm_reset_port(parent_hub, mtx, udev->port_no); 2096230091Shselasky 2097222786Shselasky /* Try to reset the parent HUB port. */ 2098194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 2099184610Salfred if (err) { 2100190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 2101194228Sthompsa old_addr, usbd_errstr(err)); 2102184610Salfred goto done; 2103184610Salfred } 2104213435Shselasky 2105184610Salfred /* 2106184610Salfred * After that the port has been reset our device should be at 2107184610Salfred * address zero: 2108184610Salfred */ 2109184610Salfred udev->address = USB_START_ADDR; 2110184610Salfred 2111185290Salfred /* reset "bMaxPacketSize" */ 2112185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 2113185290Salfred 2114213435Shselasky /* reset USB state */ 2115213435Shselasky usb_set_device_state(udev, USB_STATE_POWERED); 2116213435Shselasky 2117184610Salfred /* 2118184610Salfred * Restore device address: 2119184610Salfred */ 2120194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 2121184610Salfred if (err) { 2122184610Salfred /* XXX ignore any errors! */ 2123190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 2124194228Sthompsa old_addr, usbd_errstr(err)); 2125184610Salfred } 2126213435Shselasky /* 2127213435Shselasky * Restore device address, if the controller driver did not 2128213435Shselasky * set a new one: 2129213435Shselasky */ 2130213435Shselasky if (udev->address == USB_START_ADDR) 2131213435Shselasky udev->address = old_addr; 2132184610Salfred 2133213435Shselasky /* setup the device descriptor and the initial "wMaxPacketSize" */ 2134213435Shselasky err = usbd_setup_device_desc(udev, mtx); 2135184610Salfred 2136184610Salfreddone: 2137186730Salfred if (err && do_retry) { 2138186730Salfred /* give the USB firmware some time to load */ 2139194228Sthompsa usb_pause_mtx(mtx, hz / 2); 2140186730Salfred /* no more retries after this retry */ 2141186730Salfred do_retry = 0; 2142186730Salfred /* try again */ 2143186730Salfred goto retry; 2144186730Salfred } 2145184610Salfred /* restore address */ 2146213435Shselasky if (udev->address == USB_START_ADDR) 2147213435Shselasky udev->address = old_addr; 2148213435Shselasky /* update state, if successful */ 2149213435Shselasky if (err == 0) 2150213435Shselasky usb_set_device_state(udev, USB_STATE_ADDRESSED); 2151184610Salfred return (err); 2152184610Salfred} 2153186730Salfred 2154186730Salfred/*------------------------------------------------------------------------* 2155194228Sthompsa * usbd_req_clear_device_feature 2156186730Salfred * 2157186730Salfred * Returns: 2158186730Salfred * 0: Success 2159186730Salfred * Else: Failure 2160186730Salfred *------------------------------------------------------------------------*/ 2161193045Sthompsausb_error_t 2162194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 2163186730Salfred uint16_t sel) 2164186730Salfred{ 2165192984Sthompsa struct usb_device_request req; 2166186730Salfred 2167186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2168186730Salfred req.bRequest = UR_CLEAR_FEATURE; 2169186730Salfred USETW(req.wValue, sel); 2170186730Salfred USETW(req.wIndex, 0); 2171186730Salfred USETW(req.wLength, 0); 2172194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2173186730Salfred} 2174186730Salfred 2175186730Salfred/*------------------------------------------------------------------------* 2176194228Sthompsa * usbd_req_set_device_feature 2177186730Salfred * 2178186730Salfred * Returns: 2179186730Salfred * 0: Success 2180186730Salfred * Else: Failure 2181186730Salfred *------------------------------------------------------------------------*/ 2182193045Sthompsausb_error_t 2183194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 2184186730Salfred uint16_t sel) 2185186730Salfred{ 2186192984Sthompsa struct usb_device_request req; 2187186730Salfred 2188186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2189186730Salfred req.bRequest = UR_SET_FEATURE; 2190186730Salfred USETW(req.wValue, sel); 2191186730Salfred USETW(req.wIndex, 0); 2192186730Salfred USETW(req.wLength, 0); 2193194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2194186730Salfred} 2195222786Shselasky 2196222786Shselasky/*------------------------------------------------------------------------* 2197222786Shselasky * usbd_req_reset_tt 2198222786Shselasky * 2199222786Shselasky * Returns: 2200222786Shselasky * 0: Success 2201222786Shselasky * Else: Failure 2202222786Shselasky *------------------------------------------------------------------------*/ 2203222786Shselaskyusb_error_t 2204222786Shselaskyusbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx, 2205222786Shselasky uint8_t port) 2206222786Shselasky{ 2207222786Shselasky struct usb_device_request req; 2208222786Shselasky 2209222786Shselasky /* For single TT HUBs the port should be 1 */ 2210222786Shselasky 2211222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2212222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2213222786Shselasky port = 1; 2214222786Shselasky 2215222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2216222786Shselasky req.bRequest = UR_RESET_TT; 2217222786Shselasky USETW(req.wValue, 0); 2218222786Shselasky req.wIndex[0] = port; 2219222786Shselasky req.wIndex[1] = 0; 2220222786Shselasky USETW(req.wLength, 0); 2221222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2222222786Shselasky} 2223222786Shselasky 2224222786Shselasky/*------------------------------------------------------------------------* 2225222786Shselasky * usbd_req_clear_tt_buffer 2226222786Shselasky * 2227222786Shselasky * For single TT HUBs the port should be 1. 2228222786Shselasky * 2229222786Shselasky * Returns: 2230222786Shselasky * 0: Success 2231222786Shselasky * Else: Failure 2232222786Shselasky *------------------------------------------------------------------------*/ 2233222786Shselaskyusb_error_t 2234222786Shselaskyusbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, 2235222786Shselasky uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint) 2236222786Shselasky{ 2237222786Shselasky struct usb_device_request req; 2238222786Shselasky uint16_t wValue; 2239222786Shselasky 2240222786Shselasky /* For single TT HUBs the port should be 1 */ 2241222786Shselasky 2242222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2243222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2244222786Shselasky port = 1; 2245222786Shselasky 2246222786Shselasky wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) | 2247222786Shselasky ((endpoint & 0x80) << 8) | ((type & 3) << 12); 2248222786Shselasky 2249222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2250222786Shselasky req.bRequest = UR_CLEAR_TT_BUFFER; 2251222786Shselasky USETW(req.wValue, wValue); 2252222786Shselasky req.wIndex[0] = port; 2253222786Shselasky req.wIndex[1] = 0; 2254222786Shselasky USETW(req.wLength, 0); 2255222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2256222786Shselasky} 2257230032Shselasky 2258230032Shselasky/*------------------------------------------------------------------------* 2259230032Shselasky * usbd_req_set_port_link_state 2260230032Shselasky * 2261230032Shselasky * USB 3.0 specific request 2262230032Shselasky * 2263230032Shselasky * Returns: 2264230032Shselasky * 0: Success 2265230032Shselasky * Else: Failure 2266230032Shselasky *------------------------------------------------------------------------*/ 2267230032Shselaskyusb_error_t 2268230032Shselaskyusbd_req_set_port_link_state(struct usb_device *udev, struct mtx *mtx, 2269230032Shselasky uint8_t port, uint8_t link_state) 2270230032Shselasky{ 2271230032Shselasky struct usb_device_request req; 2272230032Shselasky 2273230032Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2274230032Shselasky req.bRequest = UR_SET_FEATURE; 2275230032Shselasky USETW(req.wValue, UHF_PORT_LINK_STATE); 2276230032Shselasky req.wIndex[0] = port; 2277230032Shselasky req.wIndex[1] = link_state; 2278230032Shselasky USETW(req.wLength, 0); 2279230032Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2280230032Shselasky} 2281233771Shselasky 2282233771Shselasky/*------------------------------------------------------------------------* 2283233771Shselasky * usbd_req_set_lpm_info 2284233771Shselasky * 2285233771Shselasky * USB 2.0 specific request for Link Power Management. 2286233771Shselasky * 2287233771Shselasky * Returns: 2288233771Shselasky * 0: Success 2289233771Shselasky * USB_ERR_PENDING_REQUESTS: NYET 2290233771Shselasky * USB_ERR_TIMEOUT: TIMEOUT 2291233771Shselasky * USB_ERR_STALL: STALL 2292233771Shselasky * Else: Failure 2293233771Shselasky *------------------------------------------------------------------------*/ 2294233771Shselaskyusb_error_t 2295233771Shselaskyusbd_req_set_lpm_info(struct usb_device *udev, struct mtx *mtx, 2296233771Shselasky uint8_t port, uint8_t besl, uint8_t addr, uint8_t rwe) 2297233771Shselasky{ 2298233771Shselasky struct usb_device_request req; 2299233771Shselasky usb_error_t err; 2300233771Shselasky uint8_t buf[1]; 2301233771Shselasky 2302233771Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2303233771Shselasky req.bRequest = UR_SET_AND_TEST; 2304233771Shselasky USETW(req.wValue, UHF_PORT_L1); 2305233771Shselasky req.wIndex[0] = (port & 0xF) | ((besl & 0xF) << 4); 2306233771Shselasky req.wIndex[1] = (addr & 0x7F) | (rwe ? 0x80 : 0x00); 2307233771Shselasky USETW(req.wLength, sizeof(buf)); 2308233771Shselasky 2309233771Shselasky /* set default value in case of short transfer */ 2310233771Shselasky buf[0] = 0x00; 2311233771Shselasky 2312233771Shselasky err = usbd_do_request(udev, mtx, &req, buf); 2313233771Shselasky if (err) 2314233771Shselasky return (err); 2315233771Shselasky 2316233771Shselasky switch (buf[0]) { 2317233771Shselasky case 0x00: /* SUCCESS */ 2318233771Shselasky break; 2319233771Shselasky case 0x10: /* NYET */ 2320233771Shselasky err = USB_ERR_PENDING_REQUESTS; 2321233771Shselasky break; 2322233771Shselasky case 0x11: /* TIMEOUT */ 2323233771Shselasky err = USB_ERR_TIMEOUT; 2324233771Shselasky break; 2325233771Shselasky case 0x30: /* STALL */ 2326233771Shselasky err = USB_ERR_STALLED; 2327233771Shselasky break; 2328233771Shselasky default: /* reserved */ 2329233771Shselasky err = USB_ERR_IOERROR; 2330233771Shselasky break; 2331233771Shselasky } 2332233771Shselasky return (err); 2333233771Shselasky} 2334233771Shselasky 2335