usb_request.c revision 227461
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 227461 2011-11-12 08:16:45Z hselasky $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 4184610Salfred * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 5184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer. 12184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 13184610Salfred * notice, this list of conditions and the following disclaimer in the 14184610Salfred * documentation and/or other materials provided with the distribution. 15184610Salfred * 16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26184610Salfred * SUCH DAMAGE. 27190754Sthompsa */ 28184610Salfred 29194677Sthompsa#include <sys/stdint.h> 30194677Sthompsa#include <sys/stddef.h> 31194677Sthompsa#include <sys/param.h> 32194677Sthompsa#include <sys/queue.h> 33194677Sthompsa#include <sys/types.h> 34194677Sthompsa#include <sys/systm.h> 35194677Sthompsa#include <sys/kernel.h> 36194677Sthompsa#include <sys/bus.h> 37194677Sthompsa#include <sys/module.h> 38194677Sthompsa#include <sys/lock.h> 39194677Sthompsa#include <sys/mutex.h> 40194677Sthompsa#include <sys/condvar.h> 41194677Sthompsa#include <sys/sysctl.h> 42194677Sthompsa#include <sys/sx.h> 43194677Sthompsa#include <sys/unistd.h> 44194677Sthompsa#include <sys/callout.h> 45194677Sthompsa#include <sys/malloc.h> 46194677Sthompsa#include <sys/priv.h> 47194677Sthompsa 48188942Sthompsa#include <dev/usb/usb.h> 49194677Sthompsa#include <dev/usb/usbdi.h> 50194677Sthompsa#include <dev/usb/usbdi_util.h> 51188942Sthompsa#include <dev/usb/usb_ioctl.h> 52188942Sthompsa#include <dev/usb/usbhid.h> 53184610Salfred 54194228Sthompsa#define USB_DEBUG_VAR usb_debug 55184610Salfred 56188942Sthompsa#include <dev/usb/usb_core.h> 57188942Sthompsa#include <dev/usb/usb_busdma.h> 58188942Sthompsa#include <dev/usb/usb_request.h> 59188942Sthompsa#include <dev/usb/usb_process.h> 60188942Sthompsa#include <dev/usb/usb_transfer.h> 61188942Sthompsa#include <dev/usb/usb_debug.h> 62188942Sthompsa#include <dev/usb/usb_device.h> 63188942Sthompsa#include <dev/usb/usb_util.h> 64188942Sthompsa#include <dev/usb/usb_dynamic.h> 65184610Salfred 66188942Sthompsa#include <dev/usb/usb_controller.h> 67188942Sthompsa#include <dev/usb/usb_bus.h> 68184610Salfred#include <sys/ctype.h> 69184610Salfred 70225000Shselaskystatic int usb_no_cs_fail; 71225000Shselasky 72225000ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, no_cs_fail, CTLFLAG_RW, 73225000Shselasky &usb_no_cs_fail, 0, "USB clear stall failures are ignored, if set"); 74225000Shselasky 75207077Sthompsa#ifdef USB_DEBUG 76194228Sthompsastatic int usb_pr_poll_delay = USB_PORT_RESET_DELAY; 77194228Sthompsastatic int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY; 78184610Salfred 79192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW, 80194228Sthompsa &usb_pr_poll_delay, 0, "USB port reset poll delay in ms"); 81192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, 82194228Sthompsa &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms"); 83184610Salfred 84208018Sthompsa#ifdef USB_REQ_DEBUG 85208018Sthompsa/* The following structures are used in connection to fault injection. */ 86208018Sthompsastruct usb_ctrl_debug { 87208018Sthompsa int bus_index; /* target bus */ 88208018Sthompsa int dev_index; /* target address */ 89208018Sthompsa int ds_fail; /* fail data stage */ 90208018Sthompsa int ss_fail; /* fail data stage */ 91208018Sthompsa int ds_delay; /* data stage delay in ms */ 92208018Sthompsa int ss_delay; /* status stage delay in ms */ 93208018Sthompsa int bmRequestType_value; 94208018Sthompsa int bRequest_value; 95208018Sthompsa}; 96208018Sthompsa 97208018Sthompsastruct usb_ctrl_debug_bits { 98208018Sthompsa uint16_t ds_delay; 99208018Sthompsa uint16_t ss_delay; 100208018Sthompsa uint8_t ds_fail:1; 101208018Sthompsa uint8_t ss_fail:1; 102208018Sthompsa uint8_t enabled:1; 103208018Sthompsa}; 104208018Sthompsa 105208018Sthompsa/* The default is to disable fault injection. */ 106208018Sthompsa 107208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = { 108208018Sthompsa .bus_index = -1, 109208018Sthompsa .dev_index = -1, 110208018Sthompsa .bmRequestType_value = -1, 111208018Sthompsa .bRequest_value = -1, 112208018Sthompsa}; 113208018Sthompsa 114208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW, 115208018Sthompsa &usb_ctrl_debug.bus_index, 0, "USB controller index to fail"); 116208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW, 117208018Sthompsa &usb_ctrl_debug.dev_index, 0, "USB device address to fail"); 118208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW, 119208018Sthompsa &usb_ctrl_debug.ds_fail, 0, "USB fail data stage"); 120208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW, 121208018Sthompsa &usb_ctrl_debug.ss_fail, 0, "USB fail status stage"); 122208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW, 123208018Sthompsa &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms"); 124208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW, 125208018Sthompsa &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms"); 126208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW, 127208018Sthompsa &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail"); 128208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW, 129208018Sthompsa &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail"); 130208018Sthompsa 131184610Salfred/*------------------------------------------------------------------------* 132208018Sthompsa * usbd_get_debug_bits 133208018Sthompsa * 134208018Sthompsa * This function is only useful in USB host mode. 135208018Sthompsa *------------------------------------------------------------------------*/ 136208018Sthompsastatic void 137208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, 138208018Sthompsa struct usb_ctrl_debug_bits *dbg) 139208018Sthompsa{ 140208018Sthompsa int temp; 141208018Sthompsa 142208018Sthompsa memset(dbg, 0, sizeof(*dbg)); 143208018Sthompsa 144208018Sthompsa /* Compute data stage delay */ 145208018Sthompsa 146208018Sthompsa temp = usb_ctrl_debug.ds_delay; 147208018Sthompsa if (temp < 0) 148208018Sthompsa temp = 0; 149208018Sthompsa else if (temp > (16*1024)) 150208018Sthompsa temp = (16*1024); 151208018Sthompsa 152208018Sthompsa dbg->ds_delay = temp; 153208018Sthompsa 154208018Sthompsa /* Compute status stage delay */ 155208018Sthompsa 156208018Sthompsa temp = usb_ctrl_debug.ss_delay; 157208018Sthompsa if (temp < 0) 158208018Sthompsa temp = 0; 159208018Sthompsa else if (temp > (16*1024)) 160208018Sthompsa temp = (16*1024); 161208018Sthompsa 162208018Sthompsa dbg->ss_delay = temp; 163208018Sthompsa 164208018Sthompsa /* Check if this control request should be failed */ 165208018Sthompsa 166208018Sthompsa if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) 167208018Sthompsa return; 168208018Sthompsa 169208018Sthompsa if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) 170208018Sthompsa return; 171208018Sthompsa 172208018Sthompsa temp = usb_ctrl_debug.bmRequestType_value; 173208018Sthompsa 174208018Sthompsa if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) 175208018Sthompsa return; 176208018Sthompsa 177208018Sthompsa temp = usb_ctrl_debug.bRequest_value; 178208018Sthompsa 179208018Sthompsa if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) 180208018Sthompsa return; 181208018Sthompsa 182208018Sthompsa temp = usb_ctrl_debug.ds_fail; 183208018Sthompsa if (temp) 184208018Sthompsa dbg->ds_fail = 1; 185208018Sthompsa 186208018Sthompsa temp = usb_ctrl_debug.ss_fail; 187208018Sthompsa if (temp) 188208018Sthompsa dbg->ss_fail = 1; 189208018Sthompsa 190208018Sthompsa dbg->enabled = 1; 191208018Sthompsa} 192208018Sthompsa#endif /* USB_REQ_DEBUG */ 193208018Sthompsa#endif /* USB_DEBUG */ 194208018Sthompsa 195208018Sthompsa/*------------------------------------------------------------------------* 196194228Sthompsa * usbd_do_request_callback 197184610Salfred * 198184610Salfred * This function is the USB callback for generic USB Host control 199184610Salfred * transfers. 200184610Salfred *------------------------------------------------------------------------*/ 201184610Salfredvoid 202194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error) 203184610Salfred{ 204184610Salfred ; /* workaround for a bug in "indent" */ 205184610Salfred 206184610Salfred DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 207184610Salfred 208184610Salfred switch (USB_GET_STATE(xfer)) { 209184610Salfred case USB_ST_SETUP: 210194228Sthompsa usbd_transfer_submit(xfer); 211184610Salfred break; 212184610Salfred default: 213207079Sthompsa cv_signal(&xfer->xroot->udev->ctrlreq_cv); 214184610Salfred break; 215184610Salfred } 216184610Salfred} 217184610Salfred 218184610Salfred/*------------------------------------------------------------------------* 219194228Sthompsa * usb_do_clear_stall_callback 220184610Salfred * 221184610Salfred * This function is the USB callback for generic clear stall requests. 222184610Salfred *------------------------------------------------------------------------*/ 223184610Salfredvoid 224194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 225184610Salfred{ 226192984Sthompsa struct usb_device_request req; 227192984Sthompsa struct usb_device *udev; 228193644Sthompsa struct usb_endpoint *ep; 229193644Sthompsa struct usb_endpoint *ep_end; 230193644Sthompsa struct usb_endpoint *ep_first; 231190731Sthompsa uint8_t to; 232184610Salfred 233187173Sthompsa udev = xfer->xroot->udev; 234184610Salfred 235187173Sthompsa USB_BUS_LOCK(udev->bus); 236187173Sthompsa 237193644Sthompsa /* round robin endpoint clear stall */ 238184610Salfred 239193644Sthompsa ep = udev->ep_curr; 240193644Sthompsa ep_end = udev->endpoints + udev->endpoints_max; 241193644Sthompsa ep_first = udev->endpoints; 242193644Sthompsa to = udev->endpoints_max; 243193318Sthompsa 244184610Salfred switch (USB_GET_STATE(xfer)) { 245184610Salfred case USB_ST_TRANSFERRED: 246225000Shselaskytr_transferred: 247222786Shselasky /* reset error counter */ 248222786Shselasky udev->clear_stall_errors = 0; 249222786Shselasky 250193644Sthompsa if (ep == NULL) 251193318Sthompsa goto tr_setup; /* device was unconfigured */ 252193644Sthompsa if (ep->edesc && 253193644Sthompsa ep->is_stalled) { 254193644Sthompsa ep->toggle_next = 0; 255193644Sthompsa ep->is_stalled = 0; 256213435Shselasky /* some hardware needs a callback to clear the data toggle */ 257213435Shselasky usbd_clear_stall_locked(udev, ep); 258184610Salfred /* start up the current or next transfer, if any */ 259194228Sthompsa usb_command_wrapper(&ep->endpoint_q, 260193644Sthompsa ep->endpoint_q.curr); 261184610Salfred } 262193644Sthompsa ep++; 263184610Salfred 264184610Salfred case USB_ST_SETUP: 265184610Salfredtr_setup: 266193318Sthompsa if (to == 0) 267193644Sthompsa break; /* no endpoints - nothing to do */ 268193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 269193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 270193644Sthompsa if (ep->edesc && 271193644Sthompsa ep->is_stalled) { 272184610Salfred 273184610Salfred /* setup a clear-stall packet */ 274184610Salfred 275184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 276184610Salfred req.bRequest = UR_CLEAR_FEATURE; 277184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 278193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 279184610Salfred req.wIndex[1] = 0; 280184610Salfred USETW(req.wLength, 0); 281184610Salfred 282184610Salfred /* copy in the transfer */ 283184610Salfred 284194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 285184610Salfred 286184610Salfred /* set length */ 287194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 288184610Salfred xfer->nframes = 1; 289187173Sthompsa USB_BUS_UNLOCK(udev->bus); 290184610Salfred 291194228Sthompsa usbd_transfer_submit(xfer); 292184610Salfred 293187173Sthompsa USB_BUS_LOCK(udev->bus); 294184610Salfred break; 295184610Salfred } 296193644Sthompsa ep++; 297193318Sthompsa to--; 298193318Sthompsa goto tr_setup; 299184610Salfred 300184610Salfred default: 301222786Shselasky if (error == USB_ERR_CANCELLED) 302184610Salfred break; 303222786Shselasky 304222786Shselasky DPRINTF("Clear stall failed.\n"); 305225000Shselasky 306225000Shselasky /* 307225000Shselasky * Some VMs like VirtualBox always return failure on 308225000Shselasky * clear-stall which we sometimes should just ignore. 309225000Shselasky */ 310225000Shselasky if (usb_no_cs_fail) 311225000Shselasky goto tr_transferred; 312222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) 313222786Shselasky goto tr_setup; 314222786Shselasky 315222786Shselasky if (error == USB_ERR_TIMEOUT) { 316222786Shselasky udev->clear_stall_errors = USB_CS_RESET_LIMIT; 317222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 318222786Shselasky usbd_start_re_enumerate(udev); 319222786Shselasky } else { 320222786Shselasky udev->clear_stall_errors++; 321222786Shselasky if (udev->clear_stall_errors == USB_CS_RESET_LIMIT) { 322222786Shselasky DPRINTF("Trying to re-enumerate.\n"); 323222786Shselasky usbd_start_re_enumerate(udev); 324222786Shselasky } 325184610Salfred } 326184610Salfred goto tr_setup; 327184610Salfred } 328184610Salfred 329193644Sthompsa /* store current endpoint */ 330193644Sthompsa udev->ep_curr = ep; 331187173Sthompsa USB_BUS_UNLOCK(udev->bus); 332184610Salfred} 333184610Salfred 334193045Sthompsastatic usb_handle_req_t * 335194228Sthompsausbd_get_hr_func(struct usb_device *udev) 336191402Sthompsa{ 337191402Sthompsa /* figure out if there is a Handle Request function */ 338192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 339194228Sthompsa return (usb_temp_get_desc_p); 340191402Sthompsa else if (udev->parent_hub == NULL) 341191402Sthompsa return (udev->bus->methods->roothub_exec); 342191402Sthompsa else 343191402Sthompsa return (NULL); 344191402Sthompsa} 345191402Sthompsa 346184610Salfred/*------------------------------------------------------------------------* 347194228Sthompsa * usbd_do_request_flags and usbd_do_request 348184610Salfred * 349184610Salfred * Description of arguments passed to these functions: 350184610Salfred * 351192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 352184610Salfred * request should be performed. It is possible to call this function 353184610Salfred * in both Host Side mode and Device Side mode. 354184610Salfred * 355184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 356184610Salfred * will get dropped and picked up during the execution of this 357184610Salfred * function, hence this function sometimes needs to sleep. If this 358184610Salfred * argument is NULL it has no effect. 359184610Salfred * 360184610Salfred * "req" - this argument must always be non-NULL and points to an 361184610Salfred * 8-byte structure holding the USB request to be done. The USB 362184610Salfred * request structure has a bit telling the direction of the USB 363184610Salfred * request, if it is a read or a write. 364184610Salfred * 365184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 366184610Salfred * is non-zero this argument must point to a valid kernel buffer which 367184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 368184610Salfred * be NULL. 369184610Salfred * 370184610Salfred * "flags" - here is a list of valid flags: 371184610Salfred * 372184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 373184610Salfred * specified 374184610Salfred * 375184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 376184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 377184610Salfred * sysctl. This flag is mostly useful for debugging. 378184610Salfred * 379184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 380184610Salfred * pointer. 381184610Salfred * 382184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 383184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 384184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 385184610Salfred * used. 386184610Salfred * 387184610Salfred * "timeout" - gives the timeout for the control transfer in 388184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 389184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 390184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 391184610Salfred * does not allow control requests without a timeout. 392184610Salfred * 393184610Salfred * NOTE: This function is thread safe. All calls to 394194228Sthompsa * "usbd_do_request_flags" will be serialised by the use of an 395184610Salfred * internal "sx_lock". 396184610Salfred * 397184610Salfred * Returns: 398184610Salfred * 0: Success 399184610Salfred * Else: Failure 400184610Salfred *------------------------------------------------------------------------*/ 401193045Sthompsausb_error_t 402194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 403192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 404193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 405184610Salfred{ 406208018Sthompsa#ifdef USB_REQ_DEBUG 407208018Sthompsa struct usb_ctrl_debug_bits dbg; 408208018Sthompsa#endif 409193045Sthompsa usb_handle_req_t *hr_func; 410192984Sthompsa struct usb_xfer *xfer; 411184610Salfred const void *desc; 412184610Salfred int err = 0; 413193045Sthompsa usb_ticks_t start_ticks; 414193045Sthompsa usb_ticks_t delta_ticks; 415193045Sthompsa usb_ticks_t max_ticks; 416184610Salfred uint16_t length; 417184610Salfred uint16_t temp; 418208018Sthompsa uint16_t acttemp; 419208008Sthompsa uint8_t enum_locked; 420184610Salfred 421184610Salfred if (timeout < 50) { 422184610Salfred /* timeout is too small */ 423184610Salfred timeout = 50; 424184610Salfred } 425184610Salfred if (timeout > 30000) { 426184610Salfred /* timeout is too big */ 427184610Salfred timeout = 30000; 428184610Salfred } 429184610Salfred length = UGETW(req->wLength); 430184610Salfred 431208008Sthompsa enum_locked = usbd_enum_is_locked(udev); 432208008Sthompsa 433184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 434184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 435184610Salfred udev, req->bmRequestType, req->bRequest, 436184610Salfred req->wValue[1], req->wValue[0], 437184610Salfred req->wIndex[1], req->wIndex[0], 438184610Salfred req->wLength[1], req->wLength[0]); 439184610Salfred 440191494Sthompsa /* Check if the device is still alive */ 441191494Sthompsa if (udev->state < USB_STATE_POWERED) { 442191494Sthompsa DPRINTF("usb device has gone\n"); 443191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 444191494Sthompsa } 445191494Sthompsa 446184610Salfred /* 447184610Salfred * Set "actlen" to a known value in case the caller does not 448184610Salfred * check the return value: 449184610Salfred */ 450190735Sthompsa if (actlen) 451184610Salfred *actlen = 0; 452190735Sthompsa 453190180Sthompsa#if (USB_HAVE_USER_IO == 0) 454190180Sthompsa if (flags & USB_USER_DATA_PTR) 455190180Sthompsa return (USB_ERR_INVAL); 456190180Sthompsa#endif 457208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) { 458184610Salfred mtx_unlock(mtx); 459208008Sthompsa mtx_assert(mtx, MA_NOTOWNED); 460184610Salfred } 461208008Sthompsa 462184610Salfred /* 463208008Sthompsa * We need to allow suspend and resume at this point, else the 464208008Sthompsa * control transfer will timeout if the device is suspended! 465208008Sthompsa */ 466208008Sthompsa if (enum_locked) 467208008Sthompsa usbd_sr_unlock(udev); 468208008Sthompsa 469208008Sthompsa /* 470184610Salfred * Grab the default sx-lock so that serialisation 471184610Salfred * is achieved when multiple threads are involved: 472184610Salfred */ 473207079Sthompsa sx_xlock(&udev->ctrl_sx); 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: 717207079Sthompsa sx_xunlock(&udev->ctrl_sx); 718184610Salfred 719208008Sthompsa if (enum_locked) 720208008Sthompsa usbd_sr_lock(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; 788184610Salfred 789207077Sthompsa#ifdef USB_DEBUG 790184610Salfred uint16_t pr_poll_delay; 791184610Salfred uint16_t pr_recovery_delay; 792184610Salfred 793184610Salfred#endif 794224095Shselasky /* clear any leftover port reset changes first */ 795224095Shselasky usbd_req_clear_port_feature( 796224095Shselasky udev, mtx, port, UHF_C_PORT_RESET); 797224095Shselasky 798224095Shselasky /* assert port reset on the given port */ 799224095Shselasky err = usbd_req_set_port_feature( 800224095Shselasky udev, mtx, port, UHF_PORT_RESET); 801224095Shselasky 802224095Shselasky /* check for errors */ 803224095Shselasky if (err) 804184610Salfred goto done; 805207077Sthompsa#ifdef USB_DEBUG 806184610Salfred /* range check input parameters */ 807194228Sthompsa pr_poll_delay = usb_pr_poll_delay; 808184610Salfred if (pr_poll_delay < 1) { 809184610Salfred pr_poll_delay = 1; 810184610Salfred } else if (pr_poll_delay > 1000) { 811184610Salfred pr_poll_delay = 1000; 812184610Salfred } 813194228Sthompsa pr_recovery_delay = usb_pr_recovery_delay; 814184610Salfred if (pr_recovery_delay > 1000) { 815184610Salfred pr_recovery_delay = 1000; 816184610Salfred } 817184610Salfred#endif 818184610Salfred n = 0; 819184610Salfred while (1) { 820224095Shselasky uint16_t status; 821224095Shselasky uint16_t change; 822224095Shselasky 823207077Sthompsa#ifdef USB_DEBUG 824184610Salfred /* wait for the device to recover from reset */ 825194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 826184610Salfred n += pr_poll_delay; 827184610Salfred#else 828184610Salfred /* wait for the device to recover from reset */ 829194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 830184610Salfred n += USB_PORT_RESET_DELAY; 831184610Salfred#endif 832194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 833184610Salfred if (err) { 834184610Salfred goto done; 835184610Salfred } 836224095Shselasky status = UGETW(ps.wPortStatus); 837224095Shselasky change = UGETW(ps.wPortChange); 838224095Shselasky 839216249Shselasky /* if the device disappeared, just give up */ 840224095Shselasky if (!(status & UPS_CURRENT_CONNECT_STATUS)) 841216249Shselasky goto done; 842224095Shselasky 843214804Shselasky /* check if reset is complete */ 844224095Shselasky if (change & UPS_C_PORT_RESET) 845214804Shselasky break; 846224095Shselasky 847224095Shselasky /* 848224095Shselasky * Some Virtual Machines like VirtualBox 4.x fail to 849224095Shselasky * generate a port reset change event. Check if reset 850224095Shselasky * is no longer asserted. 851224095Shselasky */ 852224095Shselasky if (!(status & UPS_RESET)) 853224095Shselasky break; 854224095Shselasky 855214804Shselasky /* check for timeout */ 856214804Shselasky if (n > 1000) { 857214804Shselasky n = 0; 858214804Shselasky break; 859214804Shselasky } 860214804Shselasky } 861214804Shselasky 862214804Shselasky /* clear port reset first */ 863214804Shselasky err = usbd_req_clear_port_feature( 864214804Shselasky udev, mtx, port, UHF_C_PORT_RESET); 865214804Shselasky if (err) { 866214804Shselasky goto done; 867214804Shselasky } 868214804Shselasky /* check for timeout */ 869214804Shselasky if (n == 0) { 870214804Shselasky err = USB_ERR_TIMEOUT; 871214804Shselasky goto done; 872214804Shselasky } 873214804Shselasky#ifdef USB_DEBUG 874214804Shselasky /* wait for the device to recover from reset */ 875214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 876214804Shselasky#else 877214804Shselasky /* wait for the device to recover from reset */ 878214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 879214804Shselasky#endif 880214804Shselasky 881214804Shselaskydone: 882214804Shselasky DPRINTFN(2, "port %d reset returning error=%s\n", 883214804Shselasky port, usbd_errstr(err)); 884214804Shselasky return (err); 885214804Shselasky} 886214804Shselasky 887214804Shselasky/*------------------------------------------------------------------------* 888214804Shselasky * usbd_req_warm_reset_port 889214804Shselasky * 890214804Shselasky * This function will instruct an USB HUB to perform a warm reset 891214804Shselasky * sequence on the specified port number. This kind of reset is not 892214804Shselasky * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted 893214804Shselasky * for SUPER-speed USB HUBs. 894214804Shselasky * 895214804Shselasky * Returns: 896214804Shselasky * 0: Success. The USB device should now be available again. 897214804Shselasky * Else: Failure. No USB device is present and the USB port should be 898214804Shselasky * disabled. 899214804Shselasky *------------------------------------------------------------------------*/ 900214804Shselaskyusb_error_t 901214804Shselaskyusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 902214804Shselasky{ 903214804Shselasky struct usb_port_status ps; 904214804Shselasky usb_error_t err; 905214804Shselasky uint16_t n; 906214804Shselasky 907214804Shselasky#ifdef USB_DEBUG 908214804Shselasky uint16_t pr_poll_delay; 909214804Shselasky uint16_t pr_recovery_delay; 910214804Shselasky 911214804Shselasky#endif 912214804Shselasky err = usbd_req_set_port_feature(udev, mtx, port, UHF_BH_PORT_RESET); 913214804Shselasky if (err) { 914214804Shselasky goto done; 915214804Shselasky } 916214804Shselasky#ifdef USB_DEBUG 917214804Shselasky /* range check input parameters */ 918214804Shselasky pr_poll_delay = usb_pr_poll_delay; 919214804Shselasky if (pr_poll_delay < 1) { 920214804Shselasky pr_poll_delay = 1; 921214804Shselasky } else if (pr_poll_delay > 1000) { 922214804Shselasky pr_poll_delay = 1000; 923214804Shselasky } 924214804Shselasky pr_recovery_delay = usb_pr_recovery_delay; 925214804Shselasky if (pr_recovery_delay > 1000) { 926214804Shselasky pr_recovery_delay = 1000; 927214804Shselasky } 928214804Shselasky#endif 929214804Shselasky n = 0; 930214804Shselasky while (1) { 931214804Shselasky#ifdef USB_DEBUG 932214804Shselasky /* wait for the device to recover from reset */ 933214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 934214804Shselasky n += pr_poll_delay; 935214804Shselasky#else 936214804Shselasky /* wait for the device to recover from reset */ 937214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 938214804Shselasky n += USB_PORT_RESET_DELAY; 939214804Shselasky#endif 940214804Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 941214804Shselasky if (err) { 942214804Shselasky goto done; 943214804Shselasky } 944184610Salfred /* if the device disappeared, just give up */ 945184610Salfred if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) { 946184610Salfred goto done; 947184610Salfred } 948184610Salfred /* check if reset is complete */ 949214804Shselasky if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) { 950184610Salfred break; 951184610Salfred } 952184610Salfred /* check for timeout */ 953184610Salfred if (n > 1000) { 954184610Salfred n = 0; 955184610Salfred break; 956184610Salfred } 957184610Salfred } 958184610Salfred 959184610Salfred /* clear port reset first */ 960194228Sthompsa err = usbd_req_clear_port_feature( 961214804Shselasky udev, mtx, port, UHF_C_BH_PORT_RESET); 962184610Salfred if (err) { 963184610Salfred goto done; 964184610Salfred } 965184610Salfred /* check for timeout */ 966184610Salfred if (n == 0) { 967184610Salfred err = USB_ERR_TIMEOUT; 968184610Salfred goto done; 969184610Salfred } 970207077Sthompsa#ifdef USB_DEBUG 971184610Salfred /* wait for the device to recover from reset */ 972194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 973184610Salfred#else 974184610Salfred /* wait for the device to recover from reset */ 975194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 976184610Salfred#endif 977184610Salfred 978184610Salfreddone: 979214804Shselasky DPRINTFN(2, "port %d warm reset returning error=%s\n", 980194228Sthompsa port, usbd_errstr(err)); 981184610Salfred return (err); 982184610Salfred} 983184610Salfred 984184610Salfred/*------------------------------------------------------------------------* 985194228Sthompsa * usbd_req_get_desc 986184610Salfred * 987184610Salfred * This function can be used to retrieve USB descriptors. It contains 988184610Salfred * some additional logic like zeroing of missing descriptor bytes and 989184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 990184610Salfred * argument specifies the minimum descriptor length. The "max_len" 991184610Salfred * argument specifies the maximum descriptor length. If the real 992184610Salfred * descriptor length is less than the minimum length the missing 993188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 994188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 995188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 996188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 997188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 998188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 999188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 1000188985Sthompsa * "max_len" then this function will try to retrive the beginning of 1001188985Sthompsa * the descriptor and base the maximum length on the first byte of the 1002188985Sthompsa * descriptor. 1003184610Salfred * 1004184610Salfred * Returns: 1005184610Salfred * 0: Success 1006184610Salfred * Else: Failure 1007184610Salfred *------------------------------------------------------------------------*/ 1008193045Sthompsausb_error_t 1009194228Sthompsausbd_req_get_desc(struct usb_device *udev, 1010188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 1011184610Salfred uint16_t min_len, uint16_t max_len, 1012184610Salfred uint16_t id, uint8_t type, uint8_t index, 1013184610Salfred uint8_t retries) 1014184610Salfred{ 1015192984Sthompsa struct usb_device_request req; 1016184610Salfred uint8_t *buf; 1017193045Sthompsa usb_error_t err; 1018184610Salfred 1019184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 1020184610Salfred id, type, index, max_len); 1021184610Salfred 1022184610Salfred req.bmRequestType = UT_READ_DEVICE; 1023184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1024184610Salfred USETW2(req.wValue, type, index); 1025184610Salfred USETW(req.wIndex, id); 1026184610Salfred 1027184610Salfred while (1) { 1028184610Salfred 1029184610Salfred if ((min_len < 2) || (max_len < 2)) { 1030184610Salfred err = USB_ERR_INVAL; 1031184610Salfred goto done; 1032184610Salfred } 1033184610Salfred USETW(req.wLength, min_len); 1034184610Salfred 1035194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 1036186730Salfred desc, 0, NULL, 1000); 1037184610Salfred 1038184610Salfred if (err) { 1039184610Salfred if (!retries) { 1040184610Salfred goto done; 1041184610Salfred } 1042184610Salfred retries--; 1043184610Salfred 1044194228Sthompsa usb_pause_mtx(mtx, hz / 5); 1045184610Salfred 1046184610Salfred continue; 1047184610Salfred } 1048184610Salfred buf = desc; 1049184610Salfred 1050184610Salfred if (min_len == max_len) { 1051184610Salfred 1052188985Sthompsa /* enforce correct length */ 1053188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 1054188985Sthompsa buf[0] = min_len; 1055184610Salfred 1056188985Sthompsa /* enforce correct type */ 1057184610Salfred buf[1] = type; 1058184610Salfred 1059184610Salfred goto done; 1060184610Salfred } 1061184610Salfred /* range check */ 1062184610Salfred 1063184610Salfred if (max_len > buf[0]) { 1064184610Salfred max_len = buf[0]; 1065184610Salfred } 1066184610Salfred /* zero minimum data */ 1067184610Salfred 1068184610Salfred while (min_len > max_len) { 1069184610Salfred min_len--; 1070184610Salfred buf[min_len] = 0; 1071184610Salfred } 1072184610Salfred 1073184610Salfred /* set new minimum length */ 1074184610Salfred 1075184610Salfred min_len = max_len; 1076184610Salfred } 1077184610Salfreddone: 1078188985Sthompsa if (actlen != NULL) { 1079188985Sthompsa if (err) 1080188985Sthompsa *actlen = 0; 1081188985Sthompsa else 1082188985Sthompsa *actlen = min_len; 1083188985Sthompsa } 1084184610Salfred return (err); 1085184610Salfred} 1086184610Salfred 1087184610Salfred/*------------------------------------------------------------------------* 1088194228Sthompsa * usbd_req_get_string_any 1089184610Salfred * 1090184610Salfred * This function will return the string given by "string_index" 1091184610Salfred * using the first language ID. The maximum length "len" includes 1092184610Salfred * the terminating zero. The "len" argument should be twice as 1093184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 1094184610Salfred * 1095184610Salfred * Returns: 1096184610Salfred * 0: Success 1097184610Salfred * Else: Failure 1098184610Salfred *------------------------------------------------------------------------*/ 1099193045Sthompsausb_error_t 1100194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 1101184610Salfred uint16_t len, uint8_t string_index) 1102184610Salfred{ 1103184610Salfred char *s; 1104184610Salfred uint8_t *temp; 1105184610Salfred uint16_t i; 1106184610Salfred uint16_t n; 1107184610Salfred uint16_t c; 1108184610Salfred uint8_t swap; 1109193045Sthompsa usb_error_t err; 1110184610Salfred 1111184610Salfred if (len == 0) { 1112184610Salfred /* should not happen */ 1113184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1114184610Salfred } 1115184610Salfred if (string_index == 0) { 1116184610Salfred /* this is the language table */ 1117185087Salfred buf[0] = 0; 1118184610Salfred return (USB_ERR_INVAL); 1119184610Salfred } 1120184610Salfred if (udev->flags.no_strings) { 1121185087Salfred buf[0] = 0; 1122184610Salfred return (USB_ERR_STALLED); 1123184610Salfred } 1124194228Sthompsa err = usbd_req_get_string_desc 1125184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 1126184610Salfred if (err) { 1127185087Salfred buf[0] = 0; 1128184610Salfred return (err); 1129184610Salfred } 1130184610Salfred temp = (uint8_t *)buf; 1131184610Salfred 1132184610Salfred if (temp[0] < 2) { 1133184610Salfred /* string length is too short */ 1134185087Salfred buf[0] = 0; 1135184610Salfred return (USB_ERR_INVAL); 1136184610Salfred } 1137184610Salfred /* reserve one byte for terminating zero */ 1138184610Salfred len--; 1139184610Salfred 1140184610Salfred /* find maximum length */ 1141184610Salfred s = buf; 1142184610Salfred n = (temp[0] / 2) - 1; 1143184610Salfred if (n > len) { 1144184610Salfred n = len; 1145184610Salfred } 1146184610Salfred /* skip descriptor header */ 1147184610Salfred temp += 2; 1148184610Salfred 1149184610Salfred /* reset swap state */ 1150184610Salfred swap = 3; 1151184610Salfred 1152184610Salfred /* convert and filter */ 1153184610Salfred for (i = 0; (i != n); i++) { 1154184610Salfred c = UGETW(temp + (2 * i)); 1155184610Salfred 1156184610Salfred /* convert from Unicode, handle buggy strings */ 1157184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 1158184610Salfred /* Little Endian, default */ 1159184610Salfred *s = c; 1160184610Salfred swap = 1; 1161184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1162184610Salfred /* Big Endian */ 1163184610Salfred *s = c >> 8; 1164184610Salfred swap = 2; 1165184610Salfred } else { 1166185087Salfred /* silently skip bad character */ 1167185087Salfred continue; 1168184610Salfred } 1169184610Salfred 1170184610Salfred /* 1171213433Shselasky * Filter by default - We only allow alphanumerical 1172213433Shselasky * and a few more to avoid any problems with scripts 1173213433Shselasky * and daemons. 1174184610Salfred */ 1175213433Shselasky if (isalpha(*s) || 1176213433Shselasky isdigit(*s) || 1177213433Shselasky *s == '-' || 1178213433Shselasky *s == '+' || 1179213433Shselasky *s == ' ' || 1180213433Shselasky *s == '.' || 1181213433Shselasky *s == ',') { 1182213433Shselasky /* allowed */ 1183213433Shselasky s++; 1184184610Salfred } 1185213433Shselasky /* silently skip bad character */ 1186184610Salfred } 1187185087Salfred *s = 0; /* zero terminate resulting string */ 1188184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1189184610Salfred} 1190184610Salfred 1191184610Salfred/*------------------------------------------------------------------------* 1192194228Sthompsa * usbd_req_get_string_desc 1193184610Salfred * 1194184610Salfred * If you don't know the language ID, consider using 1195194228Sthompsa * "usbd_req_get_string_any()". 1196184610Salfred * 1197184610Salfred * Returns: 1198184610Salfred * 0: Success 1199184610Salfred * Else: Failure 1200184610Salfred *------------------------------------------------------------------------*/ 1201193045Sthompsausb_error_t 1202194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1203184610Salfred uint16_t max_len, uint16_t lang_id, 1204184610Salfred uint8_t string_index) 1205184610Salfred{ 1206194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1207184610Salfred UDESC_STRING, string_index, 0)); 1208184610Salfred} 1209184610Salfred 1210184610Salfred/*------------------------------------------------------------------------* 1211194228Sthompsa * usbd_req_get_config_desc_ptr 1212190727Sthompsa * 1213190727Sthompsa * This function is used in device side mode to retrieve the pointer 1214190727Sthompsa * to the generated config descriptor. This saves allocating space for 1215190727Sthompsa * an additional config descriptor when setting the configuration. 1216190727Sthompsa * 1217190727Sthompsa * Returns: 1218190727Sthompsa * 0: Success 1219190727Sthompsa * Else: Failure 1220190727Sthompsa *------------------------------------------------------------------------*/ 1221193045Sthompsausb_error_t 1222194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 1223192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 1224190727Sthompsa{ 1225192984Sthompsa struct usb_device_request req; 1226193045Sthompsa usb_handle_req_t *hr_func; 1227191402Sthompsa const void *ptr; 1228190727Sthompsa uint16_t len; 1229193045Sthompsa usb_error_t err; 1230190727Sthompsa 1231190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 1232190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 1233191402Sthompsa USETW(req.wValue, wValue); 1234190727Sthompsa USETW(req.wIndex, 0); 1235190727Sthompsa USETW(req.wLength, 0); 1236190727Sthompsa 1237191402Sthompsa ptr = NULL; 1238191402Sthompsa len = 0; 1239190727Sthompsa 1240194228Sthompsa hr_func = usbd_get_hr_func(udev); 1241191402Sthompsa 1242191402Sthompsa if (hr_func == NULL) 1243191402Sthompsa err = USB_ERR_INVAL; 1244191402Sthompsa else { 1245191402Sthompsa USB_BUS_LOCK(udev->bus); 1246191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 1247191402Sthompsa USB_BUS_UNLOCK(udev->bus); 1248191402Sthompsa } 1249191402Sthompsa 1250191402Sthompsa if (err) 1251191402Sthompsa ptr = NULL; 1252191402Sthompsa else if (ptr == NULL) 1253191402Sthompsa err = USB_ERR_INVAL; 1254191402Sthompsa 1255192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1256191402Sthompsa 1257191402Sthompsa return (err); 1258190727Sthompsa} 1259190727Sthompsa 1260190727Sthompsa/*------------------------------------------------------------------------* 1261194228Sthompsa * usbd_req_get_config_desc 1262184610Salfred * 1263184610Salfred * Returns: 1264184610Salfred * 0: Success 1265184610Salfred * Else: Failure 1266184610Salfred *------------------------------------------------------------------------*/ 1267193045Sthompsausb_error_t 1268194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1269192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 1270184610Salfred{ 1271193045Sthompsa usb_error_t err; 1272184610Salfred 1273184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 1274184610Salfred 1275194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1276184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1277184610Salfred if (err) { 1278184610Salfred goto done; 1279184610Salfred } 1280184610Salfred /* Extra sanity checking */ 1281184610Salfred if (UGETW(d->wTotalLength) < sizeof(*d)) { 1282184610Salfred err = USB_ERR_INVAL; 1283184610Salfred } 1284184610Salfreddone: 1285184610Salfred return (err); 1286184610Salfred} 1287184610Salfred 1288184610Salfred/*------------------------------------------------------------------------* 1289194228Sthompsa * usbd_req_get_config_desc_full 1290184610Salfred * 1291184610Salfred * This function gets the complete USB configuration descriptor and 1292184610Salfred * ensures that "wTotalLength" is correct. 1293184610Salfred * 1294184610Salfred * Returns: 1295184610Salfred * 0: Success 1296184610Salfred * Else: Failure 1297184610Salfred *------------------------------------------------------------------------*/ 1298193045Sthompsausb_error_t 1299194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1300192984Sthompsa struct usb_config_descriptor **ppcd, struct malloc_type *mtype, 1301184610Salfred uint8_t index) 1302184610Salfred{ 1303192984Sthompsa struct usb_config_descriptor cd; 1304192984Sthompsa struct usb_config_descriptor *cdesc; 1305184610Salfred uint16_t len; 1306193045Sthompsa usb_error_t err; 1307184610Salfred 1308184610Salfred DPRINTFN(4, "index=%d\n", index); 1309184610Salfred 1310184610Salfred *ppcd = NULL; 1311184610Salfred 1312194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1313184610Salfred if (err) { 1314184610Salfred return (err); 1315184610Salfred } 1316184610Salfred /* get full descriptor */ 1317184610Salfred len = UGETW(cd.wTotalLength); 1318184610Salfred if (len < sizeof(*cdesc)) { 1319184610Salfred /* corrupt descriptor */ 1320184610Salfred return (USB_ERR_INVAL); 1321184610Salfred } 1322184610Salfred cdesc = malloc(len, mtype, M_WAITOK); 1323184610Salfred if (cdesc == NULL) { 1324184610Salfred return (USB_ERR_NOMEM); 1325184610Salfred } 1326194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1327184610Salfred UDESC_CONFIG, index, 3); 1328184610Salfred if (err) { 1329184610Salfred free(cdesc, mtype); 1330184610Salfred return (err); 1331184610Salfred } 1332184610Salfred /* make sure that the device is not fooling us: */ 1333184610Salfred USETW(cdesc->wTotalLength, len); 1334184610Salfred 1335184610Salfred *ppcd = cdesc; 1336184610Salfred 1337184610Salfred return (0); /* success */ 1338184610Salfred} 1339184610Salfred 1340184610Salfred/*------------------------------------------------------------------------* 1341194228Sthompsa * usbd_req_get_device_desc 1342184610Salfred * 1343184610Salfred * Returns: 1344184610Salfred * 0: Success 1345184610Salfred * Else: Failure 1346184610Salfred *------------------------------------------------------------------------*/ 1347193045Sthompsausb_error_t 1348194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1349192984Sthompsa struct usb_device_descriptor *d) 1350184610Salfred{ 1351184610Salfred DPRINTFN(4, "\n"); 1352194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1353184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1354184610Salfred} 1355184610Salfred 1356184610Salfred/*------------------------------------------------------------------------* 1357194228Sthompsa * usbd_req_get_alt_interface_no 1358184610Salfred * 1359184610Salfred * Returns: 1360184610Salfred * 0: Success 1361184610Salfred * Else: Failure 1362184610Salfred *------------------------------------------------------------------------*/ 1363193045Sthompsausb_error_t 1364194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1365184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 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_READ_INTERFACE; 1374184610Salfred req.bRequest = UR_GET_INTERFACE; 1375184610Salfred USETW(req.wValue, 0); 1376184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1377184610Salfred req.wIndex[1] = 0; 1378184610Salfred USETW(req.wLength, 1); 1379194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1380184610Salfred} 1381184610Salfred 1382184610Salfred/*------------------------------------------------------------------------* 1383194228Sthompsa * usbd_req_set_alt_interface_no 1384184610Salfred * 1385184610Salfred * Returns: 1386184610Salfred * 0: Success 1387184610Salfred * Else: Failure 1388184610Salfred *------------------------------------------------------------------------*/ 1389193045Sthompsausb_error_t 1390194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1391184610Salfred uint8_t iface_index, uint8_t alt_no) 1392184610Salfred{ 1393194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1394192984Sthompsa struct usb_device_request req; 1395184610Salfred 1396195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1397184610Salfred return (USB_ERR_INVAL); 1398195963Salfred 1399184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1400184610Salfred req.bRequest = UR_SET_INTERFACE; 1401184610Salfred req.wValue[0] = alt_no; 1402184610Salfred req.wValue[1] = 0; 1403184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1404184610Salfred req.wIndex[1] = 0; 1405184610Salfred USETW(req.wLength, 0); 1406194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1407184610Salfred} 1408184610Salfred 1409184610Salfred/*------------------------------------------------------------------------* 1410194228Sthompsa * usbd_req_get_device_status 1411184610Salfred * 1412184610Salfred * Returns: 1413184610Salfred * 0: Success 1414184610Salfred * Else: Failure 1415184610Salfred *------------------------------------------------------------------------*/ 1416193045Sthompsausb_error_t 1417194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1418192984Sthompsa struct usb_status *st) 1419184610Salfred{ 1420192984Sthompsa struct usb_device_request req; 1421184610Salfred 1422184610Salfred req.bmRequestType = UT_READ_DEVICE; 1423184610Salfred req.bRequest = UR_GET_STATUS; 1424184610Salfred USETW(req.wValue, 0); 1425184610Salfred USETW(req.wIndex, 0); 1426184610Salfred USETW(req.wLength, sizeof(*st)); 1427194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1428184610Salfred} 1429184610Salfred 1430184610Salfred/*------------------------------------------------------------------------* 1431194228Sthompsa * usbd_req_get_hub_descriptor 1432184610Salfred * 1433184610Salfred * Returns: 1434184610Salfred * 0: Success 1435184610Salfred * Else: Failure 1436184610Salfred *------------------------------------------------------------------------*/ 1437193045Sthompsausb_error_t 1438194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1439192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1440184610Salfred{ 1441192984Sthompsa struct usb_device_request req; 1442184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1443184610Salfred 1444184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1445184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1446184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1447184610Salfred USETW(req.wIndex, 0); 1448184610Salfred USETW(req.wLength, len); 1449194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1450184610Salfred} 1451184610Salfred 1452184610Salfred/*------------------------------------------------------------------------* 1453213435Shselasky * usbd_req_get_ss_hub_descriptor 1454213435Shselasky * 1455213435Shselasky * Returns: 1456213435Shselasky * 0: Success 1457213435Shselasky * Else: Failure 1458213435Shselasky *------------------------------------------------------------------------*/ 1459213435Shselaskyusb_error_t 1460213435Shselaskyusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1461213435Shselasky struct usb_hub_ss_descriptor *hd, uint8_t nports) 1462213435Shselasky{ 1463213435Shselasky struct usb_device_request req; 1464213435Shselasky uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); 1465213435Shselasky 1466213435Shselasky req.bmRequestType = UT_READ_CLASS_DEVICE; 1467213435Shselasky req.bRequest = UR_GET_DESCRIPTOR; 1468213435Shselasky USETW2(req.wValue, UDESC_SS_HUB, 0); 1469213435Shselasky USETW(req.wIndex, 0); 1470213435Shselasky USETW(req.wLength, len); 1471213435Shselasky return (usbd_do_request(udev, mtx, &req, hd)); 1472213435Shselasky} 1473213435Shselasky 1474213435Shselasky/*------------------------------------------------------------------------* 1475194228Sthompsa * usbd_req_get_hub_status 1476184610Salfred * 1477184610Salfred * Returns: 1478184610Salfred * 0: Success 1479184610Salfred * Else: Failure 1480184610Salfred *------------------------------------------------------------------------*/ 1481193045Sthompsausb_error_t 1482194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1483192984Sthompsa struct usb_hub_status *st) 1484184610Salfred{ 1485192984Sthompsa struct usb_device_request req; 1486184610Salfred 1487184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1488184610Salfred req.bRequest = UR_GET_STATUS; 1489184610Salfred USETW(req.wValue, 0); 1490184610Salfred USETW(req.wIndex, 0); 1491192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1492194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1493184610Salfred} 1494184610Salfred 1495184610Salfred/*------------------------------------------------------------------------* 1496194228Sthompsa * usbd_req_set_address 1497184610Salfred * 1498184610Salfred * This function is used to set the address for an USB device. After 1499184610Salfred * port reset the USB device will respond at address zero. 1500184610Salfred * 1501184610Salfred * Returns: 1502184610Salfred * 0: Success 1503184610Salfred * Else: Failure 1504184610Salfred *------------------------------------------------------------------------*/ 1505193045Sthompsausb_error_t 1506194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1507184610Salfred{ 1508192984Sthompsa struct usb_device_request req; 1509213435Shselasky usb_error_t err; 1510184610Salfred 1511184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1512184610Salfred 1513184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1514184610Salfred req.bRequest = UR_SET_ADDRESS; 1515184610Salfred USETW(req.wValue, addr); 1516184610Salfred USETW(req.wIndex, 0); 1517184610Salfred USETW(req.wLength, 0); 1518184610Salfred 1519213435Shselasky err = USB_ERR_INVAL; 1520213435Shselasky 1521213435Shselasky /* check if USB controller handles set address */ 1522213435Shselasky if (udev->bus->methods->set_address != NULL) 1523213435Shselasky err = (udev->bus->methods->set_address) (udev, mtx, addr); 1524213435Shselasky 1525213435Shselasky if (err != USB_ERR_INVAL) 1526213435Shselasky goto done; 1527213435Shselasky 1528184610Salfred /* Setting the address should not take more than 1 second ! */ 1529213435Shselasky err = usbd_do_request_flags(udev, mtx, &req, NULL, 1530213435Shselasky USB_DELAY_STATUS_STAGE, NULL, 1000); 1531213435Shselasky 1532213435Shselaskydone: 1533213435Shselasky /* allow device time to set new address */ 1534213435Shselasky usb_pause_mtx(mtx, 1535213435Shselasky USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); 1536213435Shselasky 1537213435Shselasky return (err); 1538184610Salfred} 1539184610Salfred 1540184610Salfred/*------------------------------------------------------------------------* 1541194228Sthompsa * usbd_req_get_port_status 1542184610Salfred * 1543184610Salfred * Returns: 1544184610Salfred * 0: Success 1545184610Salfred * Else: Failure 1546184610Salfred *------------------------------------------------------------------------*/ 1547193045Sthompsausb_error_t 1548194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1549192984Sthompsa struct usb_port_status *ps, uint8_t port) 1550184610Salfred{ 1551192984Sthompsa struct usb_device_request req; 1552184610Salfred 1553184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1554184610Salfred req.bRequest = UR_GET_STATUS; 1555184610Salfred USETW(req.wValue, 0); 1556184610Salfred req.wIndex[0] = port; 1557184610Salfred req.wIndex[1] = 0; 1558184610Salfred USETW(req.wLength, sizeof *ps); 1559194228Sthompsa return (usbd_do_request(udev, mtx, &req, ps)); 1560184610Salfred} 1561184610Salfred 1562184610Salfred/*------------------------------------------------------------------------* 1563194228Sthompsa * usbd_req_clear_hub_feature 1564184610Salfred * 1565184610Salfred * Returns: 1566184610Salfred * 0: Success 1567184610Salfred * Else: Failure 1568184610Salfred *------------------------------------------------------------------------*/ 1569193045Sthompsausb_error_t 1570194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1571184610Salfred uint16_t sel) 1572184610Salfred{ 1573192984Sthompsa struct usb_device_request req; 1574184610Salfred 1575184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1576184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1577184610Salfred USETW(req.wValue, sel); 1578184610Salfred USETW(req.wIndex, 0); 1579184610Salfred USETW(req.wLength, 0); 1580194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1581184610Salfred} 1582184610Salfred 1583184610Salfred/*------------------------------------------------------------------------* 1584194228Sthompsa * usbd_req_set_hub_feature 1585184610Salfred * 1586184610Salfred * Returns: 1587184610Salfred * 0: Success 1588184610Salfred * Else: Failure 1589184610Salfred *------------------------------------------------------------------------*/ 1590193045Sthompsausb_error_t 1591194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1592184610Salfred uint16_t sel) 1593184610Salfred{ 1594192984Sthompsa struct usb_device_request req; 1595184610Salfred 1596184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1597184610Salfred req.bRequest = UR_SET_FEATURE; 1598184610Salfred USETW(req.wValue, sel); 1599184610Salfred USETW(req.wIndex, 0); 1600184610Salfred USETW(req.wLength, 0); 1601194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1602184610Salfred} 1603184610Salfred 1604184610Salfred/*------------------------------------------------------------------------* 1605213435Shselasky * usbd_req_set_hub_u1_timeout 1606213435Shselasky * 1607213435Shselasky * Returns: 1608213435Shselasky * 0: Success 1609213435Shselasky * Else: Failure 1610213435Shselasky *------------------------------------------------------------------------*/ 1611213435Shselaskyusb_error_t 1612213435Shselaskyusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, 1613213435Shselasky uint8_t port, uint8_t timeout) 1614213435Shselasky{ 1615213435Shselasky struct usb_device_request req; 1616213435Shselasky 1617213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1618213435Shselasky req.bRequest = UR_SET_FEATURE; 1619213435Shselasky USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 1620213435Shselasky req.wIndex[0] = port; 1621213435Shselasky req.wIndex[1] = timeout; 1622213435Shselasky USETW(req.wLength, 0); 1623213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1624213435Shselasky} 1625213435Shselasky 1626213435Shselasky/*------------------------------------------------------------------------* 1627213435Shselasky * usbd_req_set_hub_u2_timeout 1628213435Shselasky * 1629213435Shselasky * Returns: 1630213435Shselasky * 0: Success 1631213435Shselasky * Else: Failure 1632213435Shselasky *------------------------------------------------------------------------*/ 1633213435Shselaskyusb_error_t 1634213435Shselaskyusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, 1635213435Shselasky uint8_t port, uint8_t timeout) 1636213435Shselasky{ 1637213435Shselasky struct usb_device_request req; 1638213435Shselasky 1639213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1640213435Shselasky req.bRequest = UR_SET_FEATURE; 1641213435Shselasky USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 1642213435Shselasky req.wIndex[0] = port; 1643213435Shselasky req.wIndex[1] = timeout; 1644213435Shselasky USETW(req.wLength, 0); 1645213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1646213435Shselasky} 1647213435Shselasky 1648213435Shselasky/*------------------------------------------------------------------------* 1649213435Shselasky * usbd_req_set_hub_depth 1650213435Shselasky * 1651213435Shselasky * Returns: 1652213435Shselasky * 0: Success 1653213435Shselasky * Else: Failure 1654213435Shselasky *------------------------------------------------------------------------*/ 1655213435Shselaskyusb_error_t 1656213435Shselaskyusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, 1657213435Shselasky uint16_t depth) 1658213435Shselasky{ 1659213435Shselasky struct usb_device_request req; 1660213435Shselasky 1661213435Shselasky req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1662213435Shselasky req.bRequest = UR_SET_HUB_DEPTH; 1663213435Shselasky USETW(req.wValue, depth); 1664213435Shselasky USETW(req.wIndex, 0); 1665213435Shselasky USETW(req.wLength, 0); 1666213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1667213435Shselasky} 1668213435Shselasky 1669213435Shselasky/*------------------------------------------------------------------------* 1670194228Sthompsa * usbd_req_clear_port_feature 1671184610Salfred * 1672184610Salfred * Returns: 1673184610Salfred * 0: Success 1674184610Salfred * Else: Failure 1675184610Salfred *------------------------------------------------------------------------*/ 1676193045Sthompsausb_error_t 1677194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1678184610Salfred uint8_t port, uint16_t sel) 1679184610Salfred{ 1680192984Sthompsa struct usb_device_request req; 1681184610Salfred 1682184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1683184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1684184610Salfred USETW(req.wValue, sel); 1685184610Salfred req.wIndex[0] = port; 1686184610Salfred req.wIndex[1] = 0; 1687184610Salfred USETW(req.wLength, 0); 1688194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1689184610Salfred} 1690184610Salfred 1691184610Salfred/*------------------------------------------------------------------------* 1692194228Sthompsa * usbd_req_set_port_feature 1693184610Salfred * 1694184610Salfred * Returns: 1695184610Salfred * 0: Success 1696184610Salfred * Else: Failure 1697184610Salfred *------------------------------------------------------------------------*/ 1698193045Sthompsausb_error_t 1699194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1700184610Salfred uint8_t port, uint16_t sel) 1701184610Salfred{ 1702192984Sthompsa struct usb_device_request req; 1703184610Salfred 1704184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1705184610Salfred req.bRequest = UR_SET_FEATURE; 1706184610Salfred USETW(req.wValue, sel); 1707184610Salfred req.wIndex[0] = port; 1708184610Salfred req.wIndex[1] = 0; 1709184610Salfred USETW(req.wLength, 0); 1710194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1711184610Salfred} 1712184610Salfred 1713184610Salfred/*------------------------------------------------------------------------* 1714194228Sthompsa * usbd_req_set_protocol 1715184610Salfred * 1716184610Salfred * Returns: 1717184610Salfred * 0: Success 1718184610Salfred * Else: Failure 1719184610Salfred *------------------------------------------------------------------------*/ 1720193045Sthompsausb_error_t 1721194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1722184610Salfred uint8_t iface_index, uint16_t report) 1723184610Salfred{ 1724194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1725192984Sthompsa struct usb_device_request req; 1726184610Salfred 1727184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1728184610Salfred return (USB_ERR_INVAL); 1729184610Salfred } 1730184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1731184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1732184610Salfred 1733184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1734184610Salfred req.bRequest = UR_SET_PROTOCOL; 1735184610Salfred USETW(req.wValue, report); 1736184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1737184610Salfred req.wIndex[1] = 0; 1738184610Salfred USETW(req.wLength, 0); 1739194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1740184610Salfred} 1741184610Salfred 1742184610Salfred/*------------------------------------------------------------------------* 1743194228Sthompsa * usbd_req_set_report 1744184610Salfred * 1745184610Salfred * Returns: 1746184610Salfred * 0: Success 1747184610Salfred * Else: Failure 1748184610Salfred *------------------------------------------------------------------------*/ 1749193045Sthompsausb_error_t 1750194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1751184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 1752184610Salfred{ 1753194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1754192984Sthompsa struct usb_device_request req; 1755184610Salfred 1756184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1757184610Salfred return (USB_ERR_INVAL); 1758184610Salfred } 1759184610Salfred DPRINTFN(5, "len=%d\n", len); 1760184610Salfred 1761184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1762184610Salfred req.bRequest = UR_SET_REPORT; 1763184610Salfred USETW2(req.wValue, type, id); 1764184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1765184610Salfred req.wIndex[1] = 0; 1766184610Salfred USETW(req.wLength, len); 1767194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1768184610Salfred} 1769184610Salfred 1770184610Salfred/*------------------------------------------------------------------------* 1771194228Sthompsa * usbd_req_get_report 1772184610Salfred * 1773184610Salfred * Returns: 1774184610Salfred * 0: Success 1775184610Salfred * Else: Failure 1776184610Salfred *------------------------------------------------------------------------*/ 1777193045Sthompsausb_error_t 1778194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1779184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1780184610Salfred{ 1781194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1782192984Sthompsa struct usb_device_request req; 1783184610Salfred 1784224728Smav if ((iface == NULL) || (iface->idesc == NULL)) { 1785184610Salfred return (USB_ERR_INVAL); 1786184610Salfred } 1787184610Salfred DPRINTFN(5, "len=%d\n", len); 1788184610Salfred 1789184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1790184610Salfred req.bRequest = UR_GET_REPORT; 1791184610Salfred USETW2(req.wValue, type, id); 1792184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1793184610Salfred req.wIndex[1] = 0; 1794184610Salfred USETW(req.wLength, len); 1795194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1796184610Salfred} 1797184610Salfred 1798184610Salfred/*------------------------------------------------------------------------* 1799194228Sthompsa * usbd_req_set_idle 1800184610Salfred * 1801184610Salfred * Returns: 1802184610Salfred * 0: Success 1803184610Salfred * Else: Failure 1804184610Salfred *------------------------------------------------------------------------*/ 1805193045Sthompsausb_error_t 1806194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1807184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1808184610Salfred{ 1809194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1810192984Sthompsa struct usb_device_request req; 1811184610Salfred 1812184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1813184610Salfred return (USB_ERR_INVAL); 1814184610Salfred } 1815184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1816184610Salfred 1817184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1818184610Salfred req.bRequest = UR_SET_IDLE; 1819184610Salfred USETW2(req.wValue, duration, id); 1820184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1821184610Salfred req.wIndex[1] = 0; 1822184610Salfred USETW(req.wLength, 0); 1823194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1824184610Salfred} 1825184610Salfred 1826184610Salfred/*------------------------------------------------------------------------* 1827194228Sthompsa * usbd_req_get_report_descriptor 1828184610Salfred * 1829184610Salfred * Returns: 1830184610Salfred * 0: Success 1831184610Salfred * Else: Failure 1832184610Salfred *------------------------------------------------------------------------*/ 1833193045Sthompsausb_error_t 1834194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1835184610Salfred void *d, uint16_t size, uint8_t iface_index) 1836184610Salfred{ 1837194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1838192984Sthompsa struct usb_device_request req; 1839184610Salfred 1840184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1841184610Salfred return (USB_ERR_INVAL); 1842184610Salfred } 1843184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1844184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1845184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1846184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1847184610Salfred req.wIndex[1] = 0; 1848184610Salfred USETW(req.wLength, size); 1849194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1850184610Salfred} 1851184610Salfred 1852184610Salfred/*------------------------------------------------------------------------* 1853194228Sthompsa * usbd_req_set_config 1854184610Salfred * 1855184610Salfred * This function is used to select the current configuration number in 1856184610Salfred * both USB device side mode and USB host side mode. When setting the 1857184610Salfred * configuration the function of the interfaces can change. 1858184610Salfred * 1859184610Salfred * Returns: 1860184610Salfred * 0: Success 1861184610Salfred * Else: Failure 1862184610Salfred *------------------------------------------------------------------------*/ 1863193045Sthompsausb_error_t 1864194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1865184610Salfred{ 1866192984Sthompsa struct usb_device_request req; 1867184610Salfred 1868184610Salfred DPRINTF("setting config %d\n", conf); 1869184610Salfred 1870184610Salfred /* do "set configuration" request */ 1871184610Salfred 1872184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1873184610Salfred req.bRequest = UR_SET_CONFIG; 1874184610Salfred req.wValue[0] = conf; 1875184610Salfred req.wValue[1] = 0; 1876184610Salfred USETW(req.wIndex, 0); 1877184610Salfred USETW(req.wLength, 0); 1878194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1879184610Salfred} 1880184610Salfred 1881184610Salfred/*------------------------------------------------------------------------* 1882194228Sthompsa * usbd_req_get_config 1883184610Salfred * 1884184610Salfred * Returns: 1885184610Salfred * 0: Success 1886184610Salfred * Else: Failure 1887184610Salfred *------------------------------------------------------------------------*/ 1888193045Sthompsausb_error_t 1889194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1890184610Salfred{ 1891192984Sthompsa struct usb_device_request req; 1892184610Salfred 1893184610Salfred req.bmRequestType = UT_READ_DEVICE; 1894184610Salfred req.bRequest = UR_GET_CONFIG; 1895184610Salfred USETW(req.wValue, 0); 1896184610Salfred USETW(req.wIndex, 0); 1897184610Salfred USETW(req.wLength, 1); 1898194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1899184610Salfred} 1900184610Salfred 1901184610Salfred/*------------------------------------------------------------------------* 1902213435Shselasky * usbd_setup_device_desc 1903213435Shselasky *------------------------------------------------------------------------*/ 1904213435Shselaskyusb_error_t 1905213435Shselaskyusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) 1906213435Shselasky{ 1907213435Shselasky usb_error_t err; 1908213435Shselasky 1909213435Shselasky /* 1910213435Shselasky * Get the first 8 bytes of the device descriptor ! 1911213435Shselasky * 1912213435Shselasky * NOTE: "usbd_do_request()" will check the device descriptor 1913213435Shselasky * next time we do a request to see if the maximum packet size 1914213435Shselasky * changed! The 8 first bytes of the device descriptor 1915213435Shselasky * contains the maximum packet size to use on control endpoint 1916213435Shselasky * 0. If this value is different from "USB_MAX_IPACKET" a new 1917213435Shselasky * USB control request will be setup! 1918213435Shselasky */ 1919213435Shselasky switch (udev->speed) { 1920213435Shselasky case USB_SPEED_FULL: 1921213435Shselasky case USB_SPEED_LOW: 1922213435Shselasky err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1923213435Shselasky USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1924213435Shselasky if (err != 0) { 1925213435Shselasky DPRINTFN(0, "getting device descriptor " 1926213435Shselasky "at addr %d failed, %s\n", udev->address, 1927213435Shselasky usbd_errstr(err)); 1928213435Shselasky return (err); 1929213435Shselasky } 1930213435Shselasky break; 1931213435Shselasky default: 1932213435Shselasky DPRINTF("Minimum MaxPacketSize is large enough " 1933213435Shselasky "to hold the complete device descriptor\n"); 1934213435Shselasky break; 1935213435Shselasky } 1936213435Shselasky 1937213435Shselasky /* get the full device descriptor */ 1938213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1939213435Shselasky 1940213435Shselasky /* try one more time, if error */ 1941213435Shselasky if (err) 1942213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1943213435Shselasky 1944213435Shselasky if (err) { 1945213435Shselasky DPRINTF("addr=%d, getting full desc failed\n", 1946213435Shselasky udev->address); 1947213435Shselasky return (err); 1948213435Shselasky } 1949213435Shselasky 1950213435Shselasky DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " 1951213435Shselasky "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", 1952213435Shselasky udev->address, UGETW(udev->ddesc.bcdUSB), 1953213435Shselasky udev->ddesc.bDeviceClass, 1954213435Shselasky udev->ddesc.bDeviceSubClass, 1955213435Shselasky udev->ddesc.bDeviceProtocol, 1956213435Shselasky udev->ddesc.bMaxPacketSize, 1957213435Shselasky udev->ddesc.bLength, 1958213435Shselasky udev->speed); 1959213435Shselasky 1960213435Shselasky return (err); 1961213435Shselasky} 1962213435Shselasky 1963213435Shselasky/*------------------------------------------------------------------------* 1964194228Sthompsa * usbd_req_re_enumerate 1965184610Salfred * 1966185087Salfred * NOTE: After this function returns the hardware is in the 1967185087Salfred * unconfigured state! The application is responsible for setting a 1968185087Salfred * new configuration. 1969185087Salfred * 1970184610Salfred * Returns: 1971184610Salfred * 0: Success 1972184610Salfred * Else: Failure 1973184610Salfred *------------------------------------------------------------------------*/ 1974193045Sthompsausb_error_t 1975194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 1976184610Salfred{ 1977192984Sthompsa struct usb_device *parent_hub; 1978193045Sthompsa usb_error_t err; 1979184610Salfred uint8_t old_addr; 1980186730Salfred uint8_t do_retry = 1; 1981184610Salfred 1982192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 1983185290Salfred return (USB_ERR_INVAL); 1984185290Salfred } 1985184610Salfred old_addr = udev->address; 1986184610Salfred parent_hub = udev->parent_hub; 1987184610Salfred if (parent_hub == NULL) { 1988185290Salfred return (USB_ERR_INVAL); 1989184610Salfred } 1990186730Salfredretry: 1991222786Shselasky /* 1992222786Shselasky * Try to reset the High Speed parent HUB of a LOW- or FULL- 1993222786Shselasky * speed device, if any. 1994222786Shselasky */ 1995222786Shselasky if (udev->parent_hs_hub != NULL && 1996222786Shselasky udev->speed != USB_SPEED_HIGH) { 1997222786Shselasky DPRINTF("Trying to reset parent High Speed TT.\n"); 1998222786Shselasky err = usbd_req_reset_tt(udev->parent_hs_hub, NULL, 1999222786Shselasky udev->hs_port_no); 2000222786Shselasky if (err) { 2001222786Shselasky DPRINTF("Resetting parent High " 2002222786Shselasky "Speed TT failed (%s).\n", 2003222786Shselasky usbd_errstr(err)); 2004222786Shselasky } 2005222786Shselasky } 2006222786Shselasky 2007222786Shselasky /* Try to reset the parent HUB port. */ 2008194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 2009184610Salfred if (err) { 2010190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 2011194228Sthompsa old_addr, usbd_errstr(err)); 2012184610Salfred goto done; 2013184610Salfred } 2014213435Shselasky 2015184610Salfred /* 2016184610Salfred * After that the port has been reset our device should be at 2017184610Salfred * address zero: 2018184610Salfred */ 2019184610Salfred udev->address = USB_START_ADDR; 2020184610Salfred 2021185290Salfred /* reset "bMaxPacketSize" */ 2022185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 2023185290Salfred 2024213435Shselasky /* reset USB state */ 2025213435Shselasky usb_set_device_state(udev, USB_STATE_POWERED); 2026213435Shselasky 2027184610Salfred /* 2028184610Salfred * Restore device address: 2029184610Salfred */ 2030194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 2031184610Salfred if (err) { 2032184610Salfred /* XXX ignore any errors! */ 2033190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 2034194228Sthompsa old_addr, usbd_errstr(err)); 2035184610Salfred } 2036213435Shselasky /* 2037213435Shselasky * Restore device address, if the controller driver did not 2038213435Shselasky * set a new one: 2039213435Shselasky */ 2040213435Shselasky if (udev->address == USB_START_ADDR) 2041213435Shselasky udev->address = old_addr; 2042184610Salfred 2043213435Shselasky /* setup the device descriptor and the initial "wMaxPacketSize" */ 2044213435Shselasky err = usbd_setup_device_desc(udev, mtx); 2045184610Salfred 2046184610Salfreddone: 2047186730Salfred if (err && do_retry) { 2048186730Salfred /* give the USB firmware some time to load */ 2049194228Sthompsa usb_pause_mtx(mtx, hz / 2); 2050186730Salfred /* no more retries after this retry */ 2051186730Salfred do_retry = 0; 2052186730Salfred /* try again */ 2053186730Salfred goto retry; 2054186730Salfred } 2055184610Salfred /* restore address */ 2056213435Shselasky if (udev->address == USB_START_ADDR) 2057213435Shselasky udev->address = old_addr; 2058213435Shselasky /* update state, if successful */ 2059213435Shselasky if (err == 0) 2060213435Shselasky usb_set_device_state(udev, USB_STATE_ADDRESSED); 2061184610Salfred return (err); 2062184610Salfred} 2063186730Salfred 2064186730Salfred/*------------------------------------------------------------------------* 2065194228Sthompsa * usbd_req_clear_device_feature 2066186730Salfred * 2067186730Salfred * Returns: 2068186730Salfred * 0: Success 2069186730Salfred * Else: Failure 2070186730Salfred *------------------------------------------------------------------------*/ 2071193045Sthompsausb_error_t 2072194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 2073186730Salfred uint16_t sel) 2074186730Salfred{ 2075192984Sthompsa struct usb_device_request req; 2076186730Salfred 2077186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2078186730Salfred req.bRequest = UR_CLEAR_FEATURE; 2079186730Salfred USETW(req.wValue, sel); 2080186730Salfred USETW(req.wIndex, 0); 2081186730Salfred USETW(req.wLength, 0); 2082194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2083186730Salfred} 2084186730Salfred 2085186730Salfred/*------------------------------------------------------------------------* 2086194228Sthompsa * usbd_req_set_device_feature 2087186730Salfred * 2088186730Salfred * Returns: 2089186730Salfred * 0: Success 2090186730Salfred * Else: Failure 2091186730Salfred *------------------------------------------------------------------------*/ 2092193045Sthompsausb_error_t 2093194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 2094186730Salfred uint16_t sel) 2095186730Salfred{ 2096192984Sthompsa struct usb_device_request req; 2097186730Salfred 2098186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2099186730Salfred req.bRequest = UR_SET_FEATURE; 2100186730Salfred USETW(req.wValue, sel); 2101186730Salfred USETW(req.wIndex, 0); 2102186730Salfred USETW(req.wLength, 0); 2103194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2104186730Salfred} 2105222786Shselasky 2106222786Shselasky/*------------------------------------------------------------------------* 2107222786Shselasky * usbd_req_reset_tt 2108222786Shselasky * 2109222786Shselasky * Returns: 2110222786Shselasky * 0: Success 2111222786Shselasky * Else: Failure 2112222786Shselasky *------------------------------------------------------------------------*/ 2113222786Shselaskyusb_error_t 2114222786Shselaskyusbd_req_reset_tt(struct usb_device *udev, struct mtx *mtx, 2115222786Shselasky uint8_t port) 2116222786Shselasky{ 2117222786Shselasky struct usb_device_request req; 2118222786Shselasky 2119222786Shselasky /* For single TT HUBs the port should be 1 */ 2120222786Shselasky 2121222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2122222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2123222786Shselasky port = 1; 2124222786Shselasky 2125222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2126222786Shselasky req.bRequest = UR_RESET_TT; 2127222786Shselasky USETW(req.wValue, 0); 2128222786Shselasky req.wIndex[0] = port; 2129222786Shselasky req.wIndex[1] = 0; 2130222786Shselasky USETW(req.wLength, 0); 2131222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2132222786Shselasky} 2133222786Shselasky 2134222786Shselasky/*------------------------------------------------------------------------* 2135222786Shselasky * usbd_req_clear_tt_buffer 2136222786Shselasky * 2137222786Shselasky * For single TT HUBs the port should be 1. 2138222786Shselasky * 2139222786Shselasky * Returns: 2140222786Shselasky * 0: Success 2141222786Shselasky * Else: Failure 2142222786Shselasky *------------------------------------------------------------------------*/ 2143222786Shselaskyusb_error_t 2144222786Shselaskyusbd_req_clear_tt_buffer(struct usb_device *udev, struct mtx *mtx, 2145222786Shselasky uint8_t port, uint8_t addr, uint8_t type, uint8_t endpoint) 2146222786Shselasky{ 2147222786Shselasky struct usb_device_request req; 2148222786Shselasky uint16_t wValue; 2149222786Shselasky 2150222786Shselasky /* For single TT HUBs the port should be 1 */ 2151222786Shselasky 2152222786Shselasky if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 2153222786Shselasky udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 2154222786Shselasky port = 1; 2155222786Shselasky 2156222786Shselasky wValue = (endpoint & 0xF) | ((addr & 0x7F) << 4) | 2157222786Shselasky ((endpoint & 0x80) << 8) | ((type & 3) << 12); 2158222786Shselasky 2159222786Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 2160222786Shselasky req.bRequest = UR_CLEAR_TT_BUFFER; 2161222786Shselasky USETW(req.wValue, wValue); 2162222786Shselasky req.wIndex[0] = port; 2163222786Shselasky req.wIndex[1] = 0; 2164222786Shselasky USETW(req.wLength, 0); 2165222786Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 2166222786Shselasky} 2167