usb_request.c revision 194228
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 194228 2009-06-15 01:02:43Z thompsa $ */ 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 29188942Sthompsa#include <dev/usb/usb_mfunc.h> 30188942Sthompsa#include <dev/usb/usb_error.h> 31188942Sthompsa#include <dev/usb/usb.h> 32188942Sthompsa#include <dev/usb/usb_ioctl.h> 33188942Sthompsa#include <dev/usb/usbhid.h> 34184610Salfred 35194228Sthompsa#define USB_DEBUG_VAR usb_debug 36184610Salfred 37188942Sthompsa#include <dev/usb/usb_core.h> 38188942Sthompsa#include <dev/usb/usb_busdma.h> 39188942Sthompsa#include <dev/usb/usb_request.h> 40188942Sthompsa#include <dev/usb/usb_process.h> 41188942Sthompsa#include <dev/usb/usb_transfer.h> 42188942Sthompsa#include <dev/usb/usb_debug.h> 43188942Sthompsa#include <dev/usb/usb_device.h> 44188942Sthompsa#include <dev/usb/usb_util.h> 45188942Sthompsa#include <dev/usb/usb_dynamic.h> 46184610Salfred 47188942Sthompsa#include <dev/usb/usb_controller.h> 48188942Sthompsa#include <dev/usb/usb_bus.h> 49184610Salfred#include <sys/ctype.h> 50184610Salfred 51184610Salfred#if USB_DEBUG 52194228Sthompsastatic int usb_pr_poll_delay = USB_PORT_RESET_DELAY; 53194228Sthompsastatic int usb_pr_recovery_delay = USB_PORT_RESET_RECOVERY; 54194228Sthompsastatic int usb_ss_delay = 0; 55184610Salfred 56192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW, 57194228Sthompsa &usb_pr_poll_delay, 0, "USB port reset poll delay in ms"); 58192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, 59194228Sthompsa &usb_pr_recovery_delay, 0, "USB port reset recovery delay in ms"); 60192502SthompsaSYSCTL_INT(_hw_usb, OID_AUTO, ss_delay, CTLFLAG_RW, 61194228Sthompsa &usb_ss_delay, 0, "USB status stage delay in ms"); 62184610Salfred#endif 63184610Salfred 64184610Salfred/*------------------------------------------------------------------------* 65194228Sthompsa * usbd_do_request_callback 66184610Salfred * 67184610Salfred * This function is the USB callback for generic USB Host control 68184610Salfred * transfers. 69184610Salfred *------------------------------------------------------------------------*/ 70184610Salfredvoid 71194228Sthompsausbd_do_request_callback(struct usb_xfer *xfer) 72184610Salfred{ 73184610Salfred ; /* workaround for a bug in "indent" */ 74184610Salfred 75184610Salfred DPRINTF("st=%u\n", USB_GET_STATE(xfer)); 76184610Salfred 77184610Salfred switch (USB_GET_STATE(xfer)) { 78184610Salfred case USB_ST_SETUP: 79194228Sthompsa usbd_transfer_submit(xfer); 80184610Salfred break; 81184610Salfred default: 82194227Sthompsa cv_signal(xfer->xroot->udev->default_cv); 83184610Salfred break; 84184610Salfred } 85184610Salfred} 86184610Salfred 87184610Salfred/*------------------------------------------------------------------------* 88194228Sthompsa * usb_do_clear_stall_callback 89184610Salfred * 90184610Salfred * This function is the USB callback for generic clear stall requests. 91184610Salfred *------------------------------------------------------------------------*/ 92184610Salfredvoid 93194228Sthompsausb_do_clear_stall_callback(struct usb_xfer *xfer) 94184610Salfred{ 95192984Sthompsa struct usb_device_request req; 96192984Sthompsa struct usb_device *udev; 97193644Sthompsa struct usb_endpoint *ep; 98193644Sthompsa struct usb_endpoint *ep_end; 99193644Sthompsa struct usb_endpoint *ep_first; 100190731Sthompsa uint8_t to; 101184610Salfred 102187173Sthompsa udev = xfer->xroot->udev; 103184610Salfred 104187173Sthompsa USB_BUS_LOCK(udev->bus); 105187173Sthompsa 106193644Sthompsa /* round robin endpoint clear stall */ 107184610Salfred 108193644Sthompsa ep = udev->ep_curr; 109193644Sthompsa ep_end = udev->endpoints + udev->endpoints_max; 110193644Sthompsa ep_first = udev->endpoints; 111193644Sthompsa to = udev->endpoints_max; 112193318Sthompsa 113184610Salfred switch (USB_GET_STATE(xfer)) { 114184610Salfred case USB_ST_TRANSFERRED: 115193644Sthompsa if (ep == NULL) 116193318Sthompsa goto tr_setup; /* device was unconfigured */ 117193644Sthompsa if (ep->edesc && 118193644Sthompsa ep->is_stalled) { 119193644Sthompsa ep->toggle_next = 0; 120193644Sthompsa ep->is_stalled = 0; 121184610Salfred /* start up the current or next transfer, if any */ 122194228Sthompsa usb_command_wrapper(&ep->endpoint_q, 123193644Sthompsa ep->endpoint_q.curr); 124184610Salfred } 125193644Sthompsa ep++; 126184610Salfred 127184610Salfred case USB_ST_SETUP: 128184610Salfredtr_setup: 129193318Sthompsa if (to == 0) 130193644Sthompsa break; /* no endpoints - nothing to do */ 131193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 132193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 133193644Sthompsa if (ep->edesc && 134193644Sthompsa ep->is_stalled) { 135184610Salfred 136184610Salfred /* setup a clear-stall packet */ 137184610Salfred 138184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 139184610Salfred req.bRequest = UR_CLEAR_FEATURE; 140184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 141193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 142184610Salfred req.wIndex[1] = 0; 143184610Salfred USETW(req.wLength, 0); 144184610Salfred 145184610Salfred /* copy in the transfer */ 146184610Salfred 147194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 148184610Salfred 149184610Salfred /* set length */ 150184610Salfred xfer->frlengths[0] = sizeof(req); 151184610Salfred xfer->nframes = 1; 152187173Sthompsa USB_BUS_UNLOCK(udev->bus); 153184610Salfred 154194228Sthompsa usbd_transfer_submit(xfer); 155184610Salfred 156187173Sthompsa USB_BUS_LOCK(udev->bus); 157184610Salfred break; 158184610Salfred } 159193644Sthompsa ep++; 160193318Sthompsa to--; 161193318Sthompsa goto tr_setup; 162184610Salfred 163184610Salfred default: 164184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 165184610Salfred break; 166184610Salfred } 167184610Salfred goto tr_setup; 168184610Salfred } 169184610Salfred 170193644Sthompsa /* store current endpoint */ 171193644Sthompsa udev->ep_curr = ep; 172187173Sthompsa USB_BUS_UNLOCK(udev->bus); 173184610Salfred} 174184610Salfred 175193045Sthompsastatic usb_handle_req_t * 176194228Sthompsausbd_get_hr_func(struct usb_device *udev) 177191402Sthompsa{ 178191402Sthompsa /* figure out if there is a Handle Request function */ 179192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 180194228Sthompsa return (usb_temp_get_desc_p); 181191402Sthompsa else if (udev->parent_hub == NULL) 182191402Sthompsa return (udev->bus->methods->roothub_exec); 183191402Sthompsa else 184191402Sthompsa return (NULL); 185191402Sthompsa} 186191402Sthompsa 187184610Salfred/*------------------------------------------------------------------------* 188194228Sthompsa * usbd_do_request_flags and usbd_do_request 189184610Salfred * 190184610Salfred * Description of arguments passed to these functions: 191184610Salfred * 192192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 193184610Salfred * request should be performed. It is possible to call this function 194184610Salfred * in both Host Side mode and Device Side mode. 195184610Salfred * 196184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 197184610Salfred * will get dropped and picked up during the execution of this 198184610Salfred * function, hence this function sometimes needs to sleep. If this 199184610Salfred * argument is NULL it has no effect. 200184610Salfred * 201184610Salfred * "req" - this argument must always be non-NULL and points to an 202184610Salfred * 8-byte structure holding the USB request to be done. The USB 203184610Salfred * request structure has a bit telling the direction of the USB 204184610Salfred * request, if it is a read or a write. 205184610Salfred * 206184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 207184610Salfred * is non-zero this argument must point to a valid kernel buffer which 208184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 209184610Salfred * be NULL. 210184610Salfred * 211184610Salfred * "flags" - here is a list of valid flags: 212184610Salfred * 213184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 214184610Salfred * specified 215184610Salfred * 216184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 217184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 218184610Salfred * sysctl. This flag is mostly useful for debugging. 219184610Salfred * 220184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 221184610Salfred * pointer. 222184610Salfred * 223184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 224184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 225184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 226184610Salfred * used. 227184610Salfred * 228184610Salfred * "timeout" - gives the timeout for the control transfer in 229184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 230184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 231184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 232184610Salfred * does not allow control requests without a timeout. 233184610Salfred * 234184610Salfred * NOTE: This function is thread safe. All calls to 235194228Sthompsa * "usbd_do_request_flags" will be serialised by the use of an 236184610Salfred * internal "sx_lock". 237184610Salfred * 238184610Salfred * Returns: 239184610Salfred * 0: Success 240184610Salfred * Else: Failure 241184610Salfred *------------------------------------------------------------------------*/ 242193045Sthompsausb_error_t 243194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 244192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 245193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 246184610Salfred{ 247193045Sthompsa usb_handle_req_t *hr_func; 248192984Sthompsa struct usb_xfer *xfer; 249184610Salfred const void *desc; 250184610Salfred int err = 0; 251193045Sthompsa usb_ticks_t start_ticks; 252193045Sthompsa usb_ticks_t delta_ticks; 253193045Sthompsa usb_ticks_t max_ticks; 254184610Salfred uint16_t length; 255184610Salfred uint16_t temp; 256184610Salfred 257184610Salfred if (timeout < 50) { 258184610Salfred /* timeout is too small */ 259184610Salfred timeout = 50; 260184610Salfred } 261184610Salfred if (timeout > 30000) { 262184610Salfred /* timeout is too big */ 263184610Salfred timeout = 30000; 264184610Salfred } 265184610Salfred length = UGETW(req->wLength); 266184610Salfred 267184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 268184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 269184610Salfred udev, req->bmRequestType, req->bRequest, 270184610Salfred req->wValue[1], req->wValue[0], 271184610Salfred req->wIndex[1], req->wIndex[0], 272184610Salfred req->wLength[1], req->wLength[0]); 273184610Salfred 274191494Sthompsa /* Check if the device is still alive */ 275191494Sthompsa if (udev->state < USB_STATE_POWERED) { 276191494Sthompsa DPRINTF("usb device has gone\n"); 277191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 278191494Sthompsa } 279191494Sthompsa 280184610Salfred /* 281184610Salfred * Set "actlen" to a known value in case the caller does not 282184610Salfred * check the return value: 283184610Salfred */ 284190735Sthompsa if (actlen) 285184610Salfred *actlen = 0; 286190735Sthompsa 287190180Sthompsa#if (USB_HAVE_USER_IO == 0) 288190180Sthompsa if (flags & USB_USER_DATA_PTR) 289190180Sthompsa return (USB_ERR_INVAL); 290190180Sthompsa#endif 291184610Salfred if (mtx) { 292184610Salfred mtx_unlock(mtx); 293184610Salfred if (mtx != &Giant) { 294184610Salfred mtx_assert(mtx, MA_NOTOWNED); 295184610Salfred } 296184610Salfred } 297184610Salfred /* 298184610Salfred * Grab the default sx-lock so that serialisation 299184610Salfred * is achieved when multiple threads are involved: 300184610Salfred */ 301184610Salfred 302184610Salfred sx_xlock(udev->default_sx); 303184610Salfred 304194228Sthompsa hr_func = usbd_get_hr_func(udev); 305190735Sthompsa 306191402Sthompsa if (hr_func != NULL) { 307191402Sthompsa DPRINTF("Handle Request function is set\n"); 308190735Sthompsa 309191402Sthompsa desc = NULL; 310191402Sthompsa temp = 0; 311191402Sthompsa 312191402Sthompsa if (!(req->bmRequestType & UT_READ)) { 313190735Sthompsa if (length != 0) { 314191402Sthompsa DPRINTFN(1, "The handle request function " 315191402Sthompsa "does not support writing data!\n"); 316191402Sthompsa err = USB_ERR_INVAL; 317191402Sthompsa goto done; 318190735Sthompsa } 319190735Sthompsa } 320190735Sthompsa 321191402Sthompsa /* The root HUB code needs the BUS lock locked */ 322191402Sthompsa 323190735Sthompsa USB_BUS_LOCK(udev->bus); 324191402Sthompsa err = (hr_func) (udev, req, &desc, &temp); 325190735Sthompsa USB_BUS_UNLOCK(udev->bus); 326190735Sthompsa 327190735Sthompsa if (err) 328190735Sthompsa goto done; 329190735Sthompsa 330191402Sthompsa if (length > temp) { 331190735Sthompsa if (!(flags & USB_SHORT_XFER_OK)) { 332190735Sthompsa err = USB_ERR_SHORT_XFER; 333190735Sthompsa goto done; 334190735Sthompsa } 335191402Sthompsa length = temp; 336190735Sthompsa } 337190735Sthompsa if (actlen) 338190735Sthompsa *actlen = length; 339190735Sthompsa 340190735Sthompsa if (length > 0) { 341190735Sthompsa#if USB_HAVE_USER_IO 342190735Sthompsa if (flags & USB_USER_DATA_PTR) { 343191402Sthompsa if (copyout(desc, data, length)) { 344190735Sthompsa err = USB_ERR_INVAL; 345190735Sthompsa goto done; 346190735Sthompsa } 347190735Sthompsa } else 348190735Sthompsa#endif 349191402Sthompsa bcopy(desc, data, length); 350190735Sthompsa } 351191402Sthompsa goto done; /* success */ 352190735Sthompsa } 353190735Sthompsa 354184610Salfred /* 355184610Salfred * Setup a new USB transfer or use the existing one, if any: 356184610Salfred */ 357194228Sthompsa usbd_default_transfer_setup(udev); 358184610Salfred 359184610Salfred xfer = udev->default_xfer[0]; 360184610Salfred if (xfer == NULL) { 361184610Salfred /* most likely out of memory */ 362184610Salfred err = USB_ERR_NOMEM; 363184610Salfred goto done; 364184610Salfred } 365184824Sthompsa USB_XFER_LOCK(xfer); 366184610Salfred 367190734Sthompsa if (flags & USB_DELAY_STATUS_STAGE) 368184610Salfred xfer->flags.manual_status = 1; 369190734Sthompsa else 370184610Salfred xfer->flags.manual_status = 0; 371184610Salfred 372190734Sthompsa if (flags & USB_SHORT_XFER_OK) 373190734Sthompsa xfer->flags.short_xfer_ok = 1; 374190734Sthompsa else 375190734Sthompsa xfer->flags.short_xfer_ok = 0; 376190734Sthompsa 377184610Salfred xfer->timeout = timeout; 378184610Salfred 379184610Salfred start_ticks = ticks; 380184610Salfred 381184610Salfred max_ticks = USB_MS_TO_TICKS(timeout); 382184610Salfred 383194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 384184610Salfred 385184610Salfred xfer->frlengths[0] = sizeof(*req); 386184610Salfred xfer->nframes = 2; 387184610Salfred 388184610Salfred while (1) { 389184610Salfred temp = length; 390184610Salfred if (temp > xfer->max_data_length) { 391184610Salfred temp = xfer->max_data_length; 392184610Salfred } 393184610Salfred xfer->frlengths[1] = temp; 394184610Salfred 395184610Salfred if (temp > 0) { 396184610Salfred if (!(req->bmRequestType & UT_READ)) { 397190180Sthompsa#if USB_HAVE_USER_IO 398184610Salfred if (flags & USB_USER_DATA_PTR) { 399184824Sthompsa USB_XFER_UNLOCK(xfer); 400194228Sthompsa err = usbd_copy_in_user(xfer->frbuffers + 1, 401184610Salfred 0, data, temp); 402184824Sthompsa USB_XFER_LOCK(xfer); 403184610Salfred if (err) { 404184610Salfred err = USB_ERR_INVAL; 405184610Salfred break; 406184610Salfred } 407190180Sthompsa } else 408190180Sthompsa#endif 409194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 410190180Sthompsa 0, data, temp); 411184610Salfred } 412184610Salfred xfer->nframes = 2; 413184610Salfred } else { 414184610Salfred if (xfer->frlengths[0] == 0) { 415184610Salfred if (xfer->flags.manual_status) { 416184610Salfred#if USB_DEBUG 417184610Salfred int temp; 418184610Salfred 419194228Sthompsa temp = usb_ss_delay; 420184610Salfred if (temp > 5000) { 421184610Salfred temp = 5000; 422184610Salfred } 423184610Salfred if (temp > 0) { 424194228Sthompsa usb_pause_mtx( 425187173Sthompsa xfer->xroot->xfer_mtx, 426188411Sthompsa USB_MS_TO_TICKS(temp)); 427184610Salfred } 428184610Salfred#endif 429184610Salfred xfer->flags.manual_status = 0; 430184610Salfred } else { 431184610Salfred break; 432184610Salfred } 433184610Salfred } 434184610Salfred xfer->nframes = 1; 435184610Salfred } 436184610Salfred 437194228Sthompsa usbd_transfer_start(xfer); 438184610Salfred 439194228Sthompsa while (usbd_transfer_pending(xfer)) { 440194227Sthompsa cv_wait(udev->default_cv, 441188983Sthompsa xfer->xroot->xfer_mtx); 442184610Salfred } 443184610Salfred 444184610Salfred err = xfer->error; 445184610Salfred 446184610Salfred if (err) { 447184610Salfred break; 448184610Salfred } 449184610Salfred /* subtract length of SETUP packet, if any */ 450184610Salfred 451184610Salfred if (xfer->aframes > 0) { 452184610Salfred xfer->actlen -= xfer->frlengths[0]; 453184610Salfred } else { 454184610Salfred xfer->actlen = 0; 455184610Salfred } 456184610Salfred 457184610Salfred /* check for short packet */ 458184610Salfred 459184610Salfred if (temp > xfer->actlen) { 460184610Salfred temp = xfer->actlen; 461184610Salfred length = temp; 462184610Salfred } 463184610Salfred if (temp > 0) { 464184610Salfred if (req->bmRequestType & UT_READ) { 465190180Sthompsa#if USB_HAVE_USER_IO 466184610Salfred if (flags & USB_USER_DATA_PTR) { 467184824Sthompsa USB_XFER_UNLOCK(xfer); 468194228Sthompsa err = usbd_copy_out_user(xfer->frbuffers + 1, 469184610Salfred 0, data, temp); 470184824Sthompsa USB_XFER_LOCK(xfer); 471184610Salfred if (err) { 472184610Salfred err = USB_ERR_INVAL; 473184610Salfred break; 474184610Salfred } 475190180Sthompsa } else 476190180Sthompsa#endif 477194228Sthompsa usbd_copy_out(xfer->frbuffers + 1, 478184610Salfred 0, data, temp); 479184610Salfred } 480184610Salfred } 481184610Salfred /* 482184610Salfred * Clear "frlengths[0]" so that we don't send the setup 483184610Salfred * packet again: 484184610Salfred */ 485184610Salfred xfer->frlengths[0] = 0; 486184610Salfred 487184610Salfred /* update length and data pointer */ 488184610Salfred length -= temp; 489184610Salfred data = USB_ADD_BYTES(data, temp); 490184610Salfred 491184610Salfred if (actlen) { 492184610Salfred (*actlen) += temp; 493184610Salfred } 494184610Salfred /* check for timeout */ 495184610Salfred 496184610Salfred delta_ticks = ticks - start_ticks; 497184610Salfred if (delta_ticks > max_ticks) { 498184610Salfred if (!err) { 499184610Salfred err = USB_ERR_TIMEOUT; 500184610Salfred } 501184610Salfred } 502184610Salfred if (err) { 503184610Salfred break; 504184610Salfred } 505184610Salfred } 506184610Salfred 507184610Salfred if (err) { 508184610Salfred /* 509184610Salfred * Make sure that the control endpoint is no longer 510184610Salfred * blocked in case of a non-transfer related error: 511184610Salfred */ 512194228Sthompsa usbd_transfer_stop(xfer); 513184610Salfred } 514184824Sthompsa USB_XFER_UNLOCK(xfer); 515184610Salfred 516184610Salfreddone: 517184610Salfred sx_xunlock(udev->default_sx); 518184610Salfred 519184610Salfred if (mtx) { 520184610Salfred mtx_lock(mtx); 521184610Salfred } 522193045Sthompsa return ((usb_error_t)err); 523184610Salfred} 524184610Salfred 525184610Salfred/*------------------------------------------------------------------------* 526194228Sthompsa * usbd_do_request_proc - factored out code 527188411Sthompsa * 528188411Sthompsa * This function is factored out code. It does basically the same like 529194228Sthompsa * usbd_do_request_flags, except it will check the status of the 530188411Sthompsa * passed process argument before doing the USB request. If the 531188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It 532188411Sthompsa * is assumed that the mutex associated with the process is locked 533188411Sthompsa * when calling this function. 534188411Sthompsa *------------------------------------------------------------------------*/ 535193045Sthompsausb_error_t 536194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 537192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 538193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 539188411Sthompsa{ 540193045Sthompsa usb_error_t err; 541188411Sthompsa uint16_t len; 542188411Sthompsa 543188411Sthompsa /* get request data length */ 544188411Sthompsa len = UGETW(req->wLength); 545188411Sthompsa 546188411Sthompsa /* check if the device is being detached */ 547194228Sthompsa if (usb_proc_is_gone(pproc)) { 548188411Sthompsa err = USB_ERR_IOERROR; 549188411Sthompsa goto done; 550188411Sthompsa } 551188411Sthompsa 552188411Sthompsa /* forward the USB request */ 553194228Sthompsa err = usbd_do_request_flags(udev, pproc->up_mtx, 554188411Sthompsa req, data, flags, actlen, timeout); 555188411Sthompsa 556188411Sthompsadone: 557188411Sthompsa /* on failure we zero the data */ 558188411Sthompsa /* on short packet we zero the unused data */ 559188411Sthompsa if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 560188411Sthompsa if (err) 561188411Sthompsa memset(data, 0, len); 562188411Sthompsa else if (actlen && *actlen != len) 563188411Sthompsa memset(((uint8_t *)data) + *actlen, 0, len - *actlen); 564188411Sthompsa } 565188411Sthompsa return (err); 566188411Sthompsa} 567188411Sthompsa 568188411Sthompsa/*------------------------------------------------------------------------* 569194228Sthompsa * usbd_req_reset_port 570184610Salfred * 571184610Salfred * This function will instruct an USB HUB to perform a reset sequence 572184610Salfred * on the specified port number. 573184610Salfred * 574184610Salfred * Returns: 575184610Salfred * 0: Success. The USB device should now be at address zero. 576184610Salfred * Else: Failure. No USB device is present and the USB port should be 577184610Salfred * disabled. 578184610Salfred *------------------------------------------------------------------------*/ 579193045Sthompsausb_error_t 580194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 581184610Salfred{ 582192984Sthompsa struct usb_port_status ps; 583193045Sthompsa usb_error_t err; 584184610Salfred uint16_t n; 585184610Salfred 586184610Salfred#if USB_DEBUG 587184610Salfred uint16_t pr_poll_delay; 588184610Salfred uint16_t pr_recovery_delay; 589184610Salfred 590184610Salfred#endif 591194228Sthompsa err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET); 592184610Salfred if (err) { 593184610Salfred goto done; 594184610Salfred } 595184610Salfred#if USB_DEBUG 596184610Salfred /* range check input parameters */ 597194228Sthompsa pr_poll_delay = usb_pr_poll_delay; 598184610Salfred if (pr_poll_delay < 1) { 599184610Salfred pr_poll_delay = 1; 600184610Salfred } else if (pr_poll_delay > 1000) { 601184610Salfred pr_poll_delay = 1000; 602184610Salfred } 603194228Sthompsa pr_recovery_delay = usb_pr_recovery_delay; 604184610Salfred if (pr_recovery_delay > 1000) { 605184610Salfred pr_recovery_delay = 1000; 606184610Salfred } 607184610Salfred#endif 608184610Salfred n = 0; 609184610Salfred while (1) { 610184610Salfred#if USB_DEBUG 611184610Salfred /* wait for the device to recover from reset */ 612194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 613184610Salfred n += pr_poll_delay; 614184610Salfred#else 615184610Salfred /* wait for the device to recover from reset */ 616194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 617184610Salfred n += USB_PORT_RESET_DELAY; 618184610Salfred#endif 619194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 620184610Salfred if (err) { 621184610Salfred goto done; 622184610Salfred } 623184610Salfred /* if the device disappeared, just give up */ 624184610Salfred if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) { 625184610Salfred goto done; 626184610Salfred } 627184610Salfred /* check if reset is complete */ 628184610Salfred if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) { 629184610Salfred break; 630184610Salfred } 631184610Salfred /* check for timeout */ 632184610Salfred if (n > 1000) { 633184610Salfred n = 0; 634184610Salfred break; 635184610Salfred } 636184610Salfred } 637184610Salfred 638184610Salfred /* clear port reset first */ 639194228Sthompsa err = usbd_req_clear_port_feature( 640184610Salfred udev, mtx, port, UHF_C_PORT_RESET); 641184610Salfred if (err) { 642184610Salfred goto done; 643184610Salfred } 644184610Salfred /* check for timeout */ 645184610Salfred if (n == 0) { 646184610Salfred err = USB_ERR_TIMEOUT; 647184610Salfred goto done; 648184610Salfred } 649184610Salfred#if USB_DEBUG 650184610Salfred /* wait for the device to recover from reset */ 651194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 652184610Salfred#else 653184610Salfred /* wait for the device to recover from reset */ 654194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 655184610Salfred#endif 656184610Salfred 657184610Salfreddone: 658184610Salfred DPRINTFN(2, "port %d reset returning error=%s\n", 659194228Sthompsa port, usbd_errstr(err)); 660184610Salfred return (err); 661184610Salfred} 662184610Salfred 663184610Salfred/*------------------------------------------------------------------------* 664194228Sthompsa * usbd_req_get_desc 665184610Salfred * 666184610Salfred * This function can be used to retrieve USB descriptors. It contains 667184610Salfred * some additional logic like zeroing of missing descriptor bytes and 668184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 669184610Salfred * argument specifies the minimum descriptor length. The "max_len" 670184610Salfred * argument specifies the maximum descriptor length. If the real 671184610Salfred * descriptor length is less than the minimum length the missing 672188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 673188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 674188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 675188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 676188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 677188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 678188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 679188985Sthompsa * "max_len" then this function will try to retrive the beginning of 680188985Sthompsa * the descriptor and base the maximum length on the first byte of the 681188985Sthompsa * descriptor. 682184610Salfred * 683184610Salfred * Returns: 684184610Salfred * 0: Success 685184610Salfred * Else: Failure 686184610Salfred *------------------------------------------------------------------------*/ 687193045Sthompsausb_error_t 688194228Sthompsausbd_req_get_desc(struct usb_device *udev, 689188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 690184610Salfred uint16_t min_len, uint16_t max_len, 691184610Salfred uint16_t id, uint8_t type, uint8_t index, 692184610Salfred uint8_t retries) 693184610Salfred{ 694192984Sthompsa struct usb_device_request req; 695184610Salfred uint8_t *buf; 696193045Sthompsa usb_error_t err; 697184610Salfred 698184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 699184610Salfred id, type, index, max_len); 700184610Salfred 701184610Salfred req.bmRequestType = UT_READ_DEVICE; 702184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 703184610Salfred USETW2(req.wValue, type, index); 704184610Salfred USETW(req.wIndex, id); 705184610Salfred 706184610Salfred while (1) { 707184610Salfred 708184610Salfred if ((min_len < 2) || (max_len < 2)) { 709184610Salfred err = USB_ERR_INVAL; 710184610Salfred goto done; 711184610Salfred } 712184610Salfred USETW(req.wLength, min_len); 713184610Salfred 714194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 715186730Salfred desc, 0, NULL, 1000); 716184610Salfred 717184610Salfred if (err) { 718184610Salfred if (!retries) { 719184610Salfred goto done; 720184610Salfred } 721184610Salfred retries--; 722184610Salfred 723194228Sthompsa usb_pause_mtx(mtx, hz / 5); 724184610Salfred 725184610Salfred continue; 726184610Salfred } 727184610Salfred buf = desc; 728184610Salfred 729184610Salfred if (min_len == max_len) { 730184610Salfred 731188985Sthompsa /* enforce correct length */ 732188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 733188985Sthompsa buf[0] = min_len; 734184610Salfred 735188985Sthompsa /* enforce correct type */ 736184610Salfred buf[1] = type; 737184610Salfred 738184610Salfred goto done; 739184610Salfred } 740184610Salfred /* range check */ 741184610Salfred 742184610Salfred if (max_len > buf[0]) { 743184610Salfred max_len = buf[0]; 744184610Salfred } 745184610Salfred /* zero minimum data */ 746184610Salfred 747184610Salfred while (min_len > max_len) { 748184610Salfred min_len--; 749184610Salfred buf[min_len] = 0; 750184610Salfred } 751184610Salfred 752184610Salfred /* set new minimum length */ 753184610Salfred 754184610Salfred min_len = max_len; 755184610Salfred } 756184610Salfreddone: 757188985Sthompsa if (actlen != NULL) { 758188985Sthompsa if (err) 759188985Sthompsa *actlen = 0; 760188985Sthompsa else 761188985Sthompsa *actlen = min_len; 762188985Sthompsa } 763184610Salfred return (err); 764184610Salfred} 765184610Salfred 766184610Salfred/*------------------------------------------------------------------------* 767194228Sthompsa * usbd_req_get_string_any 768184610Salfred * 769184610Salfred * This function will return the string given by "string_index" 770184610Salfred * using the first language ID. The maximum length "len" includes 771184610Salfred * the terminating zero. The "len" argument should be twice as 772184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 773184610Salfred * 774184610Salfred * Returns: 775184610Salfred * 0: Success 776184610Salfred * Else: Failure 777184610Salfred *------------------------------------------------------------------------*/ 778193045Sthompsausb_error_t 779194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 780184610Salfred uint16_t len, uint8_t string_index) 781184610Salfred{ 782184610Salfred char *s; 783184610Salfred uint8_t *temp; 784184610Salfred uint16_t i; 785184610Salfred uint16_t n; 786184610Salfred uint16_t c; 787184610Salfred uint8_t swap; 788193045Sthompsa usb_error_t err; 789184610Salfred 790184610Salfred if (len == 0) { 791184610Salfred /* should not happen */ 792184610Salfred return (USB_ERR_NORMAL_COMPLETION); 793184610Salfred } 794184610Salfred if (string_index == 0) { 795184610Salfred /* this is the language table */ 796185087Salfred buf[0] = 0; 797184610Salfred return (USB_ERR_INVAL); 798184610Salfred } 799184610Salfred if (udev->flags.no_strings) { 800185087Salfred buf[0] = 0; 801184610Salfred return (USB_ERR_STALLED); 802184610Salfred } 803194228Sthompsa err = usbd_req_get_string_desc 804184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 805184610Salfred if (err) { 806185087Salfred buf[0] = 0; 807184610Salfred return (err); 808184610Salfred } 809184610Salfred temp = (uint8_t *)buf; 810184610Salfred 811184610Salfred if (temp[0] < 2) { 812184610Salfred /* string length is too short */ 813185087Salfred buf[0] = 0; 814184610Salfred return (USB_ERR_INVAL); 815184610Salfred } 816184610Salfred /* reserve one byte for terminating zero */ 817184610Salfred len--; 818184610Salfred 819184610Salfred /* find maximum length */ 820184610Salfred s = buf; 821184610Salfred n = (temp[0] / 2) - 1; 822184610Salfred if (n > len) { 823184610Salfred n = len; 824184610Salfred } 825184610Salfred /* skip descriptor header */ 826184610Salfred temp += 2; 827184610Salfred 828184610Salfred /* reset swap state */ 829184610Salfred swap = 3; 830184610Salfred 831184610Salfred /* convert and filter */ 832184610Salfred for (i = 0; (i != n); i++) { 833184610Salfred c = UGETW(temp + (2 * i)); 834184610Salfred 835184610Salfred /* convert from Unicode, handle buggy strings */ 836184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 837184610Salfred /* Little Endian, default */ 838184610Salfred *s = c; 839184610Salfred swap = 1; 840184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 841184610Salfred /* Big Endian */ 842184610Salfred *s = c >> 8; 843184610Salfred swap = 2; 844184610Salfred } else { 845185087Salfred /* silently skip bad character */ 846185087Salfred continue; 847184610Salfred } 848184610Salfred 849184610Salfred /* 850184610Salfred * Filter by default - we don't allow greater and less than 851184610Salfred * signs because they might confuse the dmesg printouts! 852184610Salfred */ 853184610Salfred if ((*s == '<') || (*s == '>') || (!isprint(*s))) { 854185087Salfred /* silently skip bad character */ 855185087Salfred continue; 856184610Salfred } 857184610Salfred s++; 858184610Salfred } 859185087Salfred *s = 0; /* zero terminate resulting string */ 860184610Salfred return (USB_ERR_NORMAL_COMPLETION); 861184610Salfred} 862184610Salfred 863184610Salfred/*------------------------------------------------------------------------* 864194228Sthompsa * usbd_req_get_string_desc 865184610Salfred * 866184610Salfred * If you don't know the language ID, consider using 867194228Sthompsa * "usbd_req_get_string_any()". 868184610Salfred * 869184610Salfred * Returns: 870184610Salfred * 0: Success 871184610Salfred * Else: Failure 872184610Salfred *------------------------------------------------------------------------*/ 873193045Sthompsausb_error_t 874194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 875184610Salfred uint16_t max_len, uint16_t lang_id, 876184610Salfred uint8_t string_index) 877184610Salfred{ 878194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 879184610Salfred UDESC_STRING, string_index, 0)); 880184610Salfred} 881184610Salfred 882184610Salfred/*------------------------------------------------------------------------* 883194228Sthompsa * usbd_req_get_config_desc_ptr 884190727Sthompsa * 885190727Sthompsa * This function is used in device side mode to retrieve the pointer 886190727Sthompsa * to the generated config descriptor. This saves allocating space for 887190727Sthompsa * an additional config descriptor when setting the configuration. 888190727Sthompsa * 889190727Sthompsa * Returns: 890190727Sthompsa * 0: Success 891190727Sthompsa * Else: Failure 892190727Sthompsa *------------------------------------------------------------------------*/ 893193045Sthompsausb_error_t 894194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 895192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 896190727Sthompsa{ 897192984Sthompsa struct usb_device_request req; 898193045Sthompsa usb_handle_req_t *hr_func; 899191402Sthompsa const void *ptr; 900190727Sthompsa uint16_t len; 901193045Sthompsa usb_error_t err; 902190727Sthompsa 903190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 904190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 905191402Sthompsa USETW(req.wValue, wValue); 906190727Sthompsa USETW(req.wIndex, 0); 907190727Sthompsa USETW(req.wLength, 0); 908190727Sthompsa 909191402Sthompsa ptr = NULL; 910191402Sthompsa len = 0; 911190727Sthompsa 912194228Sthompsa hr_func = usbd_get_hr_func(udev); 913191402Sthompsa 914191402Sthompsa if (hr_func == NULL) 915191402Sthompsa err = USB_ERR_INVAL; 916191402Sthompsa else { 917191402Sthompsa USB_BUS_LOCK(udev->bus); 918191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 919191402Sthompsa USB_BUS_UNLOCK(udev->bus); 920191402Sthompsa } 921191402Sthompsa 922191402Sthompsa if (err) 923191402Sthompsa ptr = NULL; 924191402Sthompsa else if (ptr == NULL) 925191402Sthompsa err = USB_ERR_INVAL; 926191402Sthompsa 927192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 928191402Sthompsa 929191402Sthompsa return (err); 930190727Sthompsa} 931190727Sthompsa 932190727Sthompsa/*------------------------------------------------------------------------* 933194228Sthompsa * usbd_req_get_config_desc 934184610Salfred * 935184610Salfred * Returns: 936184610Salfred * 0: Success 937184610Salfred * Else: Failure 938184610Salfred *------------------------------------------------------------------------*/ 939193045Sthompsausb_error_t 940194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 941192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 942184610Salfred{ 943193045Sthompsa usb_error_t err; 944184610Salfred 945184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 946184610Salfred 947194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 948184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 949184610Salfred if (err) { 950184610Salfred goto done; 951184610Salfred } 952184610Salfred /* Extra sanity checking */ 953184610Salfred if (UGETW(d->wTotalLength) < sizeof(*d)) { 954184610Salfred err = USB_ERR_INVAL; 955184610Salfred } 956184610Salfreddone: 957184610Salfred return (err); 958184610Salfred} 959184610Salfred 960184610Salfred/*------------------------------------------------------------------------* 961194228Sthompsa * usbd_req_get_config_desc_full 962184610Salfred * 963184610Salfred * This function gets the complete USB configuration descriptor and 964184610Salfred * ensures that "wTotalLength" is correct. 965184610Salfred * 966184610Salfred * Returns: 967184610Salfred * 0: Success 968184610Salfred * Else: Failure 969184610Salfred *------------------------------------------------------------------------*/ 970193045Sthompsausb_error_t 971194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 972192984Sthompsa struct usb_config_descriptor **ppcd, struct malloc_type *mtype, 973184610Salfred uint8_t index) 974184610Salfred{ 975192984Sthompsa struct usb_config_descriptor cd; 976192984Sthompsa struct usb_config_descriptor *cdesc; 977184610Salfred uint16_t len; 978193045Sthompsa usb_error_t err; 979184610Salfred 980184610Salfred DPRINTFN(4, "index=%d\n", index); 981184610Salfred 982184610Salfred *ppcd = NULL; 983184610Salfred 984194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 985184610Salfred if (err) { 986184610Salfred return (err); 987184610Salfred } 988184610Salfred /* get full descriptor */ 989184610Salfred len = UGETW(cd.wTotalLength); 990184610Salfred if (len < sizeof(*cdesc)) { 991184610Salfred /* corrupt descriptor */ 992184610Salfred return (USB_ERR_INVAL); 993184610Salfred } 994184610Salfred cdesc = malloc(len, mtype, M_WAITOK); 995184610Salfred if (cdesc == NULL) { 996184610Salfred return (USB_ERR_NOMEM); 997184610Salfred } 998194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 999184610Salfred UDESC_CONFIG, index, 3); 1000184610Salfred if (err) { 1001184610Salfred free(cdesc, mtype); 1002184610Salfred return (err); 1003184610Salfred } 1004184610Salfred /* make sure that the device is not fooling us: */ 1005184610Salfred USETW(cdesc->wTotalLength, len); 1006184610Salfred 1007184610Salfred *ppcd = cdesc; 1008184610Salfred 1009184610Salfred return (0); /* success */ 1010184610Salfred} 1011184610Salfred 1012184610Salfred/*------------------------------------------------------------------------* 1013194228Sthompsa * usbd_req_get_device_desc 1014184610Salfred * 1015184610Salfred * Returns: 1016184610Salfred * 0: Success 1017184610Salfred * Else: Failure 1018184610Salfred *------------------------------------------------------------------------*/ 1019193045Sthompsausb_error_t 1020194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1021192984Sthompsa struct usb_device_descriptor *d) 1022184610Salfred{ 1023184610Salfred DPRINTFN(4, "\n"); 1024194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1025184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1026184610Salfred} 1027184610Salfred 1028184610Salfred/*------------------------------------------------------------------------* 1029194228Sthompsa * usbd_req_get_alt_interface_no 1030184610Salfred * 1031184610Salfred * Returns: 1032184610Salfred * 0: Success 1033184610Salfred * Else: Failure 1034184610Salfred *------------------------------------------------------------------------*/ 1035193045Sthompsausb_error_t 1036194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1037184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 1038184610Salfred{ 1039194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1040192984Sthompsa struct usb_device_request req; 1041184610Salfred 1042184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1043184610Salfred return (USB_ERR_INVAL); 1044184610Salfred } 1045184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1046184610Salfred req.bRequest = UR_GET_INTERFACE; 1047184610Salfred USETW(req.wValue, 0); 1048184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1049184610Salfred req.wIndex[1] = 0; 1050184610Salfred USETW(req.wLength, 1); 1051194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1052184610Salfred} 1053184610Salfred 1054184610Salfred/*------------------------------------------------------------------------* 1055194228Sthompsa * usbd_req_set_alt_interface_no 1056184610Salfred * 1057184610Salfred * Returns: 1058184610Salfred * 0: Success 1059184610Salfred * Else: Failure 1060184610Salfred *------------------------------------------------------------------------*/ 1061193045Sthompsausb_error_t 1062194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1063184610Salfred uint8_t iface_index, uint8_t alt_no) 1064184610Salfred{ 1065194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1066192984Sthompsa struct usb_device_request req; 1067184610Salfred 1068184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1069184610Salfred return (USB_ERR_INVAL); 1070184610Salfred } 1071184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1072184610Salfred req.bRequest = UR_SET_INTERFACE; 1073184610Salfred req.wValue[0] = alt_no; 1074184610Salfred req.wValue[1] = 0; 1075184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1076184610Salfred req.wIndex[1] = 0; 1077184610Salfred USETW(req.wLength, 0); 1078194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1079184610Salfred} 1080184610Salfred 1081184610Salfred/*------------------------------------------------------------------------* 1082194228Sthompsa * usbd_req_get_device_status 1083184610Salfred * 1084184610Salfred * Returns: 1085184610Salfred * 0: Success 1086184610Salfred * Else: Failure 1087184610Salfred *------------------------------------------------------------------------*/ 1088193045Sthompsausb_error_t 1089194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1090192984Sthompsa struct usb_status *st) 1091184610Salfred{ 1092192984Sthompsa struct usb_device_request req; 1093184610Salfred 1094184610Salfred req.bmRequestType = UT_READ_DEVICE; 1095184610Salfred req.bRequest = UR_GET_STATUS; 1096184610Salfred USETW(req.wValue, 0); 1097184610Salfred USETW(req.wIndex, 0); 1098184610Salfred USETW(req.wLength, sizeof(*st)); 1099194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1100184610Salfred} 1101184610Salfred 1102184610Salfred/*------------------------------------------------------------------------* 1103194228Sthompsa * usbd_req_get_hub_descriptor 1104184610Salfred * 1105184610Salfred * Returns: 1106184610Salfred * 0: Success 1107184610Salfred * Else: Failure 1108184610Salfred *------------------------------------------------------------------------*/ 1109193045Sthompsausb_error_t 1110194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1111192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1112184610Salfred{ 1113192984Sthompsa struct usb_device_request req; 1114184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1115184610Salfred 1116184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1117184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1118184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1119184610Salfred USETW(req.wIndex, 0); 1120184610Salfred USETW(req.wLength, len); 1121194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1122184610Salfred} 1123184610Salfred 1124184610Salfred/*------------------------------------------------------------------------* 1125194228Sthompsa * usbd_req_get_hub_status 1126184610Salfred * 1127184610Salfred * Returns: 1128184610Salfred * 0: Success 1129184610Salfred * Else: Failure 1130184610Salfred *------------------------------------------------------------------------*/ 1131193045Sthompsausb_error_t 1132194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1133192984Sthompsa struct usb_hub_status *st) 1134184610Salfred{ 1135192984Sthompsa struct usb_device_request req; 1136184610Salfred 1137184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1138184610Salfred req.bRequest = UR_GET_STATUS; 1139184610Salfred USETW(req.wValue, 0); 1140184610Salfred USETW(req.wIndex, 0); 1141192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1142194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1143184610Salfred} 1144184610Salfred 1145184610Salfred/*------------------------------------------------------------------------* 1146194228Sthompsa * usbd_req_set_address 1147184610Salfred * 1148184610Salfred * This function is used to set the address for an USB device. After 1149184610Salfred * port reset the USB device will respond at address zero. 1150184610Salfred * 1151184610Salfred * Returns: 1152184610Salfred * 0: Success 1153184610Salfred * Else: Failure 1154184610Salfred *------------------------------------------------------------------------*/ 1155193045Sthompsausb_error_t 1156194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1157184610Salfred{ 1158192984Sthompsa struct usb_device_request req; 1159184610Salfred 1160184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1161184610Salfred 1162184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1163184610Salfred req.bRequest = UR_SET_ADDRESS; 1164184610Salfred USETW(req.wValue, addr); 1165184610Salfred USETW(req.wIndex, 0); 1166184610Salfred USETW(req.wLength, 0); 1167184610Salfred 1168184610Salfred /* Setting the address should not take more than 1 second ! */ 1169194228Sthompsa return (usbd_do_request_flags(udev, mtx, &req, NULL, 1170184610Salfred USB_DELAY_STATUS_STAGE, NULL, 1000)); 1171184610Salfred} 1172184610Salfred 1173184610Salfred/*------------------------------------------------------------------------* 1174194228Sthompsa * usbd_req_get_port_status 1175184610Salfred * 1176184610Salfred * Returns: 1177184610Salfred * 0: Success 1178184610Salfred * Else: Failure 1179184610Salfred *------------------------------------------------------------------------*/ 1180193045Sthompsausb_error_t 1181194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1182192984Sthompsa struct usb_port_status *ps, uint8_t port) 1183184610Salfred{ 1184192984Sthompsa struct usb_device_request req; 1185184610Salfred 1186184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1187184610Salfred req.bRequest = UR_GET_STATUS; 1188184610Salfred USETW(req.wValue, 0); 1189184610Salfred req.wIndex[0] = port; 1190184610Salfred req.wIndex[1] = 0; 1191184610Salfred USETW(req.wLength, sizeof *ps); 1192194228Sthompsa return (usbd_do_request(udev, mtx, &req, ps)); 1193184610Salfred} 1194184610Salfred 1195184610Salfred/*------------------------------------------------------------------------* 1196194228Sthompsa * usbd_req_clear_hub_feature 1197184610Salfred * 1198184610Salfred * Returns: 1199184610Salfred * 0: Success 1200184610Salfred * Else: Failure 1201184610Salfred *------------------------------------------------------------------------*/ 1202193045Sthompsausb_error_t 1203194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1204184610Salfred uint16_t sel) 1205184610Salfred{ 1206192984Sthompsa struct usb_device_request req; 1207184610Salfred 1208184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1209184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1210184610Salfred USETW(req.wValue, sel); 1211184610Salfred USETW(req.wIndex, 0); 1212184610Salfred USETW(req.wLength, 0); 1213194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1214184610Salfred} 1215184610Salfred 1216184610Salfred/*------------------------------------------------------------------------* 1217194228Sthompsa * usbd_req_set_hub_feature 1218184610Salfred * 1219184610Salfred * Returns: 1220184610Salfred * 0: Success 1221184610Salfred * Else: Failure 1222184610Salfred *------------------------------------------------------------------------*/ 1223193045Sthompsausb_error_t 1224194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1225184610Salfred uint16_t sel) 1226184610Salfred{ 1227192984Sthompsa struct usb_device_request req; 1228184610Salfred 1229184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1230184610Salfred req.bRequest = UR_SET_FEATURE; 1231184610Salfred USETW(req.wValue, sel); 1232184610Salfred USETW(req.wIndex, 0); 1233184610Salfred USETW(req.wLength, 0); 1234194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1235184610Salfred} 1236184610Salfred 1237184610Salfred/*------------------------------------------------------------------------* 1238194228Sthompsa * usbd_req_clear_port_feature 1239184610Salfred * 1240184610Salfred * Returns: 1241184610Salfred * 0: Success 1242184610Salfred * Else: Failure 1243184610Salfred *------------------------------------------------------------------------*/ 1244193045Sthompsausb_error_t 1245194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1246184610Salfred uint8_t port, uint16_t sel) 1247184610Salfred{ 1248192984Sthompsa struct usb_device_request req; 1249184610Salfred 1250184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1251184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1252184610Salfred USETW(req.wValue, sel); 1253184610Salfred req.wIndex[0] = port; 1254184610Salfred req.wIndex[1] = 0; 1255184610Salfred USETW(req.wLength, 0); 1256194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1257184610Salfred} 1258184610Salfred 1259184610Salfred/*------------------------------------------------------------------------* 1260194228Sthompsa * usbd_req_set_port_feature 1261184610Salfred * 1262184610Salfred * Returns: 1263184610Salfred * 0: Success 1264184610Salfred * Else: Failure 1265184610Salfred *------------------------------------------------------------------------*/ 1266193045Sthompsausb_error_t 1267194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1268184610Salfred uint8_t port, uint16_t sel) 1269184610Salfred{ 1270192984Sthompsa struct usb_device_request req; 1271184610Salfred 1272184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1273184610Salfred req.bRequest = UR_SET_FEATURE; 1274184610Salfred USETW(req.wValue, sel); 1275184610Salfred req.wIndex[0] = port; 1276184610Salfred req.wIndex[1] = 0; 1277184610Salfred USETW(req.wLength, 0); 1278194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1279184610Salfred} 1280184610Salfred 1281184610Salfred/*------------------------------------------------------------------------* 1282194228Sthompsa * usbd_req_set_protocol 1283184610Salfred * 1284184610Salfred * Returns: 1285184610Salfred * 0: Success 1286184610Salfred * Else: Failure 1287184610Salfred *------------------------------------------------------------------------*/ 1288193045Sthompsausb_error_t 1289194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1290184610Salfred uint8_t iface_index, uint16_t report) 1291184610Salfred{ 1292194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1293192984Sthompsa struct usb_device_request req; 1294184610Salfred 1295184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1296184610Salfred return (USB_ERR_INVAL); 1297184610Salfred } 1298184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1299184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1300184610Salfred 1301184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1302184610Salfred req.bRequest = UR_SET_PROTOCOL; 1303184610Salfred USETW(req.wValue, report); 1304184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1305184610Salfred req.wIndex[1] = 0; 1306184610Salfred USETW(req.wLength, 0); 1307194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1308184610Salfred} 1309184610Salfred 1310184610Salfred/*------------------------------------------------------------------------* 1311194228Sthompsa * usbd_req_set_report 1312184610Salfred * 1313184610Salfred * Returns: 1314184610Salfred * 0: Success 1315184610Salfred * Else: Failure 1316184610Salfred *------------------------------------------------------------------------*/ 1317193045Sthompsausb_error_t 1318194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1319184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 1320184610Salfred{ 1321194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1322192984Sthompsa struct usb_device_request req; 1323184610Salfred 1324184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1325184610Salfred return (USB_ERR_INVAL); 1326184610Salfred } 1327184610Salfred DPRINTFN(5, "len=%d\n", len); 1328184610Salfred 1329184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1330184610Salfred req.bRequest = UR_SET_REPORT; 1331184610Salfred USETW2(req.wValue, type, id); 1332184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1333184610Salfred req.wIndex[1] = 0; 1334184610Salfred USETW(req.wLength, len); 1335194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1336184610Salfred} 1337184610Salfred 1338184610Salfred/*------------------------------------------------------------------------* 1339194228Sthompsa * usbd_req_get_report 1340184610Salfred * 1341184610Salfred * Returns: 1342184610Salfred * 0: Success 1343184610Salfred * Else: Failure 1344184610Salfred *------------------------------------------------------------------------*/ 1345193045Sthompsausb_error_t 1346194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1347184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1348184610Salfred{ 1349194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1350192984Sthompsa struct usb_device_request req; 1351184610Salfred 1352184610Salfred if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) { 1353184610Salfred return (USB_ERR_INVAL); 1354184610Salfred } 1355184610Salfred DPRINTFN(5, "len=%d\n", len); 1356184610Salfred 1357184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1358184610Salfred req.bRequest = UR_GET_REPORT; 1359184610Salfred USETW2(req.wValue, type, id); 1360184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1361184610Salfred req.wIndex[1] = 0; 1362184610Salfred USETW(req.wLength, len); 1363194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1364184610Salfred} 1365184610Salfred 1366184610Salfred/*------------------------------------------------------------------------* 1367194228Sthompsa * usbd_req_set_idle 1368184610Salfred * 1369184610Salfred * Returns: 1370184610Salfred * 0: Success 1371184610Salfred * Else: Failure 1372184610Salfred *------------------------------------------------------------------------*/ 1373193045Sthompsausb_error_t 1374194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1375184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1376184610Salfred{ 1377194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1378192984Sthompsa struct usb_device_request req; 1379184610Salfred 1380184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1381184610Salfred return (USB_ERR_INVAL); 1382184610Salfred } 1383184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1384184610Salfred 1385184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1386184610Salfred req.bRequest = UR_SET_IDLE; 1387184610Salfred USETW2(req.wValue, duration, id); 1388184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1389184610Salfred req.wIndex[1] = 0; 1390184610Salfred USETW(req.wLength, 0); 1391194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1392184610Salfred} 1393184610Salfred 1394184610Salfred/*------------------------------------------------------------------------* 1395194228Sthompsa * usbd_req_get_report_descriptor 1396184610Salfred * 1397184610Salfred * Returns: 1398184610Salfred * 0: Success 1399184610Salfred * Else: Failure 1400184610Salfred *------------------------------------------------------------------------*/ 1401193045Sthompsausb_error_t 1402194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1403184610Salfred void *d, uint16_t size, uint8_t iface_index) 1404184610Salfred{ 1405194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1406192984Sthompsa struct usb_device_request req; 1407184610Salfred 1408184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1409184610Salfred return (USB_ERR_INVAL); 1410184610Salfred } 1411184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1412184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1413184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1414184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1415184610Salfred req.wIndex[1] = 0; 1416184610Salfred USETW(req.wLength, size); 1417194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1418184610Salfred} 1419184610Salfred 1420184610Salfred/*------------------------------------------------------------------------* 1421194228Sthompsa * usbd_req_set_config 1422184610Salfred * 1423184610Salfred * This function is used to select the current configuration number in 1424184610Salfred * both USB device side mode and USB host side mode. When setting the 1425184610Salfred * configuration the function of the interfaces can change. 1426184610Salfred * 1427184610Salfred * Returns: 1428184610Salfred * 0: Success 1429184610Salfred * Else: Failure 1430184610Salfred *------------------------------------------------------------------------*/ 1431193045Sthompsausb_error_t 1432194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1433184610Salfred{ 1434192984Sthompsa struct usb_device_request req; 1435184610Salfred 1436184610Salfred DPRINTF("setting config %d\n", conf); 1437184610Salfred 1438184610Salfred /* do "set configuration" request */ 1439184610Salfred 1440184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1441184610Salfred req.bRequest = UR_SET_CONFIG; 1442184610Salfred req.wValue[0] = conf; 1443184610Salfred req.wValue[1] = 0; 1444184610Salfred USETW(req.wIndex, 0); 1445184610Salfred USETW(req.wLength, 0); 1446194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1447184610Salfred} 1448184610Salfred 1449184610Salfred/*------------------------------------------------------------------------* 1450194228Sthompsa * usbd_req_get_config 1451184610Salfred * 1452184610Salfred * Returns: 1453184610Salfred * 0: Success 1454184610Salfred * Else: Failure 1455184610Salfred *------------------------------------------------------------------------*/ 1456193045Sthompsausb_error_t 1457194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1458184610Salfred{ 1459192984Sthompsa struct usb_device_request req; 1460184610Salfred 1461184610Salfred req.bmRequestType = UT_READ_DEVICE; 1462184610Salfred req.bRequest = UR_GET_CONFIG; 1463184610Salfred USETW(req.wValue, 0); 1464184610Salfred USETW(req.wIndex, 0); 1465184610Salfred USETW(req.wLength, 1); 1466194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1467184610Salfred} 1468184610Salfred 1469184610Salfred/*------------------------------------------------------------------------* 1470194228Sthompsa * usbd_req_re_enumerate 1471184610Salfred * 1472185087Salfred * NOTE: After this function returns the hardware is in the 1473185087Salfred * unconfigured state! The application is responsible for setting a 1474185087Salfred * new configuration. 1475185087Salfred * 1476184610Salfred * Returns: 1477184610Salfred * 0: Success 1478184610Salfred * Else: Failure 1479184610Salfred *------------------------------------------------------------------------*/ 1480193045Sthompsausb_error_t 1481194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 1482184610Salfred{ 1483192984Sthompsa struct usb_device *parent_hub; 1484193045Sthompsa usb_error_t err; 1485184610Salfred uint8_t old_addr; 1486186730Salfred uint8_t do_retry = 1; 1487184610Salfred 1488192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 1489185290Salfred return (USB_ERR_INVAL); 1490185290Salfred } 1491184610Salfred old_addr = udev->address; 1492184610Salfred parent_hub = udev->parent_hub; 1493184610Salfred if (parent_hub == NULL) { 1494185290Salfred return (USB_ERR_INVAL); 1495184610Salfred } 1496186730Salfredretry: 1497194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 1498184610Salfred if (err) { 1499190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 1500194228Sthompsa old_addr, usbd_errstr(err)); 1501184610Salfred goto done; 1502184610Salfred } 1503184610Salfred /* 1504184610Salfred * After that the port has been reset our device should be at 1505184610Salfred * address zero: 1506184610Salfred */ 1507184610Salfred udev->address = USB_START_ADDR; 1508184610Salfred 1509185290Salfred /* reset "bMaxPacketSize" */ 1510185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 1511185290Salfred 1512184610Salfred /* 1513184610Salfred * Restore device address: 1514184610Salfred */ 1515194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 1516184610Salfred if (err) { 1517184610Salfred /* XXX ignore any errors! */ 1518190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 1519194228Sthompsa old_addr, usbd_errstr(err)); 1520184610Salfred } 1521184610Salfred /* restore device address */ 1522184610Salfred udev->address = old_addr; 1523184610Salfred 1524184610Salfred /* allow device time to set new address */ 1525194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); 1526184610Salfred 1527184610Salfred /* get the device descriptor */ 1528194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1529185290Salfred USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1530184610Salfred if (err) { 1531185290Salfred DPRINTFN(0, "getting device descriptor " 1532190739Sthompsa "at addr %d failed, %s!\n", udev->address, 1533194228Sthompsa usbd_errstr(err)); 1534185290Salfred goto done; 1535185290Salfred } 1536185290Salfred /* get the full device descriptor */ 1537194228Sthompsa err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1538185290Salfred if (err) { 1539184610Salfred DPRINTFN(0, "addr=%d, getting device " 1540190739Sthompsa "descriptor failed, %s!\n", old_addr, 1541194228Sthompsa usbd_errstr(err)); 1542184610Salfred goto done; 1543184610Salfred } 1544184610Salfreddone: 1545186730Salfred if (err && do_retry) { 1546186730Salfred /* give the USB firmware some time to load */ 1547194228Sthompsa usb_pause_mtx(mtx, hz / 2); 1548186730Salfred /* no more retries after this retry */ 1549186730Salfred do_retry = 0; 1550186730Salfred /* try again */ 1551186730Salfred goto retry; 1552186730Salfred } 1553184610Salfred /* restore address */ 1554184610Salfred udev->address = old_addr; 1555184610Salfred return (err); 1556184610Salfred} 1557186730Salfred 1558186730Salfred/*------------------------------------------------------------------------* 1559194228Sthompsa * usbd_req_clear_device_feature 1560186730Salfred * 1561186730Salfred * Returns: 1562186730Salfred * 0: Success 1563186730Salfred * Else: Failure 1564186730Salfred *------------------------------------------------------------------------*/ 1565193045Sthompsausb_error_t 1566194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 1567186730Salfred uint16_t sel) 1568186730Salfred{ 1569192984Sthompsa struct usb_device_request req; 1570186730Salfred 1571186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 1572186730Salfred req.bRequest = UR_CLEAR_FEATURE; 1573186730Salfred USETW(req.wValue, sel); 1574186730Salfred USETW(req.wIndex, 0); 1575186730Salfred USETW(req.wLength, 0); 1576194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1577186730Salfred} 1578186730Salfred 1579186730Salfred/*------------------------------------------------------------------------* 1580194228Sthompsa * usbd_req_set_device_feature 1581186730Salfred * 1582186730Salfred * Returns: 1583186730Salfred * 0: Success 1584186730Salfred * Else: Failure 1585186730Salfred *------------------------------------------------------------------------*/ 1586193045Sthompsausb_error_t 1587194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 1588186730Salfred uint16_t sel) 1589186730Salfred{ 1590192984Sthompsa struct usb_device_request req; 1591186730Salfred 1592186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 1593186730Salfred req.bRequest = UR_SET_FEATURE; 1594186730Salfred USETW(req.wValue, sel); 1595186730Salfred USETW(req.wIndex, 0); 1596186730Salfred USETW(req.wLength, 0); 1597194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1598186730Salfred} 1599