usb_request.c revision 208018
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_request.c 208018 2010-05-12 23:40:44Z 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 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; 248184610Salfred /* start up the current or next transfer, if any */ 249194228Sthompsa usb_command_wrapper(&ep->endpoint_q, 250193644Sthompsa ep->endpoint_q.curr); 251184610Salfred } 252193644Sthompsa ep++; 253184610Salfred 254184610Salfred case USB_ST_SETUP: 255184610Salfredtr_setup: 256193318Sthompsa if (to == 0) 257193644Sthompsa break; /* no endpoints - nothing to do */ 258193644Sthompsa if ((ep < ep_first) || (ep >= ep_end)) 259193644Sthompsa ep = ep_first; /* endpoint wrapped around */ 260193644Sthompsa if (ep->edesc && 261193644Sthompsa ep->is_stalled) { 262184610Salfred 263184610Salfred /* setup a clear-stall packet */ 264184610Salfred 265184610Salfred req.bmRequestType = UT_WRITE_ENDPOINT; 266184610Salfred req.bRequest = UR_CLEAR_FEATURE; 267184610Salfred USETW(req.wValue, UF_ENDPOINT_HALT); 268193644Sthompsa req.wIndex[0] = ep->edesc->bEndpointAddress; 269184610Salfred req.wIndex[1] = 0; 270184610Salfred USETW(req.wLength, 0); 271184610Salfred 272184610Salfred /* copy in the transfer */ 273184610Salfred 274194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req)); 275184610Salfred 276184610Salfred /* set length */ 277194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 278184610Salfred xfer->nframes = 1; 279187173Sthompsa USB_BUS_UNLOCK(udev->bus); 280184610Salfred 281194228Sthompsa usbd_transfer_submit(xfer); 282184610Salfred 283187173Sthompsa USB_BUS_LOCK(udev->bus); 284184610Salfred break; 285184610Salfred } 286193644Sthompsa ep++; 287193318Sthompsa to--; 288193318Sthompsa goto tr_setup; 289184610Salfred 290184610Salfred default: 291184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 292184610Salfred break; 293184610Salfred } 294184610Salfred goto tr_setup; 295184610Salfred } 296184610Salfred 297193644Sthompsa /* store current endpoint */ 298193644Sthompsa udev->ep_curr = ep; 299187173Sthompsa USB_BUS_UNLOCK(udev->bus); 300184610Salfred} 301184610Salfred 302193045Sthompsastatic usb_handle_req_t * 303194228Sthompsausbd_get_hr_func(struct usb_device *udev) 304191402Sthompsa{ 305191402Sthompsa /* figure out if there is a Handle Request function */ 306192499Sthompsa if (udev->flags.usb_mode == USB_MODE_DEVICE) 307194228Sthompsa return (usb_temp_get_desc_p); 308191402Sthompsa else if (udev->parent_hub == NULL) 309191402Sthompsa return (udev->bus->methods->roothub_exec); 310191402Sthompsa else 311191402Sthompsa return (NULL); 312191402Sthompsa} 313191402Sthompsa 314184610Salfred/*------------------------------------------------------------------------* 315194228Sthompsa * usbd_do_request_flags and usbd_do_request 316184610Salfred * 317184610Salfred * Description of arguments passed to these functions: 318184610Salfred * 319192984Sthompsa * "udev" - this is the "usb_device" structure pointer on which the 320184610Salfred * request should be performed. It is possible to call this function 321184610Salfred * in both Host Side mode and Device Side mode. 322184610Salfred * 323184610Salfred * "mtx" - if this argument is non-NULL the mutex pointed to by it 324184610Salfred * will get dropped and picked up during the execution of this 325184610Salfred * function, hence this function sometimes needs to sleep. If this 326184610Salfred * argument is NULL it has no effect. 327184610Salfred * 328184610Salfred * "req" - this argument must always be non-NULL and points to an 329184610Salfred * 8-byte structure holding the USB request to be done. The USB 330184610Salfred * request structure has a bit telling the direction of the USB 331184610Salfred * request, if it is a read or a write. 332184610Salfred * 333184610Salfred * "data" - if the "wLength" part of the structure pointed to by "req" 334184610Salfred * is non-zero this argument must point to a valid kernel buffer which 335184610Salfred * can hold at least "wLength" bytes. If "wLength" is zero "data" can 336184610Salfred * be NULL. 337184610Salfred * 338184610Salfred * "flags" - here is a list of valid flags: 339184610Salfred * 340184610Salfred * o USB_SHORT_XFER_OK: allows the data transfer to be shorter than 341184610Salfred * specified 342184610Salfred * 343184610Salfred * o USB_DELAY_STATUS_STAGE: allows the status stage to be performed 344184610Salfred * at a later point in time. This is tunable by the "hw.usb.ss_delay" 345184610Salfred * sysctl. This flag is mostly useful for debugging. 346184610Salfred * 347184610Salfred * o USB_USER_DATA_PTR: treat the "data" pointer like a userland 348184610Salfred * pointer. 349184610Salfred * 350184610Salfred * "actlen" - if non-NULL the actual transfer length will be stored in 351184610Salfred * the 16-bit unsigned integer pointed to by "actlen". This 352184610Salfred * information is mostly useful when the "USB_SHORT_XFER_OK" flag is 353184610Salfred * used. 354184610Salfred * 355184610Salfred * "timeout" - gives the timeout for the control transfer in 356184610Salfred * milliseconds. A "timeout" value less than 50 milliseconds is 357184610Salfred * treated like a 50 millisecond timeout. A "timeout" value greater 358184610Salfred * than 30 seconds is treated like a 30 second timeout. This USB stack 359184610Salfred * does not allow control requests without a timeout. 360184610Salfred * 361184610Salfred * NOTE: This function is thread safe. All calls to 362194228Sthompsa * "usbd_do_request_flags" will be serialised by the use of an 363184610Salfred * internal "sx_lock". 364184610Salfred * 365184610Salfred * Returns: 366184610Salfred * 0: Success 367184610Salfred * Else: Failure 368184610Salfred *------------------------------------------------------------------------*/ 369193045Sthompsausb_error_t 370194228Sthompsausbd_do_request_flags(struct usb_device *udev, struct mtx *mtx, 371192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 372193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 373184610Salfred{ 374208018Sthompsa#ifdef USB_REQ_DEBUG 375208018Sthompsa struct usb_ctrl_debug_bits dbg; 376208018Sthompsa#endif 377193045Sthompsa usb_handle_req_t *hr_func; 378192984Sthompsa struct usb_xfer *xfer; 379184610Salfred const void *desc; 380184610Salfred int err = 0; 381193045Sthompsa usb_ticks_t start_ticks; 382193045Sthompsa usb_ticks_t delta_ticks; 383193045Sthompsa usb_ticks_t max_ticks; 384184610Salfred uint16_t length; 385184610Salfred uint16_t temp; 386208018Sthompsa uint16_t acttemp; 387208008Sthompsa uint8_t enum_locked; 388184610Salfred 389184610Salfred if (timeout < 50) { 390184610Salfred /* timeout is too small */ 391184610Salfred timeout = 50; 392184610Salfred } 393184610Salfred if (timeout > 30000) { 394184610Salfred /* timeout is too big */ 395184610Salfred timeout = 30000; 396184610Salfred } 397184610Salfred length = UGETW(req->wLength); 398184610Salfred 399208008Sthompsa enum_locked = usbd_enum_is_locked(udev); 400208008Sthompsa 401184610Salfred DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x " 402184610Salfred "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n", 403184610Salfred udev, req->bmRequestType, req->bRequest, 404184610Salfred req->wValue[1], req->wValue[0], 405184610Salfred req->wIndex[1], req->wIndex[0], 406184610Salfred req->wLength[1], req->wLength[0]); 407184610Salfred 408191494Sthompsa /* Check if the device is still alive */ 409191494Sthompsa if (udev->state < USB_STATE_POWERED) { 410191494Sthompsa DPRINTF("usb device has gone\n"); 411191494Sthompsa return (USB_ERR_NOT_CONFIGURED); 412191494Sthompsa } 413191494Sthompsa 414184610Salfred /* 415184610Salfred * Set "actlen" to a known value in case the caller does not 416184610Salfred * check the return value: 417184610Salfred */ 418190735Sthompsa if (actlen) 419184610Salfred *actlen = 0; 420190735Sthompsa 421190180Sthompsa#if (USB_HAVE_USER_IO == 0) 422190180Sthompsa if (flags & USB_USER_DATA_PTR) 423190180Sthompsa return (USB_ERR_INVAL); 424190180Sthompsa#endif 425208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) { 426184610Salfred mtx_unlock(mtx); 427208008Sthompsa mtx_assert(mtx, MA_NOTOWNED); 428184610Salfred } 429208008Sthompsa 430184610Salfred /* 431208008Sthompsa * We need to allow suspend and resume at this point, else the 432208008Sthompsa * control transfer will timeout if the device is suspended! 433208008Sthompsa */ 434208008Sthompsa if (enum_locked) 435208008Sthompsa usbd_sr_unlock(udev); 436208008Sthompsa 437208008Sthompsa /* 438184610Salfred * Grab the default sx-lock so that serialisation 439184610Salfred * is achieved when multiple threads are involved: 440184610Salfred */ 441207079Sthompsa sx_xlock(&udev->ctrl_sx); 442184610Salfred 443194228Sthompsa hr_func = usbd_get_hr_func(udev); 444190735Sthompsa 445191402Sthompsa if (hr_func != NULL) { 446191402Sthompsa DPRINTF("Handle Request function is set\n"); 447190735Sthompsa 448191402Sthompsa desc = NULL; 449191402Sthompsa temp = 0; 450191402Sthompsa 451191402Sthompsa if (!(req->bmRequestType & UT_READ)) { 452190735Sthompsa if (length != 0) { 453191402Sthompsa DPRINTFN(1, "The handle request function " 454191402Sthompsa "does not support writing data!\n"); 455191402Sthompsa err = USB_ERR_INVAL; 456191402Sthompsa goto done; 457190735Sthompsa } 458190735Sthompsa } 459190735Sthompsa 460191402Sthompsa /* The root HUB code needs the BUS lock locked */ 461191402Sthompsa 462190735Sthompsa USB_BUS_LOCK(udev->bus); 463191402Sthompsa err = (hr_func) (udev, req, &desc, &temp); 464190735Sthompsa USB_BUS_UNLOCK(udev->bus); 465190735Sthompsa 466190735Sthompsa if (err) 467190735Sthompsa goto done; 468190735Sthompsa 469191402Sthompsa if (length > temp) { 470190735Sthompsa if (!(flags & USB_SHORT_XFER_OK)) { 471190735Sthompsa err = USB_ERR_SHORT_XFER; 472190735Sthompsa goto done; 473190735Sthompsa } 474191402Sthompsa length = temp; 475190735Sthompsa } 476190735Sthompsa if (actlen) 477190735Sthompsa *actlen = length; 478190735Sthompsa 479190735Sthompsa if (length > 0) { 480190735Sthompsa#if USB_HAVE_USER_IO 481190735Sthompsa if (flags & USB_USER_DATA_PTR) { 482191402Sthompsa if (copyout(desc, data, length)) { 483190735Sthompsa err = USB_ERR_INVAL; 484190735Sthompsa goto done; 485190735Sthompsa } 486190735Sthompsa } else 487190735Sthompsa#endif 488191402Sthompsa bcopy(desc, data, length); 489190735Sthompsa } 490191402Sthompsa goto done; /* success */ 491190735Sthompsa } 492190735Sthompsa 493184610Salfred /* 494184610Salfred * Setup a new USB transfer or use the existing one, if any: 495184610Salfred */ 496207080Sthompsa usbd_ctrl_transfer_setup(udev); 497184610Salfred 498207080Sthompsa xfer = udev->ctrl_xfer[0]; 499184610Salfred if (xfer == NULL) { 500184610Salfred /* most likely out of memory */ 501184610Salfred err = USB_ERR_NOMEM; 502184610Salfred goto done; 503184610Salfred } 504208018Sthompsa 505208018Sthompsa#ifdef USB_REQ_DEBUG 506208018Sthompsa /* Get debug bits */ 507208018Sthompsa usbd_get_debug_bits(udev, req, &dbg); 508208018Sthompsa 509208018Sthompsa /* Check for fault injection */ 510208018Sthompsa if (dbg.enabled) 511208018Sthompsa flags |= USB_DELAY_STATUS_STAGE; 512208018Sthompsa#endif 513184824Sthompsa USB_XFER_LOCK(xfer); 514184610Salfred 515190734Sthompsa if (flags & USB_DELAY_STATUS_STAGE) 516184610Salfred xfer->flags.manual_status = 1; 517190734Sthompsa else 518184610Salfred xfer->flags.manual_status = 0; 519184610Salfred 520190734Sthompsa if (flags & USB_SHORT_XFER_OK) 521190734Sthompsa xfer->flags.short_xfer_ok = 1; 522190734Sthompsa else 523190734Sthompsa xfer->flags.short_xfer_ok = 0; 524190734Sthompsa 525184610Salfred xfer->timeout = timeout; 526184610Salfred 527184610Salfred start_ticks = ticks; 528184610Salfred 529184610Salfred max_ticks = USB_MS_TO_TICKS(timeout); 530184610Salfred 531194228Sthompsa usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req)); 532184610Salfred 533194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(*req)); 534184610Salfred 535184610Salfred while (1) { 536184610Salfred temp = length; 537208018Sthompsa if (temp > usbd_xfer_max_len(xfer)) { 538194677Sthompsa temp = usbd_xfer_max_len(xfer); 539184610Salfred } 540208018Sthompsa#ifdef USB_REQ_DEBUG 541208018Sthompsa if (xfer->flags.manual_status) { 542208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) != 0) { 543208018Sthompsa /* Execute data stage separately */ 544208018Sthompsa temp = 0; 545208018Sthompsa } else if (temp > 0) { 546208018Sthompsa if (dbg.ds_fail) { 547208018Sthompsa err = USB_ERR_INVAL; 548208018Sthompsa break; 549208018Sthompsa } 550208018Sthompsa if (dbg.ds_delay > 0) { 551208018Sthompsa usb_pause_mtx( 552208018Sthompsa xfer->xroot->xfer_mtx, 553208018Sthompsa USB_MS_TO_TICKS(dbg.ds_delay)); 554208018Sthompsa /* make sure we don't time out */ 555208018Sthompsa start_ticks = ticks; 556208018Sthompsa } 557208018Sthompsa } 558208018Sthompsa } 559208018Sthompsa#endif 560194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, temp); 561184610Salfred 562184610Salfred if (temp > 0) { 563184610Salfred if (!(req->bmRequestType & UT_READ)) { 564190180Sthompsa#if USB_HAVE_USER_IO 565184610Salfred if (flags & USB_USER_DATA_PTR) { 566184824Sthompsa USB_XFER_UNLOCK(xfer); 567194228Sthompsa err = usbd_copy_in_user(xfer->frbuffers + 1, 568184610Salfred 0, data, temp); 569184824Sthompsa USB_XFER_LOCK(xfer); 570184610Salfred if (err) { 571184610Salfred err = USB_ERR_INVAL; 572184610Salfred break; 573184610Salfred } 574190180Sthompsa } else 575190180Sthompsa#endif 576194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 577190180Sthompsa 0, data, temp); 578184610Salfred } 579208018Sthompsa usbd_xfer_set_frames(xfer, 2); 580184610Salfred } else { 581208018Sthompsa if (usbd_xfer_frame_len(xfer, 0) == 0) { 582184610Salfred if (xfer->flags.manual_status) { 583208018Sthompsa#ifdef USB_REQ_DEBUG 584208018Sthompsa if (dbg.ss_fail) { 585208018Sthompsa err = USB_ERR_INVAL; 586208018Sthompsa break; 587184610Salfred } 588208018Sthompsa if (dbg.ss_delay > 0) { 589194228Sthompsa usb_pause_mtx( 590187173Sthompsa xfer->xroot->xfer_mtx, 591208018Sthompsa USB_MS_TO_TICKS(dbg.ss_delay)); 592208018Sthompsa /* make sure we don't time out */ 593208018Sthompsa start_ticks = ticks; 594184610Salfred } 595184610Salfred#endif 596184610Salfred xfer->flags.manual_status = 0; 597184610Salfred } else { 598184610Salfred break; 599184610Salfred } 600184610Salfred } 601208018Sthompsa usbd_xfer_set_frames(xfer, 1); 602184610Salfred } 603184610Salfred 604194228Sthompsa usbd_transfer_start(xfer); 605184610Salfred 606194228Sthompsa while (usbd_transfer_pending(xfer)) { 607207079Sthompsa cv_wait(&udev->ctrlreq_cv, 608188983Sthompsa xfer->xroot->xfer_mtx); 609184610Salfred } 610184610Salfred 611184610Salfred err = xfer->error; 612184610Salfred 613184610Salfred if (err) { 614184610Salfred break; 615184610Salfred } 616184610Salfred 617208018Sthompsa /* get actual length of DATA stage */ 618208018Sthompsa 619208018Sthompsa if (xfer->aframes < 2) { 620208018Sthompsa acttemp = 0; 621184610Salfred } else { 622208018Sthompsa acttemp = usbd_xfer_frame_len(xfer, 1); 623184610Salfred } 624184610Salfred 625184610Salfred /* check for short packet */ 626184610Salfred 627208018Sthompsa if (temp > acttemp) { 628208018Sthompsa temp = acttemp; 629184610Salfred length = temp; 630184610Salfred } 631184610Salfred if (temp > 0) { 632184610Salfred if (req->bmRequestType & UT_READ) { 633190180Sthompsa#if USB_HAVE_USER_IO 634184610Salfred if (flags & USB_USER_DATA_PTR) { 635184824Sthompsa USB_XFER_UNLOCK(xfer); 636194228Sthompsa err = usbd_copy_out_user(xfer->frbuffers + 1, 637184610Salfred 0, data, temp); 638184824Sthompsa USB_XFER_LOCK(xfer); 639184610Salfred if (err) { 640184610Salfred err = USB_ERR_INVAL; 641184610Salfred break; 642184610Salfred } 643190180Sthompsa } else 644190180Sthompsa#endif 645194228Sthompsa usbd_copy_out(xfer->frbuffers + 1, 646184610Salfred 0, data, temp); 647184610Salfred } 648184610Salfred } 649184610Salfred /* 650184610Salfred * Clear "frlengths[0]" so that we don't send the setup 651184610Salfred * packet again: 652184610Salfred */ 653194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, 0); 654184610Salfred 655184610Salfred /* update length and data pointer */ 656184610Salfred length -= temp; 657184610Salfred data = USB_ADD_BYTES(data, temp); 658184610Salfred 659184610Salfred if (actlen) { 660184610Salfred (*actlen) += temp; 661184610Salfred } 662184610Salfred /* check for timeout */ 663184610Salfred 664184610Salfred delta_ticks = ticks - start_ticks; 665184610Salfred if (delta_ticks > max_ticks) { 666184610Salfred if (!err) { 667184610Salfred err = USB_ERR_TIMEOUT; 668184610Salfred } 669184610Salfred } 670184610Salfred if (err) { 671184610Salfred break; 672184610Salfred } 673184610Salfred } 674184610Salfred 675184610Salfred if (err) { 676184610Salfred /* 677184610Salfred * Make sure that the control endpoint is no longer 678184610Salfred * blocked in case of a non-transfer related error: 679184610Salfred */ 680194228Sthompsa usbd_transfer_stop(xfer); 681184610Salfred } 682184824Sthompsa USB_XFER_UNLOCK(xfer); 683184610Salfred 684184610Salfreddone: 685207079Sthompsa sx_xunlock(&udev->ctrl_sx); 686184610Salfred 687208008Sthompsa if (enum_locked) 688208008Sthompsa usbd_sr_lock(udev); 689208008Sthompsa 690208008Sthompsa if ((mtx != NULL) && (mtx != &Giant)) 691184610Salfred mtx_lock(mtx); 692208008Sthompsa 693193045Sthompsa return ((usb_error_t)err); 694184610Salfred} 695184610Salfred 696184610Salfred/*------------------------------------------------------------------------* 697194228Sthompsa * usbd_do_request_proc - factored out code 698188411Sthompsa * 699188411Sthompsa * This function is factored out code. It does basically the same like 700194228Sthompsa * usbd_do_request_flags, except it will check the status of the 701188411Sthompsa * passed process argument before doing the USB request. If the 702188411Sthompsa * process is draining the USB_ERR_IOERROR code will be returned. It 703188411Sthompsa * is assumed that the mutex associated with the process is locked 704188411Sthompsa * when calling this function. 705188411Sthompsa *------------------------------------------------------------------------*/ 706193045Sthompsausb_error_t 707194228Sthompsausbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, 708192984Sthompsa struct usb_device_request *req, void *data, uint16_t flags, 709193045Sthompsa uint16_t *actlen, usb_timeout_t timeout) 710188411Sthompsa{ 711193045Sthompsa usb_error_t err; 712188411Sthompsa uint16_t len; 713188411Sthompsa 714188411Sthompsa /* get request data length */ 715188411Sthompsa len = UGETW(req->wLength); 716188411Sthompsa 717188411Sthompsa /* check if the device is being detached */ 718194228Sthompsa if (usb_proc_is_gone(pproc)) { 719188411Sthompsa err = USB_ERR_IOERROR; 720188411Sthompsa goto done; 721188411Sthompsa } 722188411Sthompsa 723188411Sthompsa /* forward the USB request */ 724194228Sthompsa err = usbd_do_request_flags(udev, pproc->up_mtx, 725188411Sthompsa req, data, flags, actlen, timeout); 726188411Sthompsa 727188411Sthompsadone: 728188411Sthompsa /* on failure we zero the data */ 729188411Sthompsa /* on short packet we zero the unused data */ 730188411Sthompsa if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { 731188411Sthompsa if (err) 732188411Sthompsa memset(data, 0, len); 733188411Sthompsa else if (actlen && *actlen != len) 734188411Sthompsa memset(((uint8_t *)data) + *actlen, 0, len - *actlen); 735188411Sthompsa } 736188411Sthompsa return (err); 737188411Sthompsa} 738188411Sthompsa 739188411Sthompsa/*------------------------------------------------------------------------* 740194228Sthompsa * usbd_req_reset_port 741184610Salfred * 742184610Salfred * This function will instruct an USB HUB to perform a reset sequence 743184610Salfred * on the specified port number. 744184610Salfred * 745184610Salfred * Returns: 746184610Salfred * 0: Success. The USB device should now be at address zero. 747184610Salfred * Else: Failure. No USB device is present and the USB port should be 748184610Salfred * disabled. 749184610Salfred *------------------------------------------------------------------------*/ 750193045Sthompsausb_error_t 751194228Sthompsausbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port) 752184610Salfred{ 753192984Sthompsa struct usb_port_status ps; 754193045Sthompsa usb_error_t err; 755184610Salfred uint16_t n; 756184610Salfred 757207077Sthompsa#ifdef USB_DEBUG 758184610Salfred uint16_t pr_poll_delay; 759184610Salfred uint16_t pr_recovery_delay; 760184610Salfred 761184610Salfred#endif 762194228Sthompsa err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET); 763184610Salfred if (err) { 764184610Salfred goto done; 765184610Salfred } 766207077Sthompsa#ifdef USB_DEBUG 767184610Salfred /* range check input parameters */ 768194228Sthompsa pr_poll_delay = usb_pr_poll_delay; 769184610Salfred if (pr_poll_delay < 1) { 770184610Salfred pr_poll_delay = 1; 771184610Salfred } else if (pr_poll_delay > 1000) { 772184610Salfred pr_poll_delay = 1000; 773184610Salfred } 774194228Sthompsa pr_recovery_delay = usb_pr_recovery_delay; 775184610Salfred if (pr_recovery_delay > 1000) { 776184610Salfred pr_recovery_delay = 1000; 777184610Salfred } 778184610Salfred#endif 779184610Salfred n = 0; 780184610Salfred while (1) { 781207077Sthompsa#ifdef USB_DEBUG 782184610Salfred /* wait for the device to recover from reset */ 783194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay)); 784184610Salfred n += pr_poll_delay; 785184610Salfred#else 786184610Salfred /* wait for the device to recover from reset */ 787194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY)); 788184610Salfred n += USB_PORT_RESET_DELAY; 789184610Salfred#endif 790194228Sthompsa err = usbd_req_get_port_status(udev, mtx, &ps, port); 791184610Salfred if (err) { 792184610Salfred goto done; 793184610Salfred } 794184610Salfred /* if the device disappeared, just give up */ 795184610Salfred if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) { 796184610Salfred goto done; 797184610Salfred } 798184610Salfred /* check if reset is complete */ 799184610Salfred if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) { 800184610Salfred break; 801184610Salfred } 802184610Salfred /* check for timeout */ 803184610Salfred if (n > 1000) { 804184610Salfred n = 0; 805184610Salfred break; 806184610Salfred } 807184610Salfred } 808184610Salfred 809184610Salfred /* clear port reset first */ 810194228Sthompsa err = usbd_req_clear_port_feature( 811184610Salfred udev, mtx, port, UHF_C_PORT_RESET); 812184610Salfred if (err) { 813184610Salfred goto done; 814184610Salfred } 815184610Salfred /* check for timeout */ 816184610Salfred if (n == 0) { 817184610Salfred err = USB_ERR_TIMEOUT; 818184610Salfred goto done; 819184610Salfred } 820207077Sthompsa#ifdef USB_DEBUG 821184610Salfred /* wait for the device to recover from reset */ 822194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay)); 823184610Salfred#else 824184610Salfred /* wait for the device to recover from reset */ 825194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY)); 826184610Salfred#endif 827184610Salfred 828184610Salfreddone: 829184610Salfred DPRINTFN(2, "port %d reset returning error=%s\n", 830194228Sthompsa port, usbd_errstr(err)); 831184610Salfred return (err); 832184610Salfred} 833184610Salfred 834184610Salfred/*------------------------------------------------------------------------* 835194228Sthompsa * usbd_req_get_desc 836184610Salfred * 837184610Salfred * This function can be used to retrieve USB descriptors. It contains 838184610Salfred * some additional logic like zeroing of missing descriptor bytes and 839184610Salfred * retrying an USB descriptor in case of failure. The "min_len" 840184610Salfred * argument specifies the minimum descriptor length. The "max_len" 841184610Salfred * argument specifies the maximum descriptor length. If the real 842184610Salfred * descriptor length is less than the minimum length the missing 843188985Sthompsa * byte(s) will be zeroed. The type field, the second byte of the USB 844188985Sthompsa * descriptor, will get forced to the correct type. If the "actlen" 845188985Sthompsa * pointer is non-NULL, the actual length of the transfer will get 846188985Sthompsa * stored in the 16-bit unsigned integer which it is pointing to. The 847188985Sthompsa * first byte of the descriptor will not get updated. If the "actlen" 848188985Sthompsa * pointer is NULL the first byte of the descriptor will get updated 849188985Sthompsa * to reflect the actual length instead. If "min_len" is not equal to 850188985Sthompsa * "max_len" then this function will try to retrive the beginning of 851188985Sthompsa * the descriptor and base the maximum length on the first byte of the 852188985Sthompsa * descriptor. 853184610Salfred * 854184610Salfred * Returns: 855184610Salfred * 0: Success 856184610Salfred * Else: Failure 857184610Salfred *------------------------------------------------------------------------*/ 858193045Sthompsausb_error_t 859194228Sthompsausbd_req_get_desc(struct usb_device *udev, 860188985Sthompsa struct mtx *mtx, uint16_t *actlen, void *desc, 861184610Salfred uint16_t min_len, uint16_t max_len, 862184610Salfred uint16_t id, uint8_t type, uint8_t index, 863184610Salfred uint8_t retries) 864184610Salfred{ 865192984Sthompsa struct usb_device_request req; 866184610Salfred uint8_t *buf; 867193045Sthompsa usb_error_t err; 868184610Salfred 869184610Salfred DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", 870184610Salfred id, type, index, max_len); 871184610Salfred 872184610Salfred req.bmRequestType = UT_READ_DEVICE; 873184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 874184610Salfred USETW2(req.wValue, type, index); 875184610Salfred USETW(req.wIndex, id); 876184610Salfred 877184610Salfred while (1) { 878184610Salfred 879184610Salfred if ((min_len < 2) || (max_len < 2)) { 880184610Salfred err = USB_ERR_INVAL; 881184610Salfred goto done; 882184610Salfred } 883184610Salfred USETW(req.wLength, min_len); 884184610Salfred 885194228Sthompsa err = usbd_do_request_flags(udev, mtx, &req, 886186730Salfred desc, 0, NULL, 1000); 887184610Salfred 888184610Salfred if (err) { 889184610Salfred if (!retries) { 890184610Salfred goto done; 891184610Salfred } 892184610Salfred retries--; 893184610Salfred 894194228Sthompsa usb_pause_mtx(mtx, hz / 5); 895184610Salfred 896184610Salfred continue; 897184610Salfred } 898184610Salfred buf = desc; 899184610Salfred 900184610Salfred if (min_len == max_len) { 901184610Salfred 902188985Sthompsa /* enforce correct length */ 903188985Sthompsa if ((buf[0] > min_len) && (actlen == NULL)) 904188985Sthompsa buf[0] = min_len; 905184610Salfred 906188985Sthompsa /* enforce correct type */ 907184610Salfred buf[1] = type; 908184610Salfred 909184610Salfred goto done; 910184610Salfred } 911184610Salfred /* range check */ 912184610Salfred 913184610Salfred if (max_len > buf[0]) { 914184610Salfred max_len = buf[0]; 915184610Salfred } 916184610Salfred /* zero minimum data */ 917184610Salfred 918184610Salfred while (min_len > max_len) { 919184610Salfred min_len--; 920184610Salfred buf[min_len] = 0; 921184610Salfred } 922184610Salfred 923184610Salfred /* set new minimum length */ 924184610Salfred 925184610Salfred min_len = max_len; 926184610Salfred } 927184610Salfreddone: 928188985Sthompsa if (actlen != NULL) { 929188985Sthompsa if (err) 930188985Sthompsa *actlen = 0; 931188985Sthompsa else 932188985Sthompsa *actlen = min_len; 933188985Sthompsa } 934184610Salfred return (err); 935184610Salfred} 936184610Salfred 937184610Salfred/*------------------------------------------------------------------------* 938194228Sthompsa * usbd_req_get_string_any 939184610Salfred * 940184610Salfred * This function will return the string given by "string_index" 941184610Salfred * using the first language ID. The maximum length "len" includes 942184610Salfred * the terminating zero. The "len" argument should be twice as 943184610Salfred * big pluss 2 bytes, compared with the actual maximum string length ! 944184610Salfred * 945184610Salfred * Returns: 946184610Salfred * 0: Success 947184610Salfred * Else: Failure 948184610Salfred *------------------------------------------------------------------------*/ 949193045Sthompsausb_error_t 950194228Sthompsausbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, 951184610Salfred uint16_t len, uint8_t string_index) 952184610Salfred{ 953184610Salfred char *s; 954184610Salfred uint8_t *temp; 955184610Salfred uint16_t i; 956184610Salfred uint16_t n; 957184610Salfred uint16_t c; 958184610Salfred uint8_t swap; 959193045Sthompsa usb_error_t err; 960184610Salfred 961184610Salfred if (len == 0) { 962184610Salfred /* should not happen */ 963184610Salfred return (USB_ERR_NORMAL_COMPLETION); 964184610Salfred } 965184610Salfred if (string_index == 0) { 966184610Salfred /* this is the language table */ 967185087Salfred buf[0] = 0; 968184610Salfred return (USB_ERR_INVAL); 969184610Salfred } 970184610Salfred if (udev->flags.no_strings) { 971185087Salfred buf[0] = 0; 972184610Salfred return (USB_ERR_STALLED); 973184610Salfred } 974194228Sthompsa err = usbd_req_get_string_desc 975184610Salfred (udev, mtx, buf, len, udev->langid, string_index); 976184610Salfred if (err) { 977185087Salfred buf[0] = 0; 978184610Salfred return (err); 979184610Salfred } 980184610Salfred temp = (uint8_t *)buf; 981184610Salfred 982184610Salfred if (temp[0] < 2) { 983184610Salfred /* string length is too short */ 984185087Salfred buf[0] = 0; 985184610Salfred return (USB_ERR_INVAL); 986184610Salfred } 987184610Salfred /* reserve one byte for terminating zero */ 988184610Salfred len--; 989184610Salfred 990184610Salfred /* find maximum length */ 991184610Salfred s = buf; 992184610Salfred n = (temp[0] / 2) - 1; 993184610Salfred if (n > len) { 994184610Salfred n = len; 995184610Salfred } 996184610Salfred /* skip descriptor header */ 997184610Salfred temp += 2; 998184610Salfred 999184610Salfred /* reset swap state */ 1000184610Salfred swap = 3; 1001184610Salfred 1002184610Salfred /* convert and filter */ 1003184610Salfred for (i = 0; (i != n); i++) { 1004184610Salfred c = UGETW(temp + (2 * i)); 1005184610Salfred 1006184610Salfred /* convert from Unicode, handle buggy strings */ 1007184610Salfred if (((c & 0xff00) == 0) && (swap & 1)) { 1008184610Salfred /* Little Endian, default */ 1009184610Salfred *s = c; 1010184610Salfred swap = 1; 1011184610Salfred } else if (((c & 0x00ff) == 0) && (swap & 2)) { 1012184610Salfred /* Big Endian */ 1013184610Salfred *s = c >> 8; 1014184610Salfred swap = 2; 1015184610Salfred } else { 1016185087Salfred /* silently skip bad character */ 1017185087Salfred continue; 1018184610Salfred } 1019184610Salfred 1020184610Salfred /* 1021184610Salfred * Filter by default - we don't allow greater and less than 1022184610Salfred * signs because they might confuse the dmesg printouts! 1023184610Salfred */ 1024184610Salfred if ((*s == '<') || (*s == '>') || (!isprint(*s))) { 1025185087Salfred /* silently skip bad character */ 1026185087Salfred continue; 1027184610Salfred } 1028184610Salfred s++; 1029184610Salfred } 1030185087Salfred *s = 0; /* zero terminate resulting string */ 1031184610Salfred return (USB_ERR_NORMAL_COMPLETION); 1032184610Salfred} 1033184610Salfred 1034184610Salfred/*------------------------------------------------------------------------* 1035194228Sthompsa * usbd_req_get_string_desc 1036184610Salfred * 1037184610Salfred * If you don't know the language ID, consider using 1038194228Sthompsa * "usbd_req_get_string_any()". 1039184610Salfred * 1040184610Salfred * Returns: 1041184610Salfred * 0: Success 1042184610Salfred * Else: Failure 1043184610Salfred *------------------------------------------------------------------------*/ 1044193045Sthompsausb_error_t 1045194228Sthompsausbd_req_get_string_desc(struct usb_device *udev, struct mtx *mtx, void *sdesc, 1046184610Salfred uint16_t max_len, uint16_t lang_id, 1047184610Salfred uint8_t string_index) 1048184610Salfred{ 1049194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, sdesc, 2, max_len, lang_id, 1050184610Salfred UDESC_STRING, string_index, 0)); 1051184610Salfred} 1052184610Salfred 1053184610Salfred/*------------------------------------------------------------------------* 1054194228Sthompsa * usbd_req_get_config_desc_ptr 1055190727Sthompsa * 1056190727Sthompsa * This function is used in device side mode to retrieve the pointer 1057190727Sthompsa * to the generated config descriptor. This saves allocating space for 1058190727Sthompsa * an additional config descriptor when setting the configuration. 1059190727Sthompsa * 1060190727Sthompsa * Returns: 1061190727Sthompsa * 0: Success 1062190727Sthompsa * Else: Failure 1063190727Sthompsa *------------------------------------------------------------------------*/ 1064193045Sthompsausb_error_t 1065194228Sthompsausbd_req_get_descriptor_ptr(struct usb_device *udev, 1066192984Sthompsa struct usb_config_descriptor **ppcd, uint16_t wValue) 1067190727Sthompsa{ 1068192984Sthompsa struct usb_device_request req; 1069193045Sthompsa usb_handle_req_t *hr_func; 1070191402Sthompsa const void *ptr; 1071190727Sthompsa uint16_t len; 1072193045Sthompsa usb_error_t err; 1073190727Sthompsa 1074190731Sthompsa req.bmRequestType = UT_READ_DEVICE; 1075190727Sthompsa req.bRequest = UR_GET_DESCRIPTOR; 1076191402Sthompsa USETW(req.wValue, wValue); 1077190727Sthompsa USETW(req.wIndex, 0); 1078190727Sthompsa USETW(req.wLength, 0); 1079190727Sthompsa 1080191402Sthompsa ptr = NULL; 1081191402Sthompsa len = 0; 1082190727Sthompsa 1083194228Sthompsa hr_func = usbd_get_hr_func(udev); 1084191402Sthompsa 1085191402Sthompsa if (hr_func == NULL) 1086191402Sthompsa err = USB_ERR_INVAL; 1087191402Sthompsa else { 1088191402Sthompsa USB_BUS_LOCK(udev->bus); 1089191402Sthompsa err = (hr_func) (udev, &req, &ptr, &len); 1090191402Sthompsa USB_BUS_UNLOCK(udev->bus); 1091191402Sthompsa } 1092191402Sthompsa 1093191402Sthompsa if (err) 1094191402Sthompsa ptr = NULL; 1095191402Sthompsa else if (ptr == NULL) 1096191402Sthompsa err = USB_ERR_INVAL; 1097191402Sthompsa 1098192984Sthompsa *ppcd = __DECONST(struct usb_config_descriptor *, ptr); 1099191402Sthompsa 1100191402Sthompsa return (err); 1101190727Sthompsa} 1102190727Sthompsa 1103190727Sthompsa/*------------------------------------------------------------------------* 1104194228Sthompsa * usbd_req_get_config_desc 1105184610Salfred * 1106184610Salfred * Returns: 1107184610Salfred * 0: Success 1108184610Salfred * Else: Failure 1109184610Salfred *------------------------------------------------------------------------*/ 1110193045Sthompsausb_error_t 1111194228Sthompsausbd_req_get_config_desc(struct usb_device *udev, struct mtx *mtx, 1112192984Sthompsa struct usb_config_descriptor *d, uint8_t conf_index) 1113184610Salfred{ 1114193045Sthompsa usb_error_t err; 1115184610Salfred 1116184610Salfred DPRINTFN(4, "confidx=%d\n", conf_index); 1117184610Salfred 1118194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1119184610Salfred sizeof(*d), 0, UDESC_CONFIG, conf_index, 0); 1120184610Salfred if (err) { 1121184610Salfred goto done; 1122184610Salfred } 1123184610Salfred /* Extra sanity checking */ 1124184610Salfred if (UGETW(d->wTotalLength) < sizeof(*d)) { 1125184610Salfred err = USB_ERR_INVAL; 1126184610Salfred } 1127184610Salfreddone: 1128184610Salfred return (err); 1129184610Salfred} 1130184610Salfred 1131184610Salfred/*------------------------------------------------------------------------* 1132194228Sthompsa * usbd_req_get_config_desc_full 1133184610Salfred * 1134184610Salfred * This function gets the complete USB configuration descriptor and 1135184610Salfred * ensures that "wTotalLength" is correct. 1136184610Salfred * 1137184610Salfred * Returns: 1138184610Salfred * 0: Success 1139184610Salfred * Else: Failure 1140184610Salfred *------------------------------------------------------------------------*/ 1141193045Sthompsausb_error_t 1142194228Sthompsausbd_req_get_config_desc_full(struct usb_device *udev, struct mtx *mtx, 1143192984Sthompsa struct usb_config_descriptor **ppcd, struct malloc_type *mtype, 1144184610Salfred uint8_t index) 1145184610Salfred{ 1146192984Sthompsa struct usb_config_descriptor cd; 1147192984Sthompsa struct usb_config_descriptor *cdesc; 1148184610Salfred uint16_t len; 1149193045Sthompsa usb_error_t err; 1150184610Salfred 1151184610Salfred DPRINTFN(4, "index=%d\n", index); 1152184610Salfred 1153184610Salfred *ppcd = NULL; 1154184610Salfred 1155194228Sthompsa err = usbd_req_get_config_desc(udev, mtx, &cd, index); 1156184610Salfred if (err) { 1157184610Salfred return (err); 1158184610Salfred } 1159184610Salfred /* get full descriptor */ 1160184610Salfred len = UGETW(cd.wTotalLength); 1161184610Salfred if (len < sizeof(*cdesc)) { 1162184610Salfred /* corrupt descriptor */ 1163184610Salfred return (USB_ERR_INVAL); 1164184610Salfred } 1165184610Salfred cdesc = malloc(len, mtype, M_WAITOK); 1166184610Salfred if (cdesc == NULL) { 1167184610Salfred return (USB_ERR_NOMEM); 1168184610Salfred } 1169194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, cdesc, len, len, 0, 1170184610Salfred UDESC_CONFIG, index, 3); 1171184610Salfred if (err) { 1172184610Salfred free(cdesc, mtype); 1173184610Salfred return (err); 1174184610Salfred } 1175184610Salfred /* make sure that the device is not fooling us: */ 1176184610Salfred USETW(cdesc->wTotalLength, len); 1177184610Salfred 1178184610Salfred *ppcd = cdesc; 1179184610Salfred 1180184610Salfred return (0); /* success */ 1181184610Salfred} 1182184610Salfred 1183184610Salfred/*------------------------------------------------------------------------* 1184194228Sthompsa * usbd_req_get_device_desc 1185184610Salfred * 1186184610Salfred * Returns: 1187184610Salfred * 0: Success 1188184610Salfred * Else: Failure 1189184610Salfred *------------------------------------------------------------------------*/ 1190193045Sthompsausb_error_t 1191194228Sthompsausbd_req_get_device_desc(struct usb_device *udev, struct mtx *mtx, 1192192984Sthompsa struct usb_device_descriptor *d) 1193184610Salfred{ 1194184610Salfred DPRINTFN(4, "\n"); 1195194228Sthompsa return (usbd_req_get_desc(udev, mtx, NULL, d, sizeof(*d), 1196184610Salfred sizeof(*d), 0, UDESC_DEVICE, 0, 3)); 1197184610Salfred} 1198184610Salfred 1199184610Salfred/*------------------------------------------------------------------------* 1200194228Sthompsa * usbd_req_get_alt_interface_no 1201184610Salfred * 1202184610Salfred * Returns: 1203184610Salfred * 0: Success 1204184610Salfred * Else: Failure 1205184610Salfred *------------------------------------------------------------------------*/ 1206193045Sthompsausb_error_t 1207194228Sthompsausbd_req_get_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1208184610Salfred uint8_t *alt_iface_no, uint8_t iface_index) 1209184610Salfred{ 1210194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1211192984Sthompsa struct usb_device_request req; 1212184610Salfred 1213195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1214184610Salfred return (USB_ERR_INVAL); 1215195963Salfred 1216184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1217184610Salfred req.bRequest = UR_GET_INTERFACE; 1218184610Salfred USETW(req.wValue, 0); 1219184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1220184610Salfred req.wIndex[1] = 0; 1221184610Salfred USETW(req.wLength, 1); 1222194228Sthompsa return (usbd_do_request(udev, mtx, &req, alt_iface_no)); 1223184610Salfred} 1224184610Salfred 1225184610Salfred/*------------------------------------------------------------------------* 1226194228Sthompsa * usbd_req_set_alt_interface_no 1227184610Salfred * 1228184610Salfred * Returns: 1229184610Salfred * 0: Success 1230184610Salfred * Else: Failure 1231184610Salfred *------------------------------------------------------------------------*/ 1232193045Sthompsausb_error_t 1233194228Sthompsausbd_req_set_alt_interface_no(struct usb_device *udev, struct mtx *mtx, 1234184610Salfred uint8_t iface_index, uint8_t alt_no) 1235184610Salfred{ 1236194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1237192984Sthompsa struct usb_device_request req; 1238184610Salfred 1239195963Salfred if ((iface == NULL) || (iface->idesc == NULL)) 1240184610Salfred return (USB_ERR_INVAL); 1241195963Salfred 1242184610Salfred req.bmRequestType = UT_WRITE_INTERFACE; 1243184610Salfred req.bRequest = UR_SET_INTERFACE; 1244184610Salfred req.wValue[0] = alt_no; 1245184610Salfred req.wValue[1] = 0; 1246184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1247184610Salfred req.wIndex[1] = 0; 1248184610Salfred USETW(req.wLength, 0); 1249194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1250184610Salfred} 1251184610Salfred 1252184610Salfred/*------------------------------------------------------------------------* 1253194228Sthompsa * usbd_req_get_device_status 1254184610Salfred * 1255184610Salfred * Returns: 1256184610Salfred * 0: Success 1257184610Salfred * Else: Failure 1258184610Salfred *------------------------------------------------------------------------*/ 1259193045Sthompsausb_error_t 1260194228Sthompsausbd_req_get_device_status(struct usb_device *udev, struct mtx *mtx, 1261192984Sthompsa struct usb_status *st) 1262184610Salfred{ 1263192984Sthompsa struct usb_device_request req; 1264184610Salfred 1265184610Salfred req.bmRequestType = UT_READ_DEVICE; 1266184610Salfred req.bRequest = UR_GET_STATUS; 1267184610Salfred USETW(req.wValue, 0); 1268184610Salfred USETW(req.wIndex, 0); 1269184610Salfred USETW(req.wLength, sizeof(*st)); 1270194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1271184610Salfred} 1272184610Salfred 1273184610Salfred/*------------------------------------------------------------------------* 1274194228Sthompsa * usbd_req_get_hub_descriptor 1275184610Salfred * 1276184610Salfred * Returns: 1277184610Salfred * 0: Success 1278184610Salfred * Else: Failure 1279184610Salfred *------------------------------------------------------------------------*/ 1280193045Sthompsausb_error_t 1281194228Sthompsausbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, 1282192984Sthompsa struct usb_hub_descriptor *hd, uint8_t nports) 1283184610Salfred{ 1284192984Sthompsa struct usb_device_request req; 1285184610Salfred uint16_t len = (nports + 7 + (8 * 8)) / 8; 1286184610Salfred 1287184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1288184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1289184610Salfred USETW2(req.wValue, UDESC_HUB, 0); 1290184610Salfred USETW(req.wIndex, 0); 1291184610Salfred USETW(req.wLength, len); 1292194228Sthompsa return (usbd_do_request(udev, mtx, &req, hd)); 1293184610Salfred} 1294184610Salfred 1295184610Salfred/*------------------------------------------------------------------------* 1296194228Sthompsa * usbd_req_get_hub_status 1297184610Salfred * 1298184610Salfred * Returns: 1299184610Salfred * 0: Success 1300184610Salfred * Else: Failure 1301184610Salfred *------------------------------------------------------------------------*/ 1302193045Sthompsausb_error_t 1303194228Sthompsausbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, 1304192984Sthompsa struct usb_hub_status *st) 1305184610Salfred{ 1306192984Sthompsa struct usb_device_request req; 1307184610Salfred 1308184610Salfred req.bmRequestType = UT_READ_CLASS_DEVICE; 1309184610Salfred req.bRequest = UR_GET_STATUS; 1310184610Salfred USETW(req.wValue, 0); 1311184610Salfred USETW(req.wIndex, 0); 1312192984Sthompsa USETW(req.wLength, sizeof(struct usb_hub_status)); 1313194228Sthompsa return (usbd_do_request(udev, mtx, &req, st)); 1314184610Salfred} 1315184610Salfred 1316184610Salfred/*------------------------------------------------------------------------* 1317194228Sthompsa * usbd_req_set_address 1318184610Salfred * 1319184610Salfred * This function is used to set the address for an USB device. After 1320184610Salfred * port reset the USB device will respond at address zero. 1321184610Salfred * 1322184610Salfred * Returns: 1323184610Salfred * 0: Success 1324184610Salfred * Else: Failure 1325184610Salfred *------------------------------------------------------------------------*/ 1326193045Sthompsausb_error_t 1327194228Sthompsausbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) 1328184610Salfred{ 1329192984Sthompsa struct usb_device_request req; 1330184610Salfred 1331184610Salfred DPRINTFN(6, "setting device address=%d\n", addr); 1332184610Salfred 1333184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1334184610Salfred req.bRequest = UR_SET_ADDRESS; 1335184610Salfred USETW(req.wValue, addr); 1336184610Salfred USETW(req.wIndex, 0); 1337184610Salfred USETW(req.wLength, 0); 1338184610Salfred 1339184610Salfred /* Setting the address should not take more than 1 second ! */ 1340194228Sthompsa return (usbd_do_request_flags(udev, mtx, &req, NULL, 1341184610Salfred USB_DELAY_STATUS_STAGE, NULL, 1000)); 1342184610Salfred} 1343184610Salfred 1344184610Salfred/*------------------------------------------------------------------------* 1345194228Sthompsa * usbd_req_get_port_status 1346184610Salfred * 1347184610Salfred * Returns: 1348184610Salfred * 0: Success 1349184610Salfred * Else: Failure 1350184610Salfred *------------------------------------------------------------------------*/ 1351193045Sthompsausb_error_t 1352194228Sthompsausbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, 1353192984Sthompsa struct usb_port_status *ps, uint8_t port) 1354184610Salfred{ 1355192984Sthompsa struct usb_device_request req; 1356184610Salfred 1357184610Salfred req.bmRequestType = UT_READ_CLASS_OTHER; 1358184610Salfred req.bRequest = UR_GET_STATUS; 1359184610Salfred USETW(req.wValue, 0); 1360184610Salfred req.wIndex[0] = port; 1361184610Salfred req.wIndex[1] = 0; 1362184610Salfred USETW(req.wLength, sizeof *ps); 1363194228Sthompsa return (usbd_do_request(udev, mtx, &req, ps)); 1364184610Salfred} 1365184610Salfred 1366184610Salfred/*------------------------------------------------------------------------* 1367194228Sthompsa * usbd_req_clear_hub_feature 1368184610Salfred * 1369184610Salfred * Returns: 1370184610Salfred * 0: Success 1371184610Salfred * Else: Failure 1372184610Salfred *------------------------------------------------------------------------*/ 1373193045Sthompsausb_error_t 1374194228Sthompsausbd_req_clear_hub_feature(struct usb_device *udev, struct mtx *mtx, 1375184610Salfred uint16_t sel) 1376184610Salfred{ 1377192984Sthompsa struct usb_device_request req; 1378184610Salfred 1379184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1380184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1381184610Salfred USETW(req.wValue, sel); 1382184610Salfred USETW(req.wIndex, 0); 1383184610Salfred USETW(req.wLength, 0); 1384194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1385184610Salfred} 1386184610Salfred 1387184610Salfred/*------------------------------------------------------------------------* 1388194228Sthompsa * usbd_req_set_hub_feature 1389184610Salfred * 1390184610Salfred * Returns: 1391184610Salfred * 0: Success 1392184610Salfred * Else: Failure 1393184610Salfred *------------------------------------------------------------------------*/ 1394193045Sthompsausb_error_t 1395194228Sthompsausbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, 1396184610Salfred uint16_t sel) 1397184610Salfred{ 1398192984Sthompsa struct usb_device_request req; 1399184610Salfred 1400184610Salfred req.bmRequestType = UT_WRITE_CLASS_DEVICE; 1401184610Salfred req.bRequest = UR_SET_FEATURE; 1402184610Salfred USETW(req.wValue, sel); 1403184610Salfred USETW(req.wIndex, 0); 1404184610Salfred USETW(req.wLength, 0); 1405194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1406184610Salfred} 1407184610Salfred 1408184610Salfred/*------------------------------------------------------------------------* 1409194228Sthompsa * usbd_req_clear_port_feature 1410184610Salfred * 1411184610Salfred * Returns: 1412184610Salfred * 0: Success 1413184610Salfred * Else: Failure 1414184610Salfred *------------------------------------------------------------------------*/ 1415193045Sthompsausb_error_t 1416194228Sthompsausbd_req_clear_port_feature(struct usb_device *udev, struct mtx *mtx, 1417184610Salfred uint8_t port, uint16_t sel) 1418184610Salfred{ 1419192984Sthompsa struct usb_device_request req; 1420184610Salfred 1421184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1422184610Salfred req.bRequest = UR_CLEAR_FEATURE; 1423184610Salfred USETW(req.wValue, sel); 1424184610Salfred req.wIndex[0] = port; 1425184610Salfred req.wIndex[1] = 0; 1426184610Salfred USETW(req.wLength, 0); 1427194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1428184610Salfred} 1429184610Salfred 1430184610Salfred/*------------------------------------------------------------------------* 1431194228Sthompsa * usbd_req_set_port_feature 1432184610Salfred * 1433184610Salfred * Returns: 1434184610Salfred * 0: Success 1435184610Salfred * Else: Failure 1436184610Salfred *------------------------------------------------------------------------*/ 1437193045Sthompsausb_error_t 1438194228Sthompsausbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, 1439184610Salfred uint8_t port, uint16_t sel) 1440184610Salfred{ 1441192984Sthompsa struct usb_device_request req; 1442184610Salfred 1443184610Salfred req.bmRequestType = UT_WRITE_CLASS_OTHER; 1444184610Salfred req.bRequest = UR_SET_FEATURE; 1445184610Salfred USETW(req.wValue, sel); 1446184610Salfred req.wIndex[0] = port; 1447184610Salfred req.wIndex[1] = 0; 1448184610Salfred USETW(req.wLength, 0); 1449194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1450184610Salfred} 1451184610Salfred 1452184610Salfred/*------------------------------------------------------------------------* 1453194228Sthompsa * usbd_req_set_protocol 1454184610Salfred * 1455184610Salfred * Returns: 1456184610Salfred * 0: Success 1457184610Salfred * Else: Failure 1458184610Salfred *------------------------------------------------------------------------*/ 1459193045Sthompsausb_error_t 1460194228Sthompsausbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, 1461184610Salfred uint8_t iface_index, uint16_t report) 1462184610Salfred{ 1463194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1464192984Sthompsa struct usb_device_request req; 1465184610Salfred 1466184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1467184610Salfred return (USB_ERR_INVAL); 1468184610Salfred } 1469184610Salfred DPRINTFN(5, "iface=%p, report=%d, endpt=%d\n", 1470184610Salfred iface, report, iface->idesc->bInterfaceNumber); 1471184610Salfred 1472184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1473184610Salfred req.bRequest = UR_SET_PROTOCOL; 1474184610Salfred USETW(req.wValue, report); 1475184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1476184610Salfred req.wIndex[1] = 0; 1477184610Salfred USETW(req.wLength, 0); 1478194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1479184610Salfred} 1480184610Salfred 1481184610Salfred/*------------------------------------------------------------------------* 1482194228Sthompsa * usbd_req_set_report 1483184610Salfred * 1484184610Salfred * Returns: 1485184610Salfred * 0: Success 1486184610Salfred * Else: Failure 1487184610Salfred *------------------------------------------------------------------------*/ 1488193045Sthompsausb_error_t 1489194228Sthompsausbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, 1490184610Salfred uint8_t iface_index, uint8_t type, uint8_t id) 1491184610Salfred{ 1492194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1493192984Sthompsa struct usb_device_request req; 1494184610Salfred 1495184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1496184610Salfred return (USB_ERR_INVAL); 1497184610Salfred } 1498184610Salfred DPRINTFN(5, "len=%d\n", len); 1499184610Salfred 1500184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1501184610Salfred req.bRequest = UR_SET_REPORT; 1502184610Salfred USETW2(req.wValue, type, id); 1503184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1504184610Salfred req.wIndex[1] = 0; 1505184610Salfred USETW(req.wLength, len); 1506194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1507184610Salfred} 1508184610Salfred 1509184610Salfred/*------------------------------------------------------------------------* 1510194228Sthompsa * usbd_req_get_report 1511184610Salfred * 1512184610Salfred * Returns: 1513184610Salfred * 0: Success 1514184610Salfred * Else: Failure 1515184610Salfred *------------------------------------------------------------------------*/ 1516193045Sthompsausb_error_t 1517194228Sthompsausbd_req_get_report(struct usb_device *udev, struct mtx *mtx, void *data, 1518184610Salfred uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id) 1519184610Salfred{ 1520194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1521192984Sthompsa struct usb_device_request req; 1522184610Salfred 1523184610Salfred if ((iface == NULL) || (iface->idesc == NULL) || (id == 0)) { 1524184610Salfred return (USB_ERR_INVAL); 1525184610Salfred } 1526184610Salfred DPRINTFN(5, "len=%d\n", len); 1527184610Salfred 1528184610Salfred req.bmRequestType = UT_READ_CLASS_INTERFACE; 1529184610Salfred req.bRequest = UR_GET_REPORT; 1530184610Salfred USETW2(req.wValue, type, id); 1531184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1532184610Salfred req.wIndex[1] = 0; 1533184610Salfred USETW(req.wLength, len); 1534194228Sthompsa return (usbd_do_request(udev, mtx, &req, data)); 1535184610Salfred} 1536184610Salfred 1537184610Salfred/*------------------------------------------------------------------------* 1538194228Sthompsa * usbd_req_set_idle 1539184610Salfred * 1540184610Salfred * Returns: 1541184610Salfred * 0: Success 1542184610Salfred * Else: Failure 1543184610Salfred *------------------------------------------------------------------------*/ 1544193045Sthompsausb_error_t 1545194228Sthompsausbd_req_set_idle(struct usb_device *udev, struct mtx *mtx, 1546184610Salfred uint8_t iface_index, uint8_t duration, uint8_t id) 1547184610Salfred{ 1548194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1549192984Sthompsa struct usb_device_request req; 1550184610Salfred 1551184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1552184610Salfred return (USB_ERR_INVAL); 1553184610Salfred } 1554184610Salfred DPRINTFN(5, "%d %d\n", duration, id); 1555184610Salfred 1556184610Salfred req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1557184610Salfred req.bRequest = UR_SET_IDLE; 1558184610Salfred USETW2(req.wValue, duration, id); 1559184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1560184610Salfred req.wIndex[1] = 0; 1561184610Salfred USETW(req.wLength, 0); 1562194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1563184610Salfred} 1564184610Salfred 1565184610Salfred/*------------------------------------------------------------------------* 1566194228Sthompsa * usbd_req_get_report_descriptor 1567184610Salfred * 1568184610Salfred * Returns: 1569184610Salfred * 0: Success 1570184610Salfred * Else: Failure 1571184610Salfred *------------------------------------------------------------------------*/ 1572193045Sthompsausb_error_t 1573194228Sthompsausbd_req_get_report_descriptor(struct usb_device *udev, struct mtx *mtx, 1574184610Salfred void *d, uint16_t size, uint8_t iface_index) 1575184610Salfred{ 1576194228Sthompsa struct usb_interface *iface = usbd_get_iface(udev, iface_index); 1577192984Sthompsa struct usb_device_request req; 1578184610Salfred 1579184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 1580184610Salfred return (USB_ERR_INVAL); 1581184610Salfred } 1582184610Salfred req.bmRequestType = UT_READ_INTERFACE; 1583184610Salfred req.bRequest = UR_GET_DESCRIPTOR; 1584184610Salfred USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ 1585184610Salfred req.wIndex[0] = iface->idesc->bInterfaceNumber; 1586184610Salfred req.wIndex[1] = 0; 1587184610Salfred USETW(req.wLength, size); 1588194228Sthompsa return (usbd_do_request(udev, mtx, &req, d)); 1589184610Salfred} 1590184610Salfred 1591184610Salfred/*------------------------------------------------------------------------* 1592194228Sthompsa * usbd_req_set_config 1593184610Salfred * 1594184610Salfred * This function is used to select the current configuration number in 1595184610Salfred * both USB device side mode and USB host side mode. When setting the 1596184610Salfred * configuration the function of the interfaces can change. 1597184610Salfred * 1598184610Salfred * Returns: 1599184610Salfred * 0: Success 1600184610Salfred * Else: Failure 1601184610Salfred *------------------------------------------------------------------------*/ 1602193045Sthompsausb_error_t 1603194228Sthompsausbd_req_set_config(struct usb_device *udev, struct mtx *mtx, uint8_t conf) 1604184610Salfred{ 1605192984Sthompsa struct usb_device_request req; 1606184610Salfred 1607184610Salfred DPRINTF("setting config %d\n", conf); 1608184610Salfred 1609184610Salfred /* do "set configuration" request */ 1610184610Salfred 1611184610Salfred req.bmRequestType = UT_WRITE_DEVICE; 1612184610Salfred req.bRequest = UR_SET_CONFIG; 1613184610Salfred req.wValue[0] = conf; 1614184610Salfred req.wValue[1] = 0; 1615184610Salfred USETW(req.wIndex, 0); 1616184610Salfred USETW(req.wLength, 0); 1617194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1618184610Salfred} 1619184610Salfred 1620184610Salfred/*------------------------------------------------------------------------* 1621194228Sthompsa * usbd_req_get_config 1622184610Salfred * 1623184610Salfred * Returns: 1624184610Salfred * 0: Success 1625184610Salfred * Else: Failure 1626184610Salfred *------------------------------------------------------------------------*/ 1627193045Sthompsausb_error_t 1628194228Sthompsausbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) 1629184610Salfred{ 1630192984Sthompsa struct usb_device_request req; 1631184610Salfred 1632184610Salfred req.bmRequestType = UT_READ_DEVICE; 1633184610Salfred req.bRequest = UR_GET_CONFIG; 1634184610Salfred USETW(req.wValue, 0); 1635184610Salfred USETW(req.wIndex, 0); 1636184610Salfred USETW(req.wLength, 1); 1637194228Sthompsa return (usbd_do_request(udev, mtx, &req, pconf)); 1638184610Salfred} 1639184610Salfred 1640184610Salfred/*------------------------------------------------------------------------* 1641194228Sthompsa * usbd_req_re_enumerate 1642184610Salfred * 1643185087Salfred * NOTE: After this function returns the hardware is in the 1644185087Salfred * unconfigured state! The application is responsible for setting a 1645185087Salfred * new configuration. 1646185087Salfred * 1647184610Salfred * Returns: 1648184610Salfred * 0: Success 1649184610Salfred * Else: Failure 1650184610Salfred *------------------------------------------------------------------------*/ 1651193045Sthompsausb_error_t 1652194228Sthompsausbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx) 1653184610Salfred{ 1654192984Sthompsa struct usb_device *parent_hub; 1655193045Sthompsa usb_error_t err; 1656184610Salfred uint8_t old_addr; 1657186730Salfred uint8_t do_retry = 1; 1658184610Salfred 1659192499Sthompsa if (udev->flags.usb_mode != USB_MODE_HOST) { 1660185290Salfred return (USB_ERR_INVAL); 1661185290Salfred } 1662184610Salfred old_addr = udev->address; 1663184610Salfred parent_hub = udev->parent_hub; 1664184610Salfred if (parent_hub == NULL) { 1665185290Salfred return (USB_ERR_INVAL); 1666184610Salfred } 1667186730Salfredretry: 1668194228Sthompsa err = usbd_req_reset_port(parent_hub, mtx, udev->port_no); 1669184610Salfred if (err) { 1670190739Sthompsa DPRINTFN(0, "addr=%d, port reset failed, %s\n", 1671194228Sthompsa old_addr, usbd_errstr(err)); 1672184610Salfred goto done; 1673184610Salfred } 1674184610Salfred /* 1675184610Salfred * After that the port has been reset our device should be at 1676184610Salfred * address zero: 1677184610Salfred */ 1678184610Salfred udev->address = USB_START_ADDR; 1679184610Salfred 1680185290Salfred /* reset "bMaxPacketSize" */ 1681185290Salfred udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; 1682185290Salfred 1683184610Salfred /* 1684184610Salfred * Restore device address: 1685184610Salfred */ 1686194228Sthompsa err = usbd_req_set_address(udev, mtx, old_addr); 1687184610Salfred if (err) { 1688184610Salfred /* XXX ignore any errors! */ 1689190739Sthompsa DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", 1690194228Sthompsa old_addr, usbd_errstr(err)); 1691184610Salfred } 1692184610Salfred /* restore device address */ 1693184610Salfred udev->address = old_addr; 1694184610Salfred 1695184610Salfred /* allow device time to set new address */ 1696194228Sthompsa usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); 1697184610Salfred 1698184610Salfred /* get the device descriptor */ 1699194228Sthompsa err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, 1700185290Salfred USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); 1701184610Salfred if (err) { 1702185290Salfred DPRINTFN(0, "getting device descriptor " 1703199816Sthompsa "at addr %d failed, %s\n", udev->address, 1704194228Sthompsa usbd_errstr(err)); 1705185290Salfred goto done; 1706185290Salfred } 1707185290Salfred /* get the full device descriptor */ 1708194228Sthompsa err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); 1709185290Salfred if (err) { 1710184610Salfred DPRINTFN(0, "addr=%d, getting device " 1711199816Sthompsa "descriptor failed, %s\n", old_addr, 1712194228Sthompsa usbd_errstr(err)); 1713184610Salfred goto done; 1714184610Salfred } 1715184610Salfreddone: 1716186730Salfred if (err && do_retry) { 1717186730Salfred /* give the USB firmware some time to load */ 1718194228Sthompsa usb_pause_mtx(mtx, hz / 2); 1719186730Salfred /* no more retries after this retry */ 1720186730Salfred do_retry = 0; 1721186730Salfred /* try again */ 1722186730Salfred goto retry; 1723186730Salfred } 1724184610Salfred /* restore address */ 1725184610Salfred udev->address = old_addr; 1726184610Salfred return (err); 1727184610Salfred} 1728186730Salfred 1729186730Salfred/*------------------------------------------------------------------------* 1730194228Sthompsa * usbd_req_clear_device_feature 1731186730Salfred * 1732186730Salfred * Returns: 1733186730Salfred * 0: Success 1734186730Salfred * Else: Failure 1735186730Salfred *------------------------------------------------------------------------*/ 1736193045Sthompsausb_error_t 1737194228Sthompsausbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, 1738186730Salfred uint16_t sel) 1739186730Salfred{ 1740192984Sthompsa struct usb_device_request req; 1741186730Salfred 1742186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 1743186730Salfred req.bRequest = UR_CLEAR_FEATURE; 1744186730Salfred USETW(req.wValue, sel); 1745186730Salfred USETW(req.wIndex, 0); 1746186730Salfred USETW(req.wLength, 0); 1747194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1748186730Salfred} 1749186730Salfred 1750186730Salfred/*------------------------------------------------------------------------* 1751194228Sthompsa * usbd_req_set_device_feature 1752186730Salfred * 1753186730Salfred * Returns: 1754186730Salfred * 0: Success 1755186730Salfred * Else: Failure 1756186730Salfred *------------------------------------------------------------------------*/ 1757193045Sthompsausb_error_t 1758194228Sthompsausbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, 1759186730Salfred uint16_t sel) 1760186730Salfred{ 1761192984Sthompsa struct usb_device_request req; 1762186730Salfred 1763186730Salfred req.bmRequestType = UT_WRITE_DEVICE; 1764186730Salfred req.bRequest = UR_SET_FEATURE; 1765186730Salfred USETW(req.wValue, sel); 1766186730Salfred USETW(req.wIndex, 0); 1767186730Salfred USETW(req.wLength, 0); 1768194228Sthompsa return (usbd_do_request(udev, mtx, &req, 0)); 1769186730Salfred} 1770