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