usb_request.c revision 216249
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 216249 2010-12-07 08:20:20Z 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/linker_set.h> 38194677Sthompsa#include <sys/module.h> 39194677Sthompsa#include <sys/lock.h> 40194677Sthompsa#include <sys/mutex.h> 41194677Sthompsa#include <sys/condvar.h> 42194677Sthompsa#include <sys/sysctl.h> 43194677Sthompsa#include <sys/sx.h> 44194677Sthompsa#include <sys/unistd.h> 45194677Sthompsa#include <sys/callout.h> 46194677Sthompsa#include <sys/malloc.h> 47194677Sthompsa#include <sys/priv.h> 48194677Sthompsa 49188942Sthompsa#include <dev/usb/usb.h> 50194677Sthompsa#include <dev/usb/usbdi.h> 51194677Sthompsa#include <dev/usb/usbdi_util.h> 52188942Sthompsa#include <dev/usb/usb_ioctl.h> 53188942Sthompsa#include <dev/usb/usbhid.h> 54184610Salfred 55194228Sthompsa#define USB_DEBUG_VAR usb_debug 56184610Salfred 57188942Sthompsa#include <dev/usb/usb_core.h> 58188942Sthompsa#include <dev/usb/usb_busdma.h> 59188942Sthompsa#include <dev/usb/usb_request.h> 60188942Sthompsa#include <dev/usb/usb_process.h> 61188942Sthompsa#include <dev/usb/usb_transfer.h> 62188942Sthompsa#include <dev/usb/usb_debug.h> 63188942Sthompsa#include <dev/usb/usb_device.h> 64188942Sthompsa#include <dev/usb/usb_util.h> 65188942Sthompsa#include <dev/usb/usb_dynamic.h> 66184610Salfred 67188942Sthompsa#include <dev/usb/usb_controller.h> 68188942Sthompsa#include <dev/usb/usb_bus.h> 69184610Salfred#include <sys/ctype.h> 70184610Salfred 71207077Sthompsa#ifdef USB_DEBUG 72194228Sthompsastatic int usb_pr_poll_delay = USB_PORT_RESET_DELAY; 73194228Sthompsastatic int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY; 74184610Salfred 75192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW, 76194228Sthompsa &usb_pr_poll_delay, 0, "USB port reset poll delay in ms"); 77192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, 78194228Sthompsa &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms"); 79184610Salfred 80208018Sthompsa#ifdef USB_REQ_DEBUG 81208018Sthompsa/* The following structures are used in connection to fault injection. */ 82208018Sthompsastruct usb_ctrl_debug { 83208018Sthompsa int bus_index; /* target bus */ 84208018Sthompsa int dev_index; /* target address */ 85208018Sthompsa int ds_fail; /* fail data stage */ 86208018Sthompsa int ss_fail; /* fail data stage */ 87208018Sthompsa int ds_delay; /* data stage delay in ms */ 88208018Sthompsa int ss_delay; /* status stage delay in ms */ 89208018Sthompsa int bmRequestType_value; 90208018Sthompsa int bRequest_value; 91208018Sthompsa}; 92208018Sthompsa 93208018Sthompsastruct usb_ctrl_debug_bits { 94208018Sthompsa uint16_t ds_delay; 95208018Sthompsa uint16_t ss_delay; 96208018Sthompsa uint8_t ds_fail:1; 97208018Sthompsa uint8_t ss_fail:1; 98208018Sthompsa uint8_t enabled:1; 99208018Sthompsa}; 100208018Sthompsa 101208018Sthompsa/* The default is to disable fault injection. */ 102208018Sthompsa 103208018Sthompsastatic struct usb_ctrl_debug usb_ctrl_debug = { 104208018Sthompsa .bus_index = -1, 105208018Sthompsa .dev_index = -1, 106208018Sthompsa .bmRequestType_value = -1, 107208018Sthompsa .bRequest_value = -1, 108208018Sthompsa}; 109208018Sthompsa 110208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_bus_fail, CTLFLAG_RW, 111208018Sthompsa &usb_ctrl_debug.bus_index, 0, "USB controller index to fail"); 112208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_dev_fail, CTLFLAG_RW, 113208018Sthompsa &usb_ctrl_debug.dev_index, 0, "USB device address to fail"); 114208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_fail, CTLFLAG_RW, 115208018Sthompsa &usb_ctrl_debug.ds_fail, 0, "USB fail data stage"); 116208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_fail, CTLFLAG_RW, 117208018Sthompsa &usb_ctrl_debug.ss_fail, 0, "USB fail status stage"); 118208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ds_delay, CTLFLAG_RW, 119208018Sthompsa &usb_ctrl_debug.ds_delay, 0, "USB data stage delay in ms"); 120208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_ss_delay, CTLFLAG_RW, 121208018Sthompsa &usb_ctrl_debug.ss_delay, 0, "USB status stage delay in ms"); 122208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rt_fail, CTLFLAG_RW, 123208018Sthompsa &usb_ctrl_debug.bmRequestType_value, 0, "USB bmRequestType to fail"); 124208018SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ctrl_rv_fail, CTLFLAG_RW, 125208018Sthompsa &usb_ctrl_debug.bRequest_value, 0, "USB bRequest to fail"); 126208018Sthompsa 127184610Salfred/*------------------------------------------------------------------------* 128208018Sthompsa * usbd_get_debug_bits 129208018Sthompsa * 130208018Sthompsa * This function is only useful in USB host mode. 131208018Sthompsa *------------------------------------------------------------------------*/ 132208018Sthompsastatic void 133208018Sthompsausbd_get_debug_bits(struct usb_device *udev, struct usb_device_request *req, 134208018Sthompsa struct usb_ctrl_debug_bits *dbg) 135208018Sthompsa{ 136208018Sthompsa int temp; 137208018Sthompsa 138208018Sthompsa memset(dbg, 0, sizeof(*dbg)); 139208018Sthompsa 140208018Sthompsa /* Compute data stage delay */ 141208018Sthompsa 142208018Sthompsa temp = usb_ctrl_debug.ds_delay; 143208018Sthompsa if (temp < 0) 144208018Sthompsa temp = 0; 145208018Sthompsa else if (temp > (16*1024)) 146208018Sthompsa temp = (16*1024); 147208018Sthompsa 148208018Sthompsa dbg->ds_delay = temp; 149208018Sthompsa 150208018Sthompsa /* Compute status stage delay */ 151208018Sthompsa 152208018Sthompsa temp = usb_ctrl_debug.ss_delay; 153208018Sthompsa if (temp < 0) 154208018Sthompsa temp = 0; 155208018Sthompsa else if (temp > (16*1024)) 156208018Sthompsa temp = (16*1024); 157208018Sthompsa 158208018Sthompsa dbg->ss_delay = temp; 159208018Sthompsa 160208018Sthompsa /* Check if this control request should be failed */ 161208018Sthompsa 162208018Sthompsa if (usbd_get_bus_index(udev) != usb_ctrl_debug.bus_index) 163208018Sthompsa return; 164208018Sthompsa 165208018Sthompsa if (usbd_get_device_index(udev) != usb_ctrl_debug.dev_index) 166208018Sthompsa return; 167208018Sthompsa 168208018Sthompsa temp = usb_ctrl_debug.bmRequestType_value; 169208018Sthompsa 170208018Sthompsa if ((temp != req->bmRequestType) && (temp >= 0) && (temp <= 255)) 171208018Sthompsa return; 172208018Sthompsa 173208018Sthompsa temp = usb_ctrl_debug.bRequest_value; 174208018Sthompsa 175208018Sthompsa if ((temp != req->bRequest) && (temp >= 0) && (temp <= 255)) 176208018Sthompsa return; 177208018Sthompsa 178208018Sthompsa temp = usb_ctrl_debug.ds_fail; 179208018Sthompsa if (temp) 180208018Sthompsa dbg->ds_fail = 1; 181208018Sthompsa 182208018Sthompsa temp = usb_ctrl_debug.ss_fail; 183208018Sthompsa if (temp) 184208018Sthompsa dbg->ss_fail = 1; 185208018Sthompsa 186208018Sthompsa dbg->enabled = 1; 187208018Sthompsa} 188208018Sthompsa#endif /* USB_REQ_DEBUG */ 189208018Sthompsa#endif /* USB_DEBUG */ 190208018Sthompsa 191208018Sthompsa/*------------------------------------------------------------------------* 192194228Sthompsa * usbd_do_request_callback 193184610Salfred * 194184610Salfred * This function is the USB callback for generic USB Host control 195184610Salfred * transfers. 196184610Salfred *------------------------------------------------------------------------*/ 197184610Salfredvoid 198194677Sthompsausbd_do_request_callback(struct usb_xfer *xfer, usb_error_t error) 199184610Salfred{ 200184610Salfred ; /* workaround for a bug in "indent" */ 201184610Salfred 202184610Salfred DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 203184610Salfred 204184610Salfred switch (USB_GET_STATE(xfer)) { 205184610Salfred case USB_ST_SETUP: 206194228Sthompsa usbd_transfer_submit(xfer); 207184610Salfred break; 208184610Salfred default: 209207079Sthompsa cv_signal(&xfer->xroot->udev->ctrlreq_cv); 210184610Salfred break; 211184610Salfred } 212184610Salfred} 213184610Salfred 214184610Salfred/*------------------------------------------------------------------------* 215194228Sthompsa * usb_do_clear_stall_callback 216184610Salfred * 217184610Salfred * This function is the USB callback for generic clear stall requests. 218184610Salfred *------------------------------------------------------------------------*/ 219184610Salfredvoid 220194677Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) 221184610Salfred{ 222192984Sthompsa struct usb_device_request req; 223192984Sthompsa struct usb_device *udev; 224193644Sthompsa struct usb_endpoint *ep; 225193644Sthompsa struct usb_endpoint *ep_end; 226193644Sthompsa struct usb_endpoint *ep_first; 227190731Sthompsa uint8_t to; 228184610Salfred 229187173Sthompsa udev = xfer->xroot->udev; 230184610Salfred 231187173Sthompsa USB_BUS_LOCK(udev->bus); 232187173Sthompsa 233193644Sthompsa /* round robin endpoint clear stall */ 234184610Salfred 235193644Sthompsa ep = udev->ep_curr; 236193644Sthompsa ep_end = udev->endpoints + udev->endpoints_max; 237193644Sthompsa ep_first = udev->endpoints; 238193644Sthompsa to = udev->endpoints_max; 239193318Sthompsa 240184610Salfred switch (USB_GET_STATE(xfer)) { 241184610Salfred case USB_ST_TRANSFERRED: 242193644Sthompsa if (ep == NULL) 243193318Sthompsa goto tr_setup; /* device was unconfigured */ 244193644Sthompsa if (ep->edesc && 245193644Sthompsa ep->is_stalled) { 246193644Sthompsa ep->toggle_next = 0; 247193644Sthompsa ep->is_stalled = 0; 248213435Shselasky /* some hardware needs a callback to clear the data toggle */ 249213435Shselasky usbd_clear_stall_locked(udev, ep); 250184610Salfred /* start up the current or next transfer, if any */ 251194228Sthompsa usb_command_wrapper(&ep->endpoint_q, 252193644Sthompsa ep->endpoint_q.curr); 253184610Salfred } 254193644Sthompsa ep++; 255184610Salfred 256184610Salfred case USB_ST_SETUP: 257184610Salfredtr_setup: 258193318Sthompsa if (to == 0) 259193644Sthompsa break; /* no endpoints - nothing to do */ 260193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 261193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 262193644Sthompsa if (ep->edesc && 263193644Sthompsa ep->is_stalled) { 264184610Salfred 265184610Salfred /* setup a clear-stall packet */ 266184610Salfred 267184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 268184610Salfred req.bRequest = UR_CLEAR_FEATURE; 269184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 270193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 271184610Salfred req.wIndex[1] = 0; 272184610Salfred USETW(req.wLength, 0); 273184610Salfred 274184610Salfred /* copy in the transfer */ 275184610Salfred 276194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 277184610Salfred 278184610Salfred /* set length */ 279194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 280184610Salfred xfer->nframes = 1; 281187173Sthompsa USB_BUS_UNLOCK(udev->bus); 282184610Salfred 283194228Sthompsa usbd_transfer_submit(xfer); 284184610Salfred 285187173Sthompsa USB_BUS_LOCK(udev->bus); 286184610Salfred break; 287184610Salfred } 288193644Sthompsa ep++; 289193318Sthompsa to--; 290193318Sthompsa goto tr_setup; 291184610Salfred 292184610Salfred default: 293184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 294184610Salfred break; 295184610Salfred } 296184610Salfred goto tr_setup; 297184610Salfred } 298184610Salfred 299193644Sthompsa /* store current endpoint */ 300193644Sthompsa udev->ep_curr = ep; 301187173Sthompsa USB_BUS_UNLOCK(udev->bus); 302184610Salfred} 303184610Salfred 304193045Sthompsastatic usb_handle_req_t * 305194228Sthompsausbd_get_hr_func(struct usb_device *udev) 306191402Sthompsa{ 307191402Sthompsa /* figure out if there is a Handle Request function */ 308192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 309194228Sthompsa return (usb_temp_get_desc_p); 310191402Sthompsa else if (udev->parent_hub == NULL) 311191402Sthompsa return (udev->bus->methods->roothub_exec); 312191402Sthompsa else 313191402Sthompsa return (NULL); 314191402Sthompsa} 315191402Sthompsa 316184610Salfred/*------------------------------------------------------------------------* 317194228Sthompsa * usbd_do_request_flags and usbd_do_request 318184610Salfred * 319184610Salfred * Description of arguments passed to these functions: 320184610Salfred * 321192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 322184610Salfred * request should be performed. It is possible to call this function 323184610Salfred * in both Host Side mode and Device Side mode. 324184610Salfred * 325184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 326184610Salfred * will get dropped and picked up during the execution of this 327184610Salfred * function, hence this function sometimes needs to sleep. If this 328184610Salfred * argument is NULL it has no effect. 329184610Salfred * 330184610Salfred * "req" - this argument must always be non-NULL and points to an 331184610Salfred * 8-byte structure holding the USB request to be done. The USB 332184610Salfred * request structure has a bit telling the direction of the USB 333184610Salfred * request, if it is a read or a write. 334184610Salfred * 335184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 336184610Salfred * is non-zero this argument must point to a valid kernel buffer which 337184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 338184610Salfred * be NULL. 339184610Salfred * 340184610Salfred * "flags" - here is a list of valid flags: 341184610Salfred * 342184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 343184610Salfred * specified 344184610Salfred * 345184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 346184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 347184610Salfred * sysctl. This flag is mostly useful for debugging. 348184610Salfred * 349184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 350184610Salfred * pointer. 351184610Salfred * 352184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 353184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 354184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 355184610Salfred * used. 356184610Salfred * 357184610Salfred * "timeout" - gives the timeout for the control transfer in 358184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 359184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 360184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 361184610Salfred * does not allow control requests without a timeout. 362184610Salfred * 363184610Salfred * NOTE: This function is thread safe. All calls to 364194228Sthompsa * "usbd_do_request_flags" will be serialised by the use of an 365184610Salfred * internal "sx_lock". 366184610Salfred * 367184610Salfred * Returns: 368184610Salfred * 0: Success 369184610Salfred * Else: Failure 370184610Salfred *------------------------------------------------------------------------*/ 371193045Sthompsausb_error_t 372194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 373192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 374193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 375184610Salfred{ 376208018Sthompsa#ifdef USB_REQ_DEBUG 377208018Sthompsa struct usb_ctrl_debug_bits dbg; 378208018Sthompsa#endif 379193045Sthompsa usb_handle_req_t *hr_func; 380192984Sthompsa struct usb_xfer *xfer; 381184610Salfred const void *desc; 382184610Salfred int err = 0; 383193045Sthompsa usb_ticks_t start_ticks; 384193045Sthompsa usb_ticks_t delta_ticks; 385193045Sthompsa usb_ticks_t max_ticks; 386184610Salfred uint16_t length; 387184610Salfred uint16_t temp; 388208018Sthompsa uint16_t acttemp; 389208008Sthompsa uint8_t enum_locked; 390184610Salfred 391184610Salfred if (timeout < 50) { 392184610Salfred /* timeout is too small */ 393184610Salfred timeout = 50; 394184610Salfred } 395184610Salfred if (timeout > 30000) { 396184610Salfred /* timeout is too big */ 397184610Salfred timeout = 30000; 398184610Salfred } 399184610Salfred length = UGETW(req->wLength); 400184610Salfred 401208008Sthompsa enum_locked = usbd_enum_is_locked(udev); 402208008Sthompsa 403184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 404184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 405184610Salfred udev, req->bmRequestType, req->bRequest, 406184610Salfred req->wValue[1], req->wValue[0], 407184610Salfred req->wIndex[1], req->wIndex[0], 408184610Salfred req->wLength[1], req->wLength[0]); 409184610Salfred 410191494Sthompsa /* Check if the device is still alive */ 411191494Sthompsa if (udev->state < USB_STATE_POWERED) { 412191494Sthompsa DPRINTF("usb device has gone\n"); 413191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 414191494Sthompsa } 415191494Sthompsa 416184610Salfred /* 417184610Salfred * Set "actlen" to a known value in case the caller does not 418184610Salfred * check the return value: 419184610Salfred */ 420190735Sthompsa if (actlen) 421184610Salfred *actlen = 0; 422190735Sthompsa 423190180Sthompsa#if (USB_HAVE_USER_IO == 0) 424190180Sthompsa if (flags & USB_USER_DATA_PTR) 425190180Sthompsa return (USB_ERR_INVAL); 426190180Sthompsa#endif 427208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) { 428184610Salfred mtx_unlock(mtx); 429208008Sthompsa mtx_assert(mtx, MA_NOTOWNED); 430184610Salfred } 431208008Sthompsa 432184610Salfred /* 433208008Sthompsa * We need to allow suspend and resume at this point, else the 434208008Sthompsa * control transfer will timeout if the device is suspended! 435208008Sthompsa */ 436208008Sthompsa if (enum_locked) 437208008Sthompsa usbd_sr_unlock(udev); 438208008Sthompsa 439208008Sthompsa /* 440184610Salfred * Grab the default sx-lock so that serialisation 441184610Salfred * is achieved when multiple threads are involved: 442184610Salfred */ 443207079Sthompsa sx_xlock(&udev->ctrl_sx); 444184610Salfred 445194228Sthompsa hr_func = usbd_get_hr_func(udev); 446190735Sthompsa 447191402Sthompsa if (hr_func != NULL) { 448191402Sthompsa DPRINTF("Handle Request function is set\n"); 449190735Sthompsa 450191402Sthompsa desc = NULL; 451191402Sthompsa temp = 0; 452191402Sthompsa 453191402Sthompsa if (!(req->bmRequestType & UT_READ)) { 454190735Sthompsa if (length != 0) { 455191402Sthompsa DPRINTFN(1, "The handle request function " 456191402Sthompsa "does not support writing data!\n"); 457191402Sthompsa err = USB_ERR_INVAL; 458191402Sthompsa goto done; 459190735Sthompsa } 460190735Sthompsa } 461190735Sthompsa 462191402Sthompsa /* The root HUB code needs the BUS lock locked */ 463191402Sthompsa 464190735Sthompsa USB_BUS_LOCK(udev->bus); 465191402Sthompsa err = (hr_func) (udev, req, &desc, &temp); 466190735Sthompsa USB_BUS_UNLOCK(udev->bus); 467190735Sthompsa 468190735Sthompsa if (err) 469190735Sthompsa goto done; 470190735Sthompsa 471191402Sthompsa if (length > temp) { 472190735Sthompsa if (!(flags & USB_SHORT_XFER_OK)) { 473190735Sthompsa err = USB_ERR_SHORT_XFER; 474190735Sthompsa goto done; 475190735Sthompsa } 476191402Sthompsa length = temp; 477190735Sthompsa } 478190735Sthompsa if (actlen) 479190735Sthompsa *actlen = length; 480190735Sthompsa 481190735Sthompsa if (length > 0) { 482190735Sthompsa#if USB_HAVE_USER_IO 483190735Sthompsa if (flags & USB_USER_DATA_PTR) { 484191402Sthompsa if (copyout(desc, data, length)) { 485190735Sthompsa err = USB_ERR_INVAL; 486190735Sthompsa goto done; 487190735Sthompsa } 488190735Sthompsa } else 489190735Sthompsa#endif 490191402Sthompsa bcopy(desc, data, length); 491190735Sthompsa } 492191402Sthompsa goto done; /* success */ 493190735Sthompsa } 494190735Sthompsa 495184610Salfred /* 496184610Salfred * Setup a new USB transfer or use the existing one, if any: 497184610Salfred */ 498207080Sthompsa usbd_ctrl_transfer_setup(udev); 499184610Salfred 500207080Sthompsa xfer = udev->ctrl_xfer[0]; 501184610Salfred if (xfer == NULL) { 502184610Salfred /* most likely out of memory */ 503184610Salfred err = USB_ERR_NOMEM; 504184610Salfred goto done; 505184610Salfred } 506208018Sthompsa 507208018Sthompsa#ifdef USB_REQ_DEBUG 508208018Sthompsa /* Get debug bits */ 509208018Sthompsa usbd_get_debug_bits(udev, req, &dbg); 510208018Sthompsa 511208018Sthompsa /* Check for fault injection */ 512208018Sthompsa if (dbg.enabled) 513208018Sthompsa flags |= USB_DELAY_STATUS_STAGE; 514208018Sthompsa#endif 515184824Sthompsa USB_XFER_LOCK(xfer); 516184610Salfred 517190734Sthompsa if (flags & USB_DELAY_STATUS_STAGE) 518184610Salfred xfer->flags.manual_status = 1; 519190734Sthompsa else 520184610Salfred xfer->flags.manual_status = 0; 521184610Salfred 522190734Sthompsa if (flags & USB_SHORT_XFER_OK) 523190734Sthompsa xfer->flags.short_xfer_ok = 1; 524190734Sthompsa else 525190734Sthompsa xfer->flags.short_xfer_ok = 0; 526190734Sthompsa 527184610Salfred xfer->timeout = timeout; 528184610Salfred 529184610Salfred start_ticks = ticks; 530184610Salfred 531184610Salfred max_ticks = USB_MS_TO_TICKS(timeout); 532184610Salfred 533194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 534184610Salfred 535194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); 536184610Salfred 537184610Salfred while (1) { 538184610Salfred temp = length; 539208018Sthompsa if (temp > usbd_xfer_max_len(xfer)) { 540194677Sthompsa temp = usbd_xfer_max_len(xfer); 541184610Salfred } 542208018Sthompsa#ifdef USB_REQ_DEBUG 543208018Sthompsa if (xfer->flags.manual_status) { 544208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) != 0) { 545208018Sthompsa /* Execute data stage separately */ 546208018Sthompsa temp = 0; 547208018Sthompsa } else if (temp > 0) { 548208018Sthompsa if (dbg.ds_fail) { 549208018Sthompsa err = USB_ERR_INVAL; 550208018Sthompsa break; 551208018Sthompsa } 552208018Sthompsa if (dbg.ds_delay > 0) { 553208018Sthompsa usb_pause_mtx( 554208018Sthompsa xfer->xroot->xfer_mtx, 555208018Sthompsa USB_MS_TO_TICKS(dbg.ds_delay)); 556208018Sthompsa /* make sure we don't time out */ 557208018Sthompsa start_ticks = ticks; 558208018Sthompsa } 559208018Sthompsa } 560208018Sthompsa } 561208018Sthompsa#endif 562194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, temp); 563184610Salfred 564184610Salfred if (temp > 0) { 565184610Salfred if (!(req->bmRequestType & UT_READ)) { 566190180Sthompsa#if USB_HAVE_USER_IO 567184610Salfred if (flags & USB_USER_DATA_PTR) { 568184824Sthompsa USB_XFER_UNLOCK(xfer); 569194228Sthompsa err = usbd_copy_in_user(xfer->frbuffers + 1, 570184610Salfred 0, data, temp); 571184824Sthompsa USB_XFER_LOCK(xfer); 572184610Salfred if (err) { 573184610Salfred err = USB_ERR_INVAL; 574184610Salfred break; 575184610Salfred } 576190180Sthompsa } else 577190180Sthompsa#endif 578194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 579190180Sthompsa 0, data, temp); 580184610Salfred } 581208018Sthompsa usbd_xfer_set_frames(xfer, 2); 582184610Salfred } else { 583208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) == 0) { 584184610Salfred if (xfer->flags.manual_status) { 585208018Sthompsa#ifdef USB_REQ_DEBUG 586208018Sthompsa if (dbg.ss_fail) { 587208018Sthompsa err = USB_ERR_INVAL; 588208018Sthompsa break; 589184610Salfred } 590208018Sthompsa if (dbg.ss_delay > 0) { 591194228Sthompsa usb_pause_mtx( 592187173Sthompsa xfer->xroot->xfer_mtx, 593208018Sthompsa USB_MS_TO_TICKS(dbg.ss_delay)); 594208018Sthompsa /* make sure we don't time out */ 595208018Sthompsa start_ticks = ticks; 596184610Salfred } 597184610Salfred#endif 598184610Salfred xfer->flags.manual_status = 0; 599184610Salfred } else { 600184610Salfred break; 601184610Salfred } 602184610Salfred } 603208018Sthompsa usbd_xfer_set_frames(xfer, 1); 604184610Salfred } 605184610Salfred 606194228Sthompsa usbd_transfer_start(xfer); 607184610Salfred 608194228Sthompsa while (usbd_transfer_pending(xfer)) { 609207079Sthompsa cv_wait(&udev->ctrlreq_cv, 610188983Sthompsa xfer->xroot->xfer_mtx); 611184610Salfred } 612184610Salfred 613184610Salfred err = xfer->error; 614184610Salfred 615184610Salfred if (err) { 616184610Salfred break; 617184610Salfred } 618184610Salfred 619208018Sthompsa /* get actual length of DATA stage */ 620208018Sthompsa 621208018Sthompsa if (xfer->aframes < 2) { 622208018Sthompsa acttemp = 0; 623184610Salfred } else { 624208018Sthompsa acttemp = usbd_xfer_frame_len(xfer, 1); 625184610Salfred } 626184610Salfred 627184610Salfred /* check for short packet */ 628184610Salfred 629208018Sthompsa if (temp > acttemp) { 630208018Sthompsa temp = acttemp; 631184610Salfred length = temp; 632184610Salfred } 633184610Salfred if (temp > 0) { 634184610Salfred if (req->bmRequestType & UT_READ) { 635190180Sthompsa#if USB_HAVE_USER_IO 636184610Salfred if (flags & USB_USER_DATA_PTR) { 637184824Sthompsa USB_XFER_UNLOCK(xfer); 638194228Sthompsa err = usbd_copy_out_user(xfer->frbuffers + 1, 639184610Salfred 0, data, temp); 640184824Sthompsa USB_XFER_LOCK(xfer); 641184610Salfred if (err) { 642184610Salfred err = USB_ERR_INVAL; 643184610Salfred break; 644184610Salfred } 645190180Sthompsa } else 646190180Sthompsa#endif 647194228Sthompsa usbd_copy_out(xfer->frbuffers + 1, 648184610Salfred 0, data, temp); 649184610Salfred } 650184610Salfred } 651184610Salfred /* 652184610Salfred * Clear "frlengths[0]" so that we don't send the setup 653184610Salfred * packet again: 654184610Salfred */ 655194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, 0); 656184610Salfred 657184610Salfred /* update length and data pointer */ 658184610Salfred length -= temp; 659184610Salfred data = USB_ADD_BYTES(data, temp); 660184610Salfred 661184610Salfred if (actlen) { 662184610Salfred (*actlen) += temp; 663184610Salfred } 664184610Salfred /* check for timeout */ 665184610Salfred 666184610Salfred delta_ticks = ticks - start_ticks; 667184610Salfred if (delta_ticks > max_ticks) { 668184610Salfred if (!err) { 669184610Salfred err = USB_ERR_TIMEOUT; 670184610Salfred } 671184610Salfred } 672184610Salfred if (err) { 673184610Salfred break; 674184610Salfred } 675184610Salfred } 676184610Salfred 677184610Salfred if (err) { 678184610Salfred /* 679184610Salfred * Make sure that the control endpoint is no longer 680184610Salfred * blocked in case of a non-transfer related error: 681184610Salfred */ 682194228Sthompsa usbd_transfer_stop(xfer); 683184610Salfred } 684184824Sthompsa USB_XFER_UNLOCK(xfer); 685184610Salfred 686184610Salfreddone: 687207079Sthompsa sx_xunlock(&udev->ctrl_sx); 688184610Salfred 689208008Sthompsa if (enum_locked) 690208008Sthompsa usbd_sr_lock(udev); 691208008Sthompsa 692208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) 693184610Salfred mtx_lock(mtx); 694208008Sthompsa 695193045Sthompsa return ((usb_error_t)err); 696184610Salfred} 697184610Salfred 698184610Salfred/*------------------------------------------------------------------------* 699194228Sthompsa * usbd_do_request_proc - factored out code 700188411Sthompsa * 701188411Sthompsa * This function is factored out code. It does basically the same like 702194228Sthompsa * usbd_do_request_flags, except it will check the status of the 703188411Sthompsa * passed process argument before doing the USB request. If the 704188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It 705188411Sthompsa * is assumed that the mutex associated with the process is locked 706188411Sthompsa * when calling this function. 707188411Sthompsa *------------------------------------------------------------------------*/ 708193045Sthompsausb_error_t 709194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 710192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 711193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 712188411Sthompsa{ 713193045Sthompsa usb_error_t err; 714188411Sthompsa uint16_t len; 715188411Sthompsa 716188411Sthompsa /* get request data length */ 717188411Sthompsa len = UGETW(req->wLength); 718188411Sthompsa 719188411Sthompsa /* check if the device is being detached */ 720194228Sthompsa if (usb_proc_is_gone(pproc)) { 721188411Sthompsa err = USB_ERR_IOERROR; 722188411Sthompsa goto done; 723188411Sthompsa } 724188411Sthompsa 725188411Sthompsa /* forward the USB request */ 726194228Sthompsa err = usbd_do_request_flags(udev, pproc->up_mtx, 727188411Sthompsa req, data, flags, actlen, timeout); 728188411Sthompsa 729188411Sthompsadone: 730188411Sthompsa /* on failure we zero the data */ 731188411Sthompsa /* on short packet we zero the unused data */ 732188411Sthompsa if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 733188411Sthompsa if (err) 734188411Sthompsa memset(data, 0, len); 735188411Sthompsa else if (actlen && *actlen != len) 736188411Sthompsa memset(((uint8_t *)data) + *actlen, 0, len - *actlen); 737188411Sthompsa } 738188411Sthompsa return (err); 739188411Sthompsa} 740188411Sthompsa 741188411Sthompsa/*------------------------------------------------------------------------* 742194228Sthompsa * usbd_req_reset_port 743184610Salfred * 744214804Shselasky * This function will instruct a USB HUB to perform a reset sequence 745184610Salfred * on the specified port number. 746184610Salfred * 747184610Salfred * Returns: 748184610Salfred * 0: Success. The USB device should now be at address zero. 749184610Salfred * Else: Failure. No USB device is present and the USB port should be 750184610Salfred * disabled. 751184610Salfred *------------------------------------------------------------------------*/ 752193045Sthompsausb_error_t 753194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 754184610Salfred{ 755192984Sthompsa struct usb_port_status ps; 756193045Sthompsa usb_error_t err; 757184610Salfred uint16_t n; 758184610Salfred 759207077Sthompsa#ifdef USB_DEBUG 760184610Salfred uint16_t pr_poll_delay; 761184610Salfred uint16_t pr_recovery_delay; 762184610Salfred 763184610Salfred#endif 764194228Sthompsa err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET); 765184610Salfred if (err) { 766184610Salfred goto done; 767184610Salfred } 768207077Sthompsa#ifdef USB_DEBUG 769184610Salfred /* range check input parameters */ 770194228Sthompsa pr_poll_delay = usb_pr_poll_delay; 771184610Salfred if (pr_poll_delay < 1) { 772184610Salfred pr_poll_delay = 1; 773184610Salfred } else if (pr_poll_delay > 1000) { 774184610Salfred pr_poll_delay = 1000; 775184610Salfred } 776194228Sthompsa pr_recovery_delay = usb_pr_recovery_delay; 777184610Salfred if (pr_recovery_delay > 1000) { 778184610Salfred pr_recovery_delay = 1000; 779184610Salfred } 780184610Salfred#endif 781184610Salfred n = 0; 782184610Salfred while (1) { 783207077Sthompsa#ifdef USB_DEBUG 784184610Salfred /* wait for the device to recover from reset */ 785194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 786184610Salfred n += pr_poll_delay; 787184610Salfred#else 788184610Salfred /* wait for the device to recover from reset */ 789194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 790184610Salfred n += USB_PORT_RESET_DELAY; 791184610Salfred#endif 792194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 793184610Salfred if (err) { 794184610Salfred goto done; 795184610Salfred } 796216249Shselasky /* if the device disappeared, just give up */ 797216249Shselasky if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) { 798216249Shselasky goto done; 799216249Shselasky } 800214804Shselasky /* check if reset is complete */ 801214804Shselasky if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) { 802214804Shselasky break; 803214804Shselasky } 804214804Shselasky /* check for timeout */ 805214804Shselasky if (n > 1000) { 806214804Shselasky n = 0; 807214804Shselasky break; 808214804Shselasky } 809214804Shselasky } 810214804Shselasky 811214804Shselasky /* clear port reset first */ 812214804Shselasky err = usbd_req_clear_port_feature( 813214804Shselasky udev, mtx, port, UHF_C_PORT_RESET); 814214804Shselasky if (err) { 815214804Shselasky goto done; 816214804Shselasky } 817214804Shselasky /* check for timeout */ 818214804Shselasky if (n == 0) { 819214804Shselasky err = USB_ERR_TIMEOUT; 820214804Shselasky goto done; 821214804Shselasky } 822214804Shselasky#ifdef USB_DEBUG 823214804Shselasky /* wait for the device to recover from reset */ 824214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 825214804Shselasky#else 826214804Shselasky /* wait for the device to recover from reset */ 827214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 828214804Shselasky#endif 829214804Shselasky 830214804Shselaskydone: 831214804Shselasky DPRINTFN(2, "port %d reset returning error=%s\n", 832214804Shselasky port, usbd_errstr(err)); 833214804Shselasky return (err); 834214804Shselasky} 835214804Shselasky 836214804Shselasky/*------------------------------------------------------------------------* 837214804Shselasky * usbd_req_warm_reset_port 838214804Shselasky * 839214804Shselasky * This function will instruct an USB HUB to perform a warm reset 840214804Shselasky * sequence on the specified port number. This kind of reset is not 841214804Shselasky * mandatory for LOW-, FULL- and HIGH-speed USB HUBs and is targeted 842214804Shselasky * for SUPER-speed USB HUBs. 843214804Shselasky * 844214804Shselasky * Returns: 845214804Shselasky * 0: Success. The USB device should now be available again. 846214804Shselasky * Else: Failure. No USB device is present and the USB port should be 847214804Shselasky * disabled. 848214804Shselasky *------------------------------------------------------------------------*/ 849214804Shselaskyusb_error_t 850214804Shselaskyusbd_req_warm_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 851214804Shselasky{ 852214804Shselasky struct usb_port_status ps; 853214804Shselasky usb_error_t err; 854214804Shselasky uint16_t n; 855214804Shselasky 856214804Shselasky#ifdef USB_DEBUG 857214804Shselasky uint16_t pr_poll_delay; 858214804Shselasky uint16_t pr_recovery_delay; 859214804Shselasky 860214804Shselasky#endif 861214804Shselasky err = usbd_req_set_port_feature(udev, mtx, port, UHF_BH_PORT_RESET); 862214804Shselasky if (err) { 863214804Shselasky goto done; 864214804Shselasky } 865214804Shselasky#ifdef USB_DEBUG 866214804Shselasky /* range check input parameters */ 867214804Shselasky pr_poll_delay = usb_pr_poll_delay; 868214804Shselasky if (pr_poll_delay < 1) { 869214804Shselasky pr_poll_delay = 1; 870214804Shselasky } else if (pr_poll_delay > 1000) { 871214804Shselasky pr_poll_delay = 1000; 872214804Shselasky } 873214804Shselasky pr_recovery_delay = usb_pr_recovery_delay; 874214804Shselasky if (pr_recovery_delay > 1000) { 875214804Shselasky pr_recovery_delay = 1000; 876214804Shselasky } 877214804Shselasky#endif 878214804Shselasky n = 0; 879214804Shselasky while (1) { 880214804Shselasky#ifdef USB_DEBUG 881214804Shselasky /* wait for the device to recover from reset */ 882214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 883214804Shselasky n += pr_poll_delay; 884214804Shselasky#else 885214804Shselasky /* wait for the device to recover from reset */ 886214804Shselasky usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 887214804Shselasky n += USB_PORT_RESET_DELAY; 888214804Shselasky#endif 889214804Shselasky err = usbd_req_get_port_status(udev, mtx, &ps, port); 890214804Shselasky if (err) { 891214804Shselasky goto done; 892214804Shselasky } 893184610Salfred /* if the device disappeared, just give up */ 894184610Salfred if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) { 895184610Salfred goto done; 896184610Salfred } 897184610Salfred /* check if reset is complete */ 898214804Shselasky if (UGETW(ps.wPortChange) & UPS_C_BH_PORT_RESET) { 899184610Salfred break; 900184610Salfred } 901184610Salfred /* check for timeout */ 902184610Salfred if (n > 1000) { 903184610Salfred n = 0; 904184610Salfred break; 905184610Salfred } 906184610Salfred } 907184610Salfred 908184610Salfred /* clear port reset first */ 909194228Sthompsa err = usbd_req_clear_port_feature( 910214804Shselasky udev, mtx, port, UHF_C_BH_PORT_RESET); 911184610Salfred if (err) { 912184610Salfred goto done; 913184610Salfred } 914184610Salfred /* check for timeout */ 915184610Salfred if (n == 0) { 916184610Salfred err = USB_ERR_TIMEOUT; 917184610Salfred goto done; 918184610Salfred } 919207077Sthompsa#ifdef USB_DEBUG 920184610Salfred /* wait for the device to recover from reset */ 921194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 922184610Salfred#else 923184610Salfred /* wait for the device to recover from reset */ 924194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 925184610Salfred#endif 926184610Salfred 927184610Salfreddone: 928214804Shselasky DPRINTFN(2, "port %d warm reset returning error=%s\n", 929194228Sthompsa port, usbd_errstr(err)); 930184610Salfred return (err); 931184610Salfred} 932184610Salfred 933184610Salfred/*------------------------------------------------------------------------* 934194228Sthompsa * usbd_req_get_desc 935184610Salfred * 936184610Salfred * This function can be used to retrieve USB descriptors. It contains 937184610Salfred * some additional logic like zeroing of missing descriptor bytes and 938184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 939184610Salfred * argument specifies the minimum descriptor length. The "max_len" 940184610Salfred * argument specifies the maximum descriptor length. If the real 941184610Salfred * descriptor length is less than the minimum length the missing 942188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 943188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 944188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 945188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 946188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 947188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 948188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 949188985Sthompsa * "max_len" then this function will try to retrive the beginning of 950188985Sthompsa * the descriptor and base the maximum length on the first byte of the 951188985Sthompsa * descriptor. 952184610Salfred * 953184610Salfred * Returns: 954184610Salfred * 0: Success 955184610Salfred * Else: Failure 956184610Salfred *------------------------------------------------------------------------*/ 957193045Sthompsausb_error_t 958194228Sthompsausbd_req_get_desc(struct usb_device *udev, 959188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 960184610Salfred uint16_t min_len, uint16_t max_len, 961184610Salfred uint16_t id, uint8_t type, uint8_t index, 962184610Salfred uint8_t retries) 963184610Salfred{ 964192984Sthompsa struct usb_device_request req; 965184610Salfred uint8_t *buf; 966193045Sthompsa usb_error_t err; 967184610Salfred 968184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 969184610Salfred id, type, index, max_len); 970184610Salfred 971184610Salfred req.bmRequestType = UT_READ_DEVICE; 972184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 973184610Salfred USETW2(req.wValue, type, index); 974184610Salfred USETW(req.wIndex, id); 975184610Salfred 976184610Salfred while (1) { 977184610Salfred 978184610Salfred if ((min_len < 2) || (max_len < 2)) { 979184610Salfred err = USB_ERR_INVAL; 980184610Salfred goto done; 981184610Salfred } 982184610Salfred USETW(req.wLength, min_len); 983184610Salfred 984194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 985186730Salfred desc, 0, NULL, 1000); 986184610Salfred 987184610Salfred if (err) { 988184610Salfred if (!retries) { 989184610Salfred goto done; 990184610Salfred } 991184610Salfred retries--; 992184610Salfred 993194228Sthompsa usb_pause_mtx(mtx, hz / 5); 994184610Salfred 995184610Salfred continue; 996184610Salfred } 997184610Salfred buf = desc; 998184610Salfred 999184610Salfred if (min_len == max_len) { 1000184610Salfred 1001188985Sthompsa /* enforce correct length */ 1002188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 1003188985Sthompsa buf[0] = min_len; 1004184610Salfred 1005188985Sthompsa /* enforce correct type */ 1006184610Salfred buf[1] = type; 1007184610Salfred 1008184610Salfred goto done; 1009184610Salfred } 1010184610Salfred /* range check */ 1011184610Salfred 1012184610Salfred if (max_len > buf[0]) { 1013184610Salfred max_len = buf[0]; 1014184610Salfred } 1015184610Salfred /* zero minimum data */ 1016184610Salfred 1017184610Salfred while (min_len > max_len) { 1018184610Salfred min_len--; 1019184610Salfred buf[min_len] = 0; 1020184610Salfred } 1021184610Salfred 1022184610Salfred /* set new minimum length */ 1023184610Salfred 1024184610Salfred min_len = max_len; 1025184610Salfred } 1026184610Salfreddone: 1027188985Sthompsa if (actlen != NULL) { 1028188985Sthompsa if (err) 1029188985Sthompsa *actlen = 0; 1030188985Sthompsa else 1031188985Sthompsa *actlen = min_len; 1032188985Sthompsa } 1033184610Salfred return (err); 1034184610Salfred} 1035184610Salfred 1036184610Salfred/*------------------------------------------------------------------------* 1037194228Sthompsa * usbd_req_get_string_any 1038184610Salfred * 1039184610Salfred * This function will return the string given by "string_index" 1040184610Salfred * using the first language ID. The maximum length "len" includes 1041184610Salfred * the terminating zero. The "len" argument should be twice as 1042184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 1043184610Salfred * 1044184610Salfred * Returns: 1045184610Salfred * 0: Success 1046184610Salfred * Else: Failure 1047184610Salfred *------------------------------------------------------------------------*/ 1048193045Sthompsausb_error_t 1049194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 1050184610Salfred uint16_t len, uint8_t string_index) 1051184610Salfred{ 1052184610Salfred char *s; 1053184610Salfred uint8_t *temp; 1054184610Salfred uint16_t i; 1055184610Salfred uint16_t n; 1056184610Salfred uint16_t c; 1057184610Salfred uint8_t swap; 1058193045Sthompsa usb_error_t err; 1059184610Salfred 1060184610Salfred if (len == 0) { 1061184610Salfred /* should not happen */ 1062184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1063184610Salfred } 1064184610Salfred if (string_index == 0) { 1065184610Salfred /* this is the language table */ 1066185087Salfred buf[0] = 0; 1067184610Salfred return (USB_ERR_INVAL); 1068184610Salfred } 1069184610Salfred if (udev->flags.no_strings) { 1070185087Salfred buf[0] = 0; 1071184610Salfred return (USB_ERR_STALLED); 1072184610Salfred } 1073194228Sthompsa err = usbd_req_get_string_desc 1074184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 1075184610Salfred if (err) { 1076185087Salfred buf[0] = 0; 1077184610Salfred return (err); 1078184610Salfred } 1079184610Salfred temp = (uint8_t *)buf; 1080184610Salfred 1081184610Salfred if (temp[0] < 2) { 1082184610Salfred /* string length is too short */ 1083185087Salfred buf[0] = 0; 1084184610Salfred return (USB_ERR_INVAL); 1085184610Salfred } 1086184610Salfred /* reserve one byte for terminating zero */ 1087184610Salfred len--; 1088184610Salfred 1089184610Salfred /* find maximum length */ 1090184610Salfred s = buf; 1091184610Salfred n = (temp[0] / 2) - 1; 1092184610Salfred if (n > len) { 1093184610Salfred n = len; 1094184610Salfred } 1095184610Salfred /* skip descriptor header */ 1096184610Salfred temp += 2; 1097184610Salfred 1098184610Salfred /* reset swap state */ 1099184610Salfred swap = 3; 1100184610Salfred 1101184610Salfred /* convert and filter */ 1102184610Salfred for (i = 0; (i != n); i++) { 1103184610Salfred c = UGETW(temp + (2 * i)); 1104184610Salfred 1105184610Salfred /* convert from Unicode, handle buggy strings */ 1106184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 1107184610Salfred /* Little Endian, default */ 1108184610Salfred *s = c; 1109184610Salfred swap = 1; 1110184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1111184610Salfred /* Big Endian */ 1112184610Salfred *s = c >> 8; 1113184610Salfred swap = 2; 1114184610Salfred } else { 1115185087Salfred /* silently skip bad character */ 1116185087Salfred continue; 1117184610Salfred } 1118184610Salfred 1119184610Salfred /* 1120213433Shselasky * Filter by default - We only allow alphanumerical 1121213433Shselasky * and a few more to avoid any problems with scripts 1122213433Shselasky * and daemons. 1123184610Salfred */ 1124213433Shselasky if (isalpha(*s) || 1125213433Shselasky isdigit(*s) || 1126213433Shselasky *s == '-' || 1127213433Shselasky *s == '+' || 1128213433Shselasky *s == ' ' || 1129213433Shselasky *s == '.' || 1130213433Shselasky *s == ',') { 1131213433Shselasky /* allowed */ 1132213433Shselasky s++; 1133184610Salfred } 1134213433Shselasky /* silently skip bad character */ 1135184610Salfred } 1136185087Salfred *s = 0; /* zero terminate resulting string */ 1137184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1138184610Salfred} 1139184610Salfred 1140184610Salfred/*------------------------------------------------------------------------* 1141194228Sthompsa * usbd_req_get_string_desc 1142184610Salfred * 1143184610Salfred * If you don't know the language ID, consider using 1144194228Sthompsa * "usbd_req_get_string_any()". 1145184610Salfred * 1146184610Salfred * Returns: 1147184610Salfred * 0: Success 1148184610Salfred * Else: Failure 1149184610Salfred *------------------------------------------------------------------------*/ 1150193045Sthompsausb_error_t 1151194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1152184610Salfred uint16_t max_len, uint16_t lang_id, 1153184610Salfred uint8_t string_index) 1154184610Salfred{ 1155194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1156184610Salfred UDESC_STRING, string_index, 0)); 1157184610Salfred} 1158184610Salfred 1159184610Salfred/*------------------------------------------------------------------------* 1160194228Sthompsa * usbd_req_get_config_desc_ptr 1161190727Sthompsa * 1162190727Sthompsa * This function is used in device side mode to retrieve the pointer 1163190727Sthompsa * to the generated config descriptor. This saves allocating space for 1164190727Sthompsa * an additional config descriptor when setting the configuration. 1165190727Sthompsa * 1166190727Sthompsa * Returns: 1167190727Sthompsa * 0: Success 1168190727Sthompsa * Else: Failure 1169190727Sthompsa *------------------------------------------------------------------------*/ 1170193045Sthompsausb_error_t 1171194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 1172192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 1173190727Sthompsa{ 1174192984Sthompsa struct usb_device_request req; 1175193045Sthompsa usb_handle_req_t *hr_func; 1176191402Sthompsa const void *ptr; 1177190727Sthompsa uint16_t len; 1178193045Sthompsa usb_error_t err; 1179190727Sthompsa 1180190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 1181190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 1182191402Sthompsa USETW(req.wValue, wValue); 1183190727Sthompsa USETW(req.wIndex, 0); 1184190727Sthompsa USETW(req.wLength, 0); 1185190727Sthompsa 1186191402Sthompsa ptr = NULL; 1187191402Sthompsa len = 0; 1188190727Sthompsa 1189194228Sthompsa hr_func = usbd_get_hr_func(udev); 1190191402Sthompsa 1191191402Sthompsa if (hr_func == NULL) 1192191402Sthompsa err = USB_ERR_INVAL; 1193191402Sthompsa else { 1194191402Sthompsa USB_BUS_LOCK(udev->bus); 1195191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 1196191402Sthompsa USB_BUS_UNLOCK(udev->bus); 1197191402Sthompsa } 1198191402Sthompsa 1199191402Sthompsa if (err) 1200191402Sthompsa ptr = NULL; 1201191402Sthompsa else if (ptr == NULL) 1202191402Sthompsa err = USB_ERR_INVAL; 1203191402Sthompsa 1204192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1205191402Sthompsa 1206191402Sthompsa return (err); 1207190727Sthompsa} 1208190727Sthompsa 1209190727Sthompsa/*------------------------------------------------------------------------* 1210194228Sthompsa * usbd_req_get_config_desc 1211184610Salfred * 1212184610Salfred * Returns: 1213184610Salfred * 0: Success 1214184610Salfred * Else: Failure 1215184610Salfred *------------------------------------------------------------------------*/ 1216193045Sthompsausb_error_t 1217194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1218192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 1219184610Salfred{ 1220193045Sthompsa usb_error_t err; 1221184610Salfred 1222184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 1223184610Salfred 1224194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1225184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1226184610Salfred if (err) { 1227184610Salfred goto done; 1228184610Salfred } 1229184610Salfred /* Extra sanity checking */ 1230184610Salfred if (UGETW(d->wTotalLength) < sizeof(*d)) { 1231184610Salfred err = USB_ERR_INVAL; 1232184610Salfred } 1233184610Salfreddone: 1234184610Salfred return (err); 1235184610Salfred} 1236184610Salfred 1237184610Salfred/*------------------------------------------------------------------------* 1238194228Sthompsa * usbd_req_get_config_desc_full 1239184610Salfred * 1240184610Salfred * This function gets the complete USB configuration descriptor and 1241184610Salfred * ensures that "wTotalLength" is correct. 1242184610Salfred * 1243184610Salfred * Returns: 1244184610Salfred * 0: Success 1245184610Salfred * Else: Failure 1246184610Salfred *------------------------------------------------------------------------*/ 1247193045Sthompsausb_error_t 1248194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1249192984Sthompsa struct usb_config_descriptor **ppcd, struct malloc_type *mtype, 1250184610Salfred uint8_t index) 1251184610Salfred{ 1252192984Sthompsa struct usb_config_descriptor cd; 1253192984Sthompsa struct usb_config_descriptor *cdesc; 1254184610Salfred uint16_t len; 1255193045Sthompsa usb_error_t err; 1256184610Salfred 1257184610Salfred DPRINTFN(4, "index=%d\n", index); 1258184610Salfred 1259184610Salfred *ppcd = NULL; 1260184610Salfred 1261194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1262184610Salfred if (err) { 1263184610Salfred return (err); 1264184610Salfred } 1265184610Salfred /* get full descriptor */ 1266184610Salfred len = UGETW(cd.wTotalLength); 1267184610Salfred if (len < sizeof(*cdesc)) { 1268184610Salfred /* corrupt descriptor */ 1269184610Salfred return (USB_ERR_INVAL); 1270184610Salfred } 1271184610Salfred cdesc = malloc(len, mtype, M_WAITOK); 1272184610Salfred if (cdesc == NULL) { 1273184610Salfred return (USB_ERR_NOMEM); 1274184610Salfred } 1275194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1276184610Salfred UDESC_CONFIG, index, 3); 1277184610Salfred if (err) { 1278184610Salfred free(cdesc, mtype); 1279184610Salfred return (err); 1280184610Salfred } 1281184610Salfred /* make sure that the device is not fooling us: */ 1282184610Salfred USETW(cdesc->wTotalLength, len); 1283184610Salfred 1284184610Salfred *ppcd = cdesc; 1285184610Salfred 1286184610Salfred return (0); /* success */ 1287184610Salfred} 1288184610Salfred 1289184610Salfred/*------------------------------------------------------------------------* 1290194228Sthompsa * usbd_req_get_device_desc 1291184610Salfred * 1292184610Salfred * Returns: 1293184610Salfred * 0: Success 1294184610Salfred * Else: Failure 1295184610Salfred *------------------------------------------------------------------------*/ 1296193045Sthompsausb_error_t 1297194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1298192984Sthompsa struct usb_device_descriptor *d) 1299184610Salfred{ 1300184610Salfred DPRINTFN(4, "\n"); 1301194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1302184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1303184610Salfred} 1304184610Salfred 1305184610Salfred/*------------------------------------------------------------------------* 1306194228Sthompsa * usbd_req_get_alt_interface_no 1307184610Salfred * 1308184610Salfred * Returns: 1309184610Salfred * 0: Success 1310184610Salfred * Else: Failure 1311184610Salfred *------------------------------------------------------------------------*/ 1312193045Sthompsausb_error_t 1313194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1314184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 1315184610Salfred{ 1316194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1317192984Sthompsa struct usb_device_request req; 1318184610Salfred 1319195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1320184610Salfred return (USB_ERR_INVAL); 1321195963Salfred 1322184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1323184610Salfred req.bRequest = UR_GET_INTERFACE; 1324184610Salfred USETW(req.wValue, 0); 1325184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1326184610Salfred req.wIndex[1] = 0; 1327184610Salfred USETW(req.wLength, 1); 1328194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1329184610Salfred} 1330184610Salfred 1331184610Salfred/*------------------------------------------------------------------------* 1332194228Sthompsa * usbd_req_set_alt_interface_no 1333184610Salfred * 1334184610Salfred * Returns: 1335184610Salfred * 0: Success 1336184610Salfred * Else: Failure 1337184610Salfred *------------------------------------------------------------------------*/ 1338193045Sthompsausb_error_t 1339194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1340184610Salfred uint8_t iface_index, uint8_t alt_no) 1341184610Salfred{ 1342194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1343192984Sthompsa struct usb_device_request req; 1344184610Salfred 1345195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1346184610Salfred return (USB_ERR_INVAL); 1347195963Salfred 1348184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1349184610Salfred req.bRequest = UR_SET_INTERFACE; 1350184610Salfred req.wValue[0] = alt_no; 1351184610Salfred req.wValue[1] = 0; 1352184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1353184610Salfred req.wIndex[1] = 0; 1354184610Salfred USETW(req.wLength, 0); 1355194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1356184610Salfred} 1357184610Salfred 1358184610Salfred/*------------------------------------------------------------------------* 1359194228Sthompsa * usbd_req_get_device_status 1360184610Salfred * 1361184610Salfred * Returns: 1362184610Salfred * 0: Success 1363184610Salfred * Else: Failure 1364184610Salfred *------------------------------------------------------------------------*/ 1365193045Sthompsausb_error_t 1366194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1367192984Sthompsa struct usb_status *st) 1368184610Salfred{ 1369192984Sthompsa struct usb_device_request req; 1370184610Salfred 1371184610Salfred req.bmRequestType = UT_READ_DEVICE; 1372184610Salfred req.bRequest = UR_GET_STATUS; 1373184610Salfred USETW(req.wValue, 0); 1374184610Salfred USETW(req.wIndex, 0); 1375184610Salfred USETW(req.wLength, sizeof(*st)); 1376194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1377184610Salfred} 1378184610Salfred 1379184610Salfred/*------------------------------------------------------------------------* 1380194228Sthompsa * usbd_req_get_hub_descriptor 1381184610Salfred * 1382184610Salfred * Returns: 1383184610Salfred * 0: Success 1384184610Salfred * Else: Failure 1385184610Salfred *------------------------------------------------------------------------*/ 1386193045Sthompsausb_error_t 1387194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1388192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1389184610Salfred{ 1390192984Sthompsa struct usb_device_request req; 1391184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1392184610Salfred 1393184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1394184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1395184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1396184610Salfred USETW(req.wIndex, 0); 1397184610Salfred USETW(req.wLength, len); 1398194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1399184610Salfred} 1400184610Salfred 1401184610Salfred/*------------------------------------------------------------------------* 1402213435Shselasky * usbd_req_get_ss_hub_descriptor 1403213435Shselasky * 1404213435Shselasky * Returns: 1405213435Shselasky * 0: Success 1406213435Shselasky * Else: Failure 1407213435Shselasky *------------------------------------------------------------------------*/ 1408213435Shselaskyusb_error_t 1409213435Shselaskyusbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1410213435Shselasky struct usb_hub_ss_descriptor *hd, uint8_t nports) 1411213435Shselasky{ 1412213435Shselasky struct usb_device_request req; 1413213435Shselasky uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); 1414213435Shselasky 1415213435Shselasky req.bmRequestType = UT_READ_CLASS_DEVICE; 1416213435Shselasky req.bRequest = UR_GET_DESCRIPTOR; 1417213435Shselasky USETW2(req.wValue, UDESC_SS_HUB, 0); 1418213435Shselasky USETW(req.wIndex, 0); 1419213435Shselasky USETW(req.wLength, len); 1420213435Shselasky return (usbd_do_request(udev, mtx, &req, hd)); 1421213435Shselasky} 1422213435Shselasky 1423213435Shselasky/*------------------------------------------------------------------------* 1424194228Sthompsa * usbd_req_get_hub_status 1425184610Salfred * 1426184610Salfred * Returns: 1427184610Salfred * 0: Success 1428184610Salfred * Else: Failure 1429184610Salfred *------------------------------------------------------------------------*/ 1430193045Sthompsausb_error_t 1431194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1432192984Sthompsa struct usb_hub_status *st) 1433184610Salfred{ 1434192984Sthompsa struct usb_device_request req; 1435184610Salfred 1436184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1437184610Salfred req.bRequest = UR_GET_STATUS; 1438184610Salfred USETW(req.wValue, 0); 1439184610Salfred USETW(req.wIndex, 0); 1440192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1441194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1442184610Salfred} 1443184610Salfred 1444184610Salfred/*------------------------------------------------------------------------* 1445194228Sthompsa * usbd_req_set_address 1446184610Salfred * 1447184610Salfred * This function is used to set the address for an USB device. After 1448184610Salfred * port reset the USB device will respond at address zero. 1449184610Salfred * 1450184610Salfred * Returns: 1451184610Salfred * 0: Success 1452184610Salfred * Else: Failure 1453184610Salfred *------------------------------------------------------------------------*/ 1454193045Sthompsausb_error_t 1455194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1456184610Salfred{ 1457192984Sthompsa struct usb_device_request req; 1458213435Shselasky usb_error_t err; 1459184610Salfred 1460184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1461184610Salfred 1462184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1463184610Salfred req.bRequest = UR_SET_ADDRESS; 1464184610Salfred USETW(req.wValue, addr); 1465184610Salfred USETW(req.wIndex, 0); 1466184610Salfred USETW(req.wLength, 0); 1467184610Salfred 1468213435Shselasky err = USB_ERR_INVAL; 1469213435Shselasky 1470213435Shselasky /* check if USB controller handles set address */ 1471213435Shselasky if (udev->bus->methods->set_address != NULL) 1472213435Shselasky err = (udev->bus->methods->set_address) (udev, mtx, addr); 1473213435Shselasky 1474213435Shselasky if (err != USB_ERR_INVAL) 1475213435Shselasky goto done; 1476213435Shselasky 1477184610Salfred /* Setting the address should not take more than 1 second ! */ 1478213435Shselasky err = usbd_do_request_flags(udev, mtx, &req, NULL, 1479213435Shselasky USB_DELAY_STATUS_STAGE, NULL, 1000); 1480213435Shselasky 1481213435Shselaskydone: 1482213435Shselasky /* allow device time to set new address */ 1483213435Shselasky usb_pause_mtx(mtx, 1484213435Shselasky USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); 1485213435Shselasky 1486213435Shselasky return (err); 1487184610Salfred} 1488184610Salfred 1489184610Salfred/*------------------------------------------------------------------------* 1490194228Sthompsa * usbd_req_get_port_status 1491184610Salfred * 1492184610Salfred * Returns: 1493184610Salfred * 0: Success 1494184610Salfred * Else: Failure 1495184610Salfred *------------------------------------------------------------------------*/ 1496193045Sthompsausb_error_t 1497194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1498192984Sthompsa struct usb_port_status *ps, uint8_t port) 1499184610Salfred{ 1500192984Sthompsa struct usb_device_request req; 1501184610Salfred 1502184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1503184610Salfred req.bRequest = UR_GET_STATUS; 1504184610Salfred USETW(req.wValue, 0); 1505184610Salfred req.wIndex[0] = port; 1506184610Salfred req.wIndex[1] = 0; 1507184610Salfred USETW(req.wLength, sizeof *ps); 1508194228Sthompsa return (usbd_do_request(udev, mtx, &req, ps)); 1509184610Salfred} 1510184610Salfred 1511184610Salfred/*------------------------------------------------------------------------* 1512194228Sthompsa * usbd_req_clear_hub_feature 1513184610Salfred * 1514184610Salfred * Returns: 1515184610Salfred * 0: Success 1516184610Salfred * Else: Failure 1517184610Salfred *------------------------------------------------------------------------*/ 1518193045Sthompsausb_error_t 1519194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1520184610Salfred uint16_t sel) 1521184610Salfred{ 1522192984Sthompsa struct usb_device_request req; 1523184610Salfred 1524184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1525184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1526184610Salfred USETW(req.wValue, sel); 1527184610Salfred USETW(req.wIndex, 0); 1528184610Salfred USETW(req.wLength, 0); 1529194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1530184610Salfred} 1531184610Salfred 1532184610Salfred/*------------------------------------------------------------------------* 1533194228Sthompsa * usbd_req_set_hub_feature 1534184610Salfred * 1535184610Salfred * Returns: 1536184610Salfred * 0: Success 1537184610Salfred * Else: Failure 1538184610Salfred *------------------------------------------------------------------------*/ 1539193045Sthompsausb_error_t 1540194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1541184610Salfred uint16_t sel) 1542184610Salfred{ 1543192984Sthompsa struct usb_device_request req; 1544184610Salfred 1545184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1546184610Salfred req.bRequest = UR_SET_FEATURE; 1547184610Salfred USETW(req.wValue, sel); 1548184610Salfred USETW(req.wIndex, 0); 1549184610Salfred USETW(req.wLength, 0); 1550194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1551184610Salfred} 1552184610Salfred 1553184610Salfred/*------------------------------------------------------------------------* 1554213435Shselasky * usbd_req_set_hub_u1_timeout 1555213435Shselasky * 1556213435Shselasky * Returns: 1557213435Shselasky * 0: Success 1558213435Shselasky * Else: Failure 1559213435Shselasky *------------------------------------------------------------------------*/ 1560213435Shselaskyusb_error_t 1561213435Shselaskyusbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, 1562213435Shselasky uint8_t port, uint8_t timeout) 1563213435Shselasky{ 1564213435Shselasky struct usb_device_request req; 1565213435Shselasky 1566213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1567213435Shselasky req.bRequest = UR_SET_FEATURE; 1568213435Shselasky USETW(req.wValue, UHF_PORT_U1_TIMEOUT); 1569213435Shselasky req.wIndex[0] = port; 1570213435Shselasky req.wIndex[1] = timeout; 1571213435Shselasky USETW(req.wLength, 0); 1572213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1573213435Shselasky} 1574213435Shselasky 1575213435Shselasky/*------------------------------------------------------------------------* 1576213435Shselasky * usbd_req_set_hub_u2_timeout 1577213435Shselasky * 1578213435Shselasky * Returns: 1579213435Shselasky * 0: Success 1580213435Shselasky * Else: Failure 1581213435Shselasky *------------------------------------------------------------------------*/ 1582213435Shselaskyusb_error_t 1583213435Shselaskyusbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, 1584213435Shselasky uint8_t port, uint8_t timeout) 1585213435Shselasky{ 1586213435Shselasky struct usb_device_request req; 1587213435Shselasky 1588213435Shselasky req.bmRequestType = UT_WRITE_CLASS_OTHER; 1589213435Shselasky req.bRequest = UR_SET_FEATURE; 1590213435Shselasky USETW(req.wValue, UHF_PORT_U2_TIMEOUT); 1591213435Shselasky req.wIndex[0] = port; 1592213435Shselasky req.wIndex[1] = timeout; 1593213435Shselasky USETW(req.wLength, 0); 1594213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1595213435Shselasky} 1596213435Shselasky 1597213435Shselasky/*------------------------------------------------------------------------* 1598213435Shselasky * usbd_req_set_hub_depth 1599213435Shselasky * 1600213435Shselasky * Returns: 1601213435Shselasky * 0: Success 1602213435Shselasky * Else: Failure 1603213435Shselasky *------------------------------------------------------------------------*/ 1604213435Shselaskyusb_error_t 1605213435Shselaskyusbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, 1606213435Shselasky uint16_t depth) 1607213435Shselasky{ 1608213435Shselasky struct usb_device_request req; 1609213435Shselasky 1610213435Shselasky req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1611213435Shselasky req.bRequest = UR_SET_HUB_DEPTH; 1612213435Shselasky USETW(req.wValue, depth); 1613213435Shselasky USETW(req.wIndex, 0); 1614213435Shselasky USETW(req.wLength, 0); 1615213435Shselasky return (usbd_do_request(udev, mtx, &req, 0)); 1616213435Shselasky} 1617213435Shselasky 1618213435Shselasky/*------------------------------------------------------------------------* 1619194228Sthompsa * usbd_req_clear_port_feature 1620184610Salfred * 1621184610Salfred * Returns: 1622184610Salfred * 0: Success 1623184610Salfred * Else: Failure 1624184610Salfred *------------------------------------------------------------------------*/ 1625193045Sthompsausb_error_t 1626194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1627184610Salfred uint8_t port, uint16_t sel) 1628184610Salfred{ 1629192984Sthompsa struct usb_device_request req; 1630184610Salfred 1631184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1632184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1633184610Salfred USETW(req.wValue, sel); 1634184610Salfred req.wIndex[0] = port; 1635184610Salfred req.wIndex[1] = 0; 1636184610Salfred USETW(req.wLength, 0); 1637194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1638184610Salfred} 1639184610Salfred 1640184610Salfred/*------------------------------------------------------------------------* 1641194228Sthompsa * usbd_req_set_port_feature 1642184610Salfred * 1643184610Salfred * Returns: 1644184610Salfred * 0: Success 1645184610Salfred * Else: Failure 1646184610Salfred *------------------------------------------------------------------------*/ 1647193045Sthompsausb_error_t 1648194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1649184610Salfred uint8_t port, uint16_t sel) 1650184610Salfred{ 1651192984Sthompsa struct usb_device_request req; 1652184610Salfred 1653184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1654184610Salfred req.bRequest = UR_SET_FEATURE; 1655184610Salfred USETW(req.wValue, sel); 1656184610Salfred req.wIndex[0] = port; 1657184610Salfred req.wIndex[1] = 0; 1658184610Salfred USETW(req.wLength, 0); 1659194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1660184610Salfred} 1661184610Salfred 1662184610Salfred/*------------------------------------------------------------------------* 1663194228Sthompsa * usbd_req_set_protocol 1664184610Salfred * 1665184610Salfred * Returns: 1666184610Salfred * 0: Success 1667184610Salfred * Else: Failure 1668184610Salfred *------------------------------------------------------------------------*/ 1669193045Sthompsausb_error_t 1670194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1671184610Salfred uint8_t iface_index, uint16_t report) 1672184610Salfred{ 1673194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1674192984Sthompsa struct usb_device_request req; 1675184610Salfred 1676184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1677184610Salfred return (USB_ERR_INVAL); 1678184610Salfred } 1679184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1680184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1681184610Salfred 1682184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1683184610Salfred req.bRequest = UR_SET_PROTOCOL; 1684184610Salfred USETW(req.wValue, report); 1685184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 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_report 1693184610Salfred * 1694184610Salfred * Returns: 1695184610Salfred * 0: Success 1696184610Salfred * Else: Failure 1697184610Salfred *------------------------------------------------------------------------*/ 1698193045Sthompsausb_error_t 1699194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1700184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 1701184610Salfred{ 1702194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1703192984Sthompsa struct usb_device_request req; 1704184610Salfred 1705184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1706184610Salfred return (USB_ERR_INVAL); 1707184610Salfred } 1708184610Salfred DPRINTFN(5, "len=%d\n", len); 1709184610Salfred 1710184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1711184610Salfred req.bRequest = UR_SET_REPORT; 1712184610Salfred USETW2(req.wValue, type, id); 1713184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1714184610Salfred req.wIndex[1] = 0; 1715184610Salfred USETW(req.wLength, len); 1716194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1717184610Salfred} 1718184610Salfred 1719184610Salfred/*------------------------------------------------------------------------* 1720194228Sthompsa * usbd_req_get_report 1721184610Salfred * 1722184610Salfred * Returns: 1723184610Salfred * 0: Success 1724184610Salfred * Else: Failure 1725184610Salfred *------------------------------------------------------------------------*/ 1726193045Sthompsausb_error_t 1727194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1728184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1729184610Salfred{ 1730194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1731192984Sthompsa struct usb_device_request req; 1732184610Salfred 1733184610Salfred if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) { 1734184610Salfred return (USB_ERR_INVAL); 1735184610Salfred } 1736184610Salfred DPRINTFN(5, "len=%d\n", len); 1737184610Salfred 1738184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1739184610Salfred req.bRequest = UR_GET_REPORT; 1740184610Salfred USETW2(req.wValue, type, id); 1741184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1742184610Salfred req.wIndex[1] = 0; 1743184610Salfred USETW(req.wLength, len); 1744194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1745184610Salfred} 1746184610Salfred 1747184610Salfred/*------------------------------------------------------------------------* 1748194228Sthompsa * usbd_req_set_idle 1749184610Salfred * 1750184610Salfred * Returns: 1751184610Salfred * 0: Success 1752184610Salfred * Else: Failure 1753184610Salfred *------------------------------------------------------------------------*/ 1754193045Sthompsausb_error_t 1755194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1756184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1757184610Salfred{ 1758194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1759192984Sthompsa struct usb_device_request req; 1760184610Salfred 1761184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1762184610Salfred return (USB_ERR_INVAL); 1763184610Salfred } 1764184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1765184610Salfred 1766184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1767184610Salfred req.bRequest = UR_SET_IDLE; 1768184610Salfred USETW2(req.wValue, duration, id); 1769184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1770184610Salfred req.wIndex[1] = 0; 1771184610Salfred USETW(req.wLength, 0); 1772194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1773184610Salfred} 1774184610Salfred 1775184610Salfred/*------------------------------------------------------------------------* 1776194228Sthompsa * usbd_req_get_report_descriptor 1777184610Salfred * 1778184610Salfred * Returns: 1779184610Salfred * 0: Success 1780184610Salfred * Else: Failure 1781184610Salfred *------------------------------------------------------------------------*/ 1782193045Sthompsausb_error_t 1783194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1784184610Salfred void *d, uint16_t size, uint8_t iface_index) 1785184610Salfred{ 1786194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1787192984Sthompsa struct usb_device_request req; 1788184610Salfred 1789184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1790184610Salfred return (USB_ERR_INVAL); 1791184610Salfred } 1792184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1793184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1794184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1795184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1796184610Salfred req.wIndex[1] = 0; 1797184610Salfred USETW(req.wLength, size); 1798194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1799184610Salfred} 1800184610Salfred 1801184610Salfred/*------------------------------------------------------------------------* 1802194228Sthompsa * usbd_req_set_config 1803184610Salfred * 1804184610Salfred * This function is used to select the current configuration number in 1805184610Salfred * both USB device side mode and USB host side mode. When setting the 1806184610Salfred * configuration the function of the interfaces can change. 1807184610Salfred * 1808184610Salfred * Returns: 1809184610Salfred * 0: Success 1810184610Salfred * Else: Failure 1811184610Salfred *------------------------------------------------------------------------*/ 1812193045Sthompsausb_error_t 1813194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1814184610Salfred{ 1815192984Sthompsa struct usb_device_request req; 1816184610Salfred 1817184610Salfred DPRINTF("setting config %d\n", conf); 1818184610Salfred 1819184610Salfred /* do "set configuration" request */ 1820184610Salfred 1821184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1822184610Salfred req.bRequest = UR_SET_CONFIG; 1823184610Salfred req.wValue[0] = conf; 1824184610Salfred req.wValue[1] = 0; 1825184610Salfred USETW(req.wIndex, 0); 1826184610Salfred USETW(req.wLength, 0); 1827194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1828184610Salfred} 1829184610Salfred 1830184610Salfred/*------------------------------------------------------------------------* 1831194228Sthompsa * usbd_req_get_config 1832184610Salfred * 1833184610Salfred * Returns: 1834184610Salfred * 0: Success 1835184610Salfred * Else: Failure 1836184610Salfred *------------------------------------------------------------------------*/ 1837193045Sthompsausb_error_t 1838194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1839184610Salfred{ 1840192984Sthompsa struct usb_device_request req; 1841184610Salfred 1842184610Salfred req.bmRequestType = UT_READ_DEVICE; 1843184610Salfred req.bRequest = UR_GET_CONFIG; 1844184610Salfred USETW(req.wValue, 0); 1845184610Salfred USETW(req.wIndex, 0); 1846184610Salfred USETW(req.wLength, 1); 1847194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1848184610Salfred} 1849184610Salfred 1850184610Salfred/*------------------------------------------------------------------------* 1851213435Shselasky * usbd_setup_device_desc 1852213435Shselasky *------------------------------------------------------------------------*/ 1853213435Shselaskyusb_error_t 1854213435Shselaskyusbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) 1855213435Shselasky{ 1856213435Shselasky usb_error_t err; 1857213435Shselasky 1858213435Shselasky /* 1859213435Shselasky * Get the first 8 bytes of the device descriptor ! 1860213435Shselasky * 1861213435Shselasky * NOTE: "usbd_do_request()" will check the device descriptor 1862213435Shselasky * next time we do a request to see if the maximum packet size 1863213435Shselasky * changed! The 8 first bytes of the device descriptor 1864213435Shselasky * contains the maximum packet size to use on control endpoint 1865213435Shselasky * 0. If this value is different from "USB_MAX_IPACKET" a new 1866213435Shselasky * USB control request will be setup! 1867213435Shselasky */ 1868213435Shselasky switch (udev->speed) { 1869213435Shselasky case USB_SPEED_FULL: 1870213435Shselasky case USB_SPEED_LOW: 1871213435Shselasky err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1872213435Shselasky USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1873213435Shselasky if (err != 0) { 1874213435Shselasky DPRINTFN(0, "getting device descriptor " 1875213435Shselasky "at addr %d failed, %s\n", udev->address, 1876213435Shselasky usbd_errstr(err)); 1877213435Shselasky return (err); 1878213435Shselasky } 1879213435Shselasky break; 1880213435Shselasky default: 1881213435Shselasky DPRINTF("Minimum MaxPacketSize is large enough " 1882213435Shselasky "to hold the complete device descriptor\n"); 1883213435Shselasky break; 1884213435Shselasky } 1885213435Shselasky 1886213435Shselasky /* get the full device descriptor */ 1887213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1888213435Shselasky 1889213435Shselasky /* try one more time, if error */ 1890213435Shselasky if (err) 1891213435Shselasky err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1892213435Shselasky 1893213435Shselasky if (err) { 1894213435Shselasky DPRINTF("addr=%d, getting full desc failed\n", 1895213435Shselasky udev->address); 1896213435Shselasky return (err); 1897213435Shselasky } 1898213435Shselasky 1899213435Shselasky DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " 1900213435Shselasky "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", 1901213435Shselasky udev->address, UGETW(udev->ddesc.bcdUSB), 1902213435Shselasky udev->ddesc.bDeviceClass, 1903213435Shselasky udev->ddesc.bDeviceSubClass, 1904213435Shselasky udev->ddesc.bDeviceProtocol, 1905213435Shselasky udev->ddesc.bMaxPacketSize, 1906213435Shselasky udev->ddesc.bLength, 1907213435Shselasky udev->speed); 1908213435Shselasky 1909213435Shselasky return (err); 1910213435Shselasky} 1911213435Shselasky 1912213435Shselasky/*------------------------------------------------------------------------* 1913194228Sthompsa * usbd_req_re_enumerate 1914184610Salfred * 1915185087Salfred * NOTE: After this function returns the hardware is in the 1916185087Salfred * unconfigured state! The application is responsible for setting a 1917185087Salfred * new configuration. 1918185087Salfred * 1919184610Salfred * Returns: 1920184610Salfred * 0: Success 1921184610Salfred * Else: Failure 1922184610Salfred *------------------------------------------------------------------------*/ 1923193045Sthompsausb_error_t 1924194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 1925184610Salfred{ 1926192984Sthompsa struct usb_device *parent_hub; 1927193045Sthompsa usb_error_t err; 1928184610Salfred uint8_t old_addr; 1929186730Salfred uint8_t do_retry = 1; 1930184610Salfred 1931192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 1932185290Salfred return (USB_ERR_INVAL); 1933185290Salfred } 1934184610Salfred old_addr = udev->address; 1935184610Salfred parent_hub = udev->parent_hub; 1936184610Salfred if (parent_hub == NULL) { 1937185290Salfred return (USB_ERR_INVAL); 1938184610Salfred } 1939186730Salfredretry: 1940194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 1941184610Salfred if (err) { 1942190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 1943194228Sthompsa old_addr, usbd_errstr(err)); 1944184610Salfred goto done; 1945184610Salfred } 1946213435Shselasky 1947184610Salfred /* 1948184610Salfred * After that the port has been reset our device should be at 1949184610Salfred * address zero: 1950184610Salfred */ 1951184610Salfred udev->address = USB_START_ADDR; 1952184610Salfred 1953185290Salfred /* reset "bMaxPacketSize" */ 1954185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 1955185290Salfred 1956213435Shselasky /* reset USB state */ 1957213435Shselasky usb_set_device_state(udev, USB_STATE_POWERED); 1958213435Shselasky 1959184610Salfred /* 1960184610Salfred * Restore device address: 1961184610Salfred */ 1962194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 1963184610Salfred if (err) { 1964184610Salfred /* XXX ignore any errors! */ 1965190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 1966194228Sthompsa old_addr, usbd_errstr(err)); 1967184610Salfred } 1968213435Shselasky /* 1969213435Shselasky * Restore device address, if the controller driver did not 1970213435Shselasky * set a new one: 1971213435Shselasky */ 1972213435Shselasky if (udev->address == USB_START_ADDR) 1973213435Shselasky udev->address = old_addr; 1974184610Salfred 1975213435Shselasky /* setup the device descriptor and the initial "wMaxPacketSize" */ 1976213435Shselasky err = usbd_setup_device_desc(udev, mtx); 1977184610Salfred 1978184610Salfreddone: 1979186730Salfred if (err && do_retry) { 1980186730Salfred /* give the USB firmware some time to load */ 1981194228Sthompsa usb_pause_mtx(mtx, hz / 2); 1982186730Salfred /* no more retries after this retry */ 1983186730Salfred do_retry = 0; 1984186730Salfred /* try again */ 1985186730Salfred goto retry; 1986186730Salfred } 1987184610Salfred /* restore address */ 1988213435Shselasky if (udev->address == USB_START_ADDR) 1989213435Shselasky udev->address = old_addr; 1990213435Shselasky /* update state, if successful */ 1991213435Shselasky if (err == 0) 1992213435Shselasky usb_set_device_state(udev, USB_STATE_ADDRESSED); 1993184610Salfred return (err); 1994184610Salfred} 1995186730Salfred 1996186730Salfred/*------------------------------------------------------------------------* 1997194228Sthompsa * usbd_req_clear_device_feature 1998186730Salfred * 1999186730Salfred * Returns: 2000186730Salfred * 0: Success 2001186730Salfred * Else: Failure 2002186730Salfred *------------------------------------------------------------------------*/ 2003193045Sthompsausb_error_t 2004194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 2005186730Salfred uint16_t sel) 2006186730Salfred{ 2007192984Sthompsa struct usb_device_request req; 2008186730Salfred 2009186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2010186730Salfred req.bRequest = UR_CLEAR_FEATURE; 2011186730Salfred USETW(req.wValue, sel); 2012186730Salfred USETW(req.wIndex, 0); 2013186730Salfred USETW(req.wLength, 0); 2014194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2015186730Salfred} 2016186730Salfred 2017186730Salfred/*------------------------------------------------------------------------* 2018194228Sthompsa * usbd_req_set_device_feature 2019186730Salfred * 2020186730Salfred * Returns: 2021186730Salfred * 0: Success 2022186730Salfred * Else: Failure 2023186730Salfred *------------------------------------------------------------------------*/ 2024193045Sthompsausb_error_t 2025194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 2026186730Salfred uint16_t sel) 2027186730Salfred{ 2028192984Sthompsa struct usb_device_request req; 2029186730Salfred 2030186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 2031186730Salfred req.bRequest = UR_SET_FEATURE; 2032186730Salfred USETW(req.wValue, sel); 2033186730Salfred USETW(req.wIndex, 0); 2034186730Salfred USETW(req.wLength, 0); 2035194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 2036186730Salfred} 2037