1184610Salfred/* $FreeBSD$ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 28246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 29246122Shselasky#else 30194677Sthompsa#include <sys/stdint.h> 31194677Sthompsa#include <sys/stddef.h> 32194677Sthompsa#include <sys/param.h> 33194677Sthompsa#include <sys/queue.h> 34194677Sthompsa#include <sys/types.h> 35194677Sthompsa#include <sys/systm.h> 36194677Sthompsa#include <sys/kernel.h> 37194677Sthompsa#include <sys/bus.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> 51195963Salfred#include <dev/usb/usbdi_util.h> 52194677Sthompsa#include "usb_if.h" 53184610Salfred 54194228Sthompsa#define USB_DEBUG_VAR usb_debug 55184610Salfred 56188942Sthompsa#include <dev/usb/usb_core.h> 57188942Sthompsa#include <dev/usb/usb_process.h> 58188942Sthompsa#include <dev/usb/usb_busdma.h> 59188942Sthompsa#include <dev/usb/usb_transfer.h> 60188942Sthompsa#include <dev/usb/usb_device.h> 61188942Sthompsa#include <dev/usb/usb_debug.h> 62188942Sthompsa#include <dev/usb/usb_dynamic.h> 63188942Sthompsa#include <dev/usb/usb_hub.h> 64184610Salfred 65188942Sthompsa#include <dev/usb/usb_controller.h> 66188942Sthompsa#include <dev/usb/usb_bus.h> 67246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 68184610Salfred 69184610Salfred/* function prototypes */ 70184610Salfred 71194228Sthompsastatic uint8_t usb_handle_get_stall(struct usb_device *, uint8_t); 72194228Sthompsastatic usb_error_t usb_handle_remote_wakeup(struct usb_xfer *, uint8_t); 73194228Sthompsastatic usb_error_t usb_handle_request(struct usb_xfer *); 74194228Sthompsastatic usb_error_t usb_handle_set_config(struct usb_xfer *, uint8_t); 75194228Sthompsastatic usb_error_t usb_handle_set_stall(struct usb_xfer *, uint8_t, 76185948Sthompsa uint8_t); 77194228Sthompsastatic usb_error_t usb_handle_iface_request(struct usb_xfer *, void **, 78192984Sthompsa uint16_t *, struct usb_device_request, uint16_t, 79185948Sthompsa uint8_t); 80184610Salfred 81184610Salfred/*------------------------------------------------------------------------* 82194228Sthompsa * usb_handle_request_callback 83184610Salfred * 84184610Salfred * This function is the USB callback for generic USB Device control 85184610Salfred * transfers. 86184610Salfred *------------------------------------------------------------------------*/ 87184610Salfredvoid 88194677Sthompsausb_handle_request_callback(struct usb_xfer *xfer, usb_error_t error) 89184610Salfred{ 90193045Sthompsa usb_error_t err; 91184610Salfred 92184610Salfred /* check the current transfer state */ 93184610Salfred 94184610Salfred switch (USB_GET_STATE(xfer)) { 95184610Salfred case USB_ST_SETUP: 96184610Salfred case USB_ST_TRANSFERRED: 97184610Salfred 98184610Salfred /* handle the request */ 99194228Sthompsa err = usb_handle_request(xfer); 100184610Salfred 101184610Salfred if (err) { 102184610Salfred 103184610Salfred if (err == USB_ERR_BAD_CONTEXT) { 104184610Salfred /* we need to re-setup the control transfer */ 105194228Sthompsa usb_needs_explore(xfer->xroot->bus, 0); 106184610Salfred break; 107184610Salfred } 108184610Salfred goto tr_restart; 109184610Salfred } 110194228Sthompsa usbd_transfer_submit(xfer); 111184610Salfred break; 112184610Salfred 113184610Salfred default: 114194064Sthompsa /* check if a control transfer is active */ 115194064Sthompsa if (xfer->flags_int.control_rem != 0xFFFF) { 116194064Sthompsa /* handle the request */ 117194228Sthompsa err = usb_handle_request(xfer); 118194064Sthompsa } 119184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 120184610Salfred /* should not happen - try stalling */ 121184610Salfred goto tr_restart; 122184610Salfred } 123184610Salfred break; 124184610Salfred } 125184610Salfred return; 126184610Salfred 127184610Salfredtr_restart: 128194064Sthompsa /* 129194064Sthompsa * If a control transfer is active, stall it, and wait for the 130194064Sthompsa * next control transfer. 131194064Sthompsa */ 132194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, sizeof(struct usb_device_request)); 133184610Salfred xfer->nframes = 1; 134184610Salfred xfer->flags.manual_status = 1; 135184610Salfred xfer->flags.force_short_xfer = 0; 136194677Sthompsa usbd_xfer_set_stall(xfer); /* cancel previous transfer, if any */ 137194228Sthompsa usbd_transfer_submit(xfer); 138184610Salfred} 139184610Salfred 140184610Salfred/*------------------------------------------------------------------------* 141194228Sthompsa * usb_handle_set_config 142184610Salfred * 143184610Salfred * Returns: 144184610Salfred * 0: Success 145184610Salfred * Else: Failure 146184610Salfred *------------------------------------------------------------------------*/ 147193045Sthompsastatic usb_error_t 148194228Sthompsausb_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no) 149184610Salfred{ 150192984Sthompsa struct usb_device *udev = xfer->xroot->udev; 151193045Sthompsa usb_error_t err = 0; 152246759Shselasky uint8_t do_unlock; 153184610Salfred 154184610Salfred /* 155184610Salfred * We need to protect against other threads doing probe and 156184610Salfred * attach: 157184610Salfred */ 158184824Sthompsa USB_XFER_UNLOCK(xfer); 159184610Salfred 160246759Shselasky /* Prevent re-enumeration */ 161246759Shselasky do_unlock = usbd_enum_lock(udev); 162196498Salfred 163184610Salfred if (conf_no == USB_UNCONFIG_NO) { 164184610Salfred conf_no = USB_UNCONFIG_INDEX; 165184610Salfred } else { 166184610Salfred /* 167184610Salfred * The relationship between config number and config index 168184610Salfred * is very simple in our case: 169184610Salfred */ 170184610Salfred conf_no--; 171184610Salfred } 172184610Salfred 173194228Sthompsa if (usbd_set_config_index(udev, conf_no)) { 174184610Salfred DPRINTF("set config %d failed\n", conf_no); 175184610Salfred err = USB_ERR_STALLED; 176184610Salfred goto done; 177184610Salfred } 178194228Sthompsa if (usb_probe_and_attach(udev, USB_IFACE_INDEX_ANY)) { 179184610Salfred DPRINTF("probe and attach failed\n"); 180184610Salfred err = USB_ERR_STALLED; 181184610Salfred goto done; 182184610Salfred } 183184610Salfreddone: 184246759Shselasky if (do_unlock) 185246759Shselasky usbd_enum_unlock(udev); 186184824Sthompsa USB_XFER_LOCK(xfer); 187184610Salfred return (err); 188184610Salfred} 189184610Salfred 190195963Salfredstatic usb_error_t 191195963Salfredusb_check_alt_setting(struct usb_device *udev, 192195963Salfred struct usb_interface *iface, uint8_t alt_index) 193195963Salfred{ 194195963Salfred uint8_t do_unlock; 195195963Salfred usb_error_t err = 0; 196195963Salfred 197246616Shselasky /* Prevent re-enumeration */ 198246616Shselasky do_unlock = usbd_enum_lock(udev); 199195963Salfred 200195963Salfred if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc)) 201195963Salfred err = USB_ERR_INVAL; 202195963Salfred 203196498Salfred if (do_unlock) 204196498Salfred usbd_enum_unlock(udev); 205196498Salfred 206195963Salfred return (err); 207195963Salfred} 208195963Salfred 209184610Salfred/*------------------------------------------------------------------------* 210194228Sthompsa * usb_handle_iface_request 211184610Salfred * 212184610Salfred * Returns: 213184610Salfred * 0: Success 214184610Salfred * Else: Failure 215184610Salfred *------------------------------------------------------------------------*/ 216193045Sthompsastatic usb_error_t 217194228Sthompsausb_handle_iface_request(struct usb_xfer *xfer, 218184610Salfred void **ppdata, uint16_t *plen, 219192984Sthompsa struct usb_device_request req, uint16_t off, uint8_t state) 220184610Salfred{ 221192984Sthompsa struct usb_interface *iface; 222192984Sthompsa struct usb_interface *iface_parent; /* parent interface */ 223192984Sthompsa struct usb_device *udev = xfer->xroot->udev; 224184610Salfred int error; 225184610Salfred uint8_t iface_index; 226195121Sthompsa uint8_t temp_state; 227246759Shselasky uint8_t do_unlock; 228184610Salfred 229184610Salfred if ((req.bmRequestType & 0x1F) == UT_INTERFACE) { 230184610Salfred iface_index = req.wIndex[0]; /* unicast */ 231184610Salfred } else { 232184610Salfred iface_index = 0; /* broadcast */ 233184610Salfred } 234184610Salfred 235184610Salfred /* 236184610Salfred * We need to protect against other threads doing probe and 237184610Salfred * attach: 238184610Salfred */ 239184824Sthompsa USB_XFER_UNLOCK(xfer); 240184610Salfred 241246759Shselasky /* Prevent re-enumeration */ 242246759Shselasky do_unlock = usbd_enum_lock(udev); 243196498Salfred 244184610Salfred error = ENXIO; 245184610Salfred 246184610Salfredtr_repeat: 247194228Sthompsa iface = usbd_get_iface(udev, iface_index); 248184610Salfred if ((iface == NULL) || 249184610Salfred (iface->idesc == NULL)) { 250184610Salfred /* end of interfaces non-existing interface */ 251184610Salfred goto tr_stalled; 252184610Salfred } 253195121Sthompsa /* set initial state */ 254195121Sthompsa 255195121Sthompsa temp_state = state; 256195121Sthompsa 257184610Salfred /* forward request to interface, if any */ 258184610Salfred 259184610Salfred if ((error != 0) && 260184610Salfred (error != ENOTTY) && 261184610Salfred (iface->subdev != NULL) && 262184610Salfred device_is_attached(iface->subdev)) { 263184610Salfred#if 0 264190186Sthompsa DEVMETHOD(usb_handle_request, NULL); /* dummy */ 265184610Salfred#endif 266188942Sthompsa error = USB_HANDLE_REQUEST(iface->subdev, 267184610Salfred &req, ppdata, plen, 268195121Sthompsa off, &temp_state); 269184610Salfred } 270194228Sthompsa iface_parent = usbd_get_iface(udev, iface->parent_iface_index); 271184610Salfred 272184610Salfred if ((iface_parent == NULL) || 273184610Salfred (iface_parent->idesc == NULL)) { 274184610Salfred /* non-existing interface */ 275184610Salfred iface_parent = NULL; 276184610Salfred } 277184610Salfred /* forward request to parent interface, if any */ 278184610Salfred 279184610Salfred if ((error != 0) && 280184610Salfred (error != ENOTTY) && 281184610Salfred (iface_parent != NULL) && 282184610Salfred (iface_parent->subdev != NULL) && 283184610Salfred ((req.bmRequestType & 0x1F) == UT_INTERFACE) && 284184610Salfred (iface_parent->subdev != iface->subdev) && 285184610Salfred device_is_attached(iface_parent->subdev)) { 286188942Sthompsa error = USB_HANDLE_REQUEST(iface_parent->subdev, 287195121Sthompsa &req, ppdata, plen, off, &temp_state); 288184610Salfred } 289184610Salfred if (error == 0) { 290184610Salfred /* negativly adjust pointer and length */ 291184610Salfred *ppdata = ((uint8_t *)(*ppdata)) - off; 292184610Salfred *plen += off; 293195121Sthompsa 294195121Sthompsa if ((state == USB_HR_NOT_COMPLETE) && 295195121Sthompsa (temp_state == USB_HR_COMPLETE_OK)) 296195121Sthompsa goto tr_short; 297195121Sthompsa else 298195121Sthompsa goto tr_valid; 299184610Salfred } else if (error == ENOTTY) { 300184610Salfred goto tr_stalled; 301184610Salfred } 302184610Salfred if ((req.bmRequestType & 0x1F) != UT_INTERFACE) { 303184610Salfred iface_index++; /* iterate */ 304184610Salfred goto tr_repeat; 305184610Salfred } 306194064Sthompsa if (state != USB_HR_NOT_COMPLETE) { 307184610Salfred /* we are complete */ 308184610Salfred goto tr_valid; 309184610Salfred } 310184610Salfred switch (req.bmRequestType) { 311184610Salfred case UT_WRITE_INTERFACE: 312184610Salfred switch (req.bRequest) { 313184610Salfred case UR_SET_INTERFACE: 314184610Salfred /* 315195963Salfred * We assume that the endpoints are the same 316195963Salfred * accross the alternate settings. 317195963Salfred * 318195963Salfred * Reset the endpoints, because re-attaching 319195963Salfred * only a part of the device is not possible. 320184610Salfred */ 321195963Salfred error = usb_check_alt_setting(udev, 322195963Salfred iface, req.wValue[0]); 323184610Salfred if (error) { 324195963Salfred DPRINTF("alt setting does not exist %s\n", 325194228Sthompsa usbd_errstr(error)); 326184610Salfred goto tr_stalled; 327184610Salfred } 328195963Salfred error = usb_reset_iface_endpoints(udev, iface_index); 329184610Salfred if (error) { 330195963Salfred DPRINTF("alt setting failed %s\n", 331195963Salfred usbd_errstr(error)); 332184610Salfred goto tr_stalled; 333184610Salfred } 334195963Salfred /* update the current alternate setting */ 335195963Salfred iface->alt_index = req.wValue[0]; 336184610Salfred break; 337195963Salfred 338184610Salfred default: 339184610Salfred goto tr_stalled; 340184610Salfred } 341184610Salfred break; 342184610Salfred 343184610Salfred case UT_READ_INTERFACE: 344184610Salfred switch (req.bRequest) { 345184610Salfred case UR_GET_INTERFACE: 346184610Salfred *ppdata = &iface->alt_index; 347184610Salfred *plen = 1; 348184610Salfred break; 349184610Salfred 350184610Salfred default: 351184610Salfred goto tr_stalled; 352184610Salfred } 353184610Salfred break; 354184610Salfred default: 355184610Salfred goto tr_stalled; 356184610Salfred } 357184610Salfredtr_valid: 358246759Shselasky if (do_unlock) 359246759Shselasky usbd_enum_unlock(udev); 360184824Sthompsa USB_XFER_LOCK(xfer); 361184610Salfred return (0); 362184610Salfred 363195121Sthompsatr_short: 364246759Shselasky if (do_unlock) 365246759Shselasky usbd_enum_unlock(udev); 366195121Sthompsa USB_XFER_LOCK(xfer); 367195121Sthompsa return (USB_ERR_SHORT_XFER); 368195121Sthompsa 369184610Salfredtr_stalled: 370246759Shselasky if (do_unlock) 371246759Shselasky usbd_enum_unlock(udev); 372184824Sthompsa USB_XFER_LOCK(xfer); 373184610Salfred return (USB_ERR_STALLED); 374184610Salfred} 375184610Salfred 376184610Salfred/*------------------------------------------------------------------------* 377194228Sthompsa * usb_handle_stall 378184610Salfred * 379184610Salfred * Returns: 380184610Salfred * 0: Success 381184610Salfred * Else: Failure 382184610Salfred *------------------------------------------------------------------------*/ 383193045Sthompsastatic usb_error_t 384194228Sthompsausb_handle_set_stall(struct usb_xfer *xfer, uint8_t ep, uint8_t do_stall) 385184610Salfred{ 386192984Sthompsa struct usb_device *udev = xfer->xroot->udev; 387193045Sthompsa usb_error_t err; 388184610Salfred 389184824Sthompsa USB_XFER_UNLOCK(xfer); 390194228Sthompsa err = usbd_set_endpoint_stall(udev, 391194228Sthompsa usbd_get_ep_by_addr(udev, ep), do_stall); 392184824Sthompsa USB_XFER_LOCK(xfer); 393184610Salfred return (err); 394184610Salfred} 395184610Salfred 396184610Salfred/*------------------------------------------------------------------------* 397194228Sthompsa * usb_handle_get_stall 398184610Salfred * 399184610Salfred * Returns: 400184610Salfred * 0: Success 401184610Salfred * Else: Failure 402184610Salfred *------------------------------------------------------------------------*/ 403184610Salfredstatic uint8_t 404194228Sthompsausb_handle_get_stall(struct usb_device *udev, uint8_t ea_val) 405184610Salfred{ 406193644Sthompsa struct usb_endpoint *ep; 407184610Salfred uint8_t halted; 408184610Salfred 409194228Sthompsa ep = usbd_get_ep_by_addr(udev, ea_val); 410193644Sthompsa if (ep == NULL) { 411184610Salfred /* nothing to do */ 412184610Salfred return (0); 413184610Salfred } 414184824Sthompsa USB_BUS_LOCK(udev->bus); 415193644Sthompsa halted = ep->is_stalled; 416184824Sthompsa USB_BUS_UNLOCK(udev->bus); 417184610Salfred 418184610Salfred return (halted); 419184610Salfred} 420184610Salfred 421184610Salfred/*------------------------------------------------------------------------* 422194228Sthompsa * usb_handle_remote_wakeup 423184610Salfred * 424184610Salfred * Returns: 425184610Salfred * 0: Success 426184610Salfred * Else: Failure 427184610Salfred *------------------------------------------------------------------------*/ 428193045Sthompsastatic usb_error_t 429194228Sthompsausb_handle_remote_wakeup(struct usb_xfer *xfer, uint8_t is_on) 430184610Salfred{ 431192984Sthompsa struct usb_device *udev; 432192984Sthompsa struct usb_bus *bus; 433184610Salfred 434187173Sthompsa udev = xfer->xroot->udev; 435184610Salfred bus = udev->bus; 436184610Salfred 437184824Sthompsa USB_BUS_LOCK(bus); 438184610Salfred 439184610Salfred if (is_on) { 440184610Salfred udev->flags.remote_wakeup = 1; 441184610Salfred } else { 442184610Salfred udev->flags.remote_wakeup = 0; 443184610Salfred } 444184610Salfred 445184824Sthompsa USB_BUS_UNLOCK(bus); 446184610Salfred 447213434Shselasky#if USB_HAVE_POWERD 448186730Salfred /* In case we are out of sync, update the power state. */ 449194228Sthompsa usb_bus_power_update(udev->bus); 450213434Shselasky#endif 451184610Salfred return (0); /* success */ 452184610Salfred} 453184610Salfred 454184610Salfred/*------------------------------------------------------------------------* 455194228Sthompsa * usb_handle_request 456184610Salfred * 457184610Salfred * Internal state sequence: 458184610Salfred * 459194064Sthompsa * USB_HR_NOT_COMPLETE -> USB_HR_COMPLETE_OK v USB_HR_COMPLETE_ERR 460184610Salfred * 461184610Salfred * Returns: 462184610Salfred * 0: Ready to start hardware 463184610Salfred * Else: Stall current transfer, if any 464184610Salfred *------------------------------------------------------------------------*/ 465193045Sthompsastatic usb_error_t 466194228Sthompsausb_handle_request(struct usb_xfer *xfer) 467184610Salfred{ 468192984Sthompsa struct usb_device_request req; 469192984Sthompsa struct usb_device *udev; 470184610Salfred const void *src_zcopy; /* zero-copy source pointer */ 471184610Salfred const void *src_mcopy; /* non zero-copy source pointer */ 472184610Salfred uint16_t off; /* data offset */ 473184610Salfred uint16_t rem; /* data remainder */ 474184610Salfred uint16_t max_len; /* max fragment length */ 475184610Salfred uint16_t wValue; 476184610Salfred uint8_t state; 477195121Sthompsa uint8_t is_complete = 1; 478193045Sthompsa usb_error_t err; 479184610Salfred union { 480184610Salfred uWord wStatus; 481184610Salfred uint8_t buf[2]; 482184610Salfred } temp; 483184610Salfred 484184610Salfred /* 485184610Salfred * Filter the USB transfer state into 486184610Salfred * something which we understand: 487184610Salfred */ 488184610Salfred 489184610Salfred switch (USB_GET_STATE(xfer)) { 490184610Salfred case USB_ST_SETUP: 491194064Sthompsa state = USB_HR_NOT_COMPLETE; 492184610Salfred 493184610Salfred if (!xfer->flags_int.control_act) { 494184610Salfred /* nothing to do */ 495184610Salfred goto tr_stalled; 496184610Salfred } 497184610Salfred break; 498194064Sthompsa case USB_ST_TRANSFERRED: 499184610Salfred if (!xfer->flags_int.control_act) { 500194064Sthompsa state = USB_HR_COMPLETE_OK; 501184610Salfred } else { 502194064Sthompsa state = USB_HR_NOT_COMPLETE; 503184610Salfred } 504184610Salfred break; 505194064Sthompsa default: 506194064Sthompsa state = USB_HR_COMPLETE_ERR; 507194064Sthompsa break; 508184610Salfred } 509184610Salfred 510184610Salfred /* reset frame stuff */ 511184610Salfred 512194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, 0); 513184610Salfred 514194677Sthompsa usbd_xfer_set_frame_offset(xfer, 0, 0); 515194677Sthompsa usbd_xfer_set_frame_offset(xfer, sizeof(req), 1); 516184610Salfred 517184610Salfred /* get the current request, if any */ 518184610Salfred 519194228Sthompsa usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req)); 520184610Salfred 521184610Salfred if (xfer->flags_int.control_rem == 0xFFFF) { 522184610Salfred /* first time - not initialised */ 523184610Salfred rem = UGETW(req.wLength); 524184610Salfred off = 0; 525184610Salfred } else { 526184610Salfred /* not first time - initialised */ 527184610Salfred rem = xfer->flags_int.control_rem; 528184610Salfred off = UGETW(req.wLength) - rem; 529184610Salfred } 530184610Salfred 531184610Salfred /* set some defaults */ 532184610Salfred 533184610Salfred max_len = 0; 534184610Salfred src_zcopy = NULL; 535184610Salfred src_mcopy = NULL; 536187173Sthompsa udev = xfer->xroot->udev; 537184610Salfred 538184610Salfred /* get some request fields decoded */ 539184610Salfred 540184610Salfred wValue = UGETW(req.wValue); 541184610Salfred 542184610Salfred DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x " 543184610Salfred "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType, 544233774Shselasky req.bRequest, wValue, UGETW(req.wIndex), off, rem, state); 545184610Salfred 546184610Salfred /* demultiplex the control request */ 547184610Salfred 548184610Salfred switch (req.bmRequestType) { 549184610Salfred case UT_READ_DEVICE: 550194064Sthompsa if (state != USB_HR_NOT_COMPLETE) { 551184610Salfred break; 552184610Salfred } 553184610Salfred switch (req.bRequest) { 554184610Salfred case UR_GET_DESCRIPTOR: 555184610Salfred goto tr_handle_get_descriptor; 556184610Salfred case UR_GET_CONFIG: 557184610Salfred goto tr_handle_get_config; 558184610Salfred case UR_GET_STATUS: 559184610Salfred goto tr_handle_get_status; 560184610Salfred default: 561184610Salfred goto tr_stalled; 562184610Salfred } 563184610Salfred break; 564184610Salfred 565184610Salfred case UT_WRITE_DEVICE: 566184610Salfred switch (req.bRequest) { 567184610Salfred case UR_SET_ADDRESS: 568184610Salfred goto tr_handle_set_address; 569184610Salfred case UR_SET_CONFIG: 570184610Salfred goto tr_handle_set_config; 571184610Salfred case UR_CLEAR_FEATURE: 572184610Salfred switch (wValue) { 573184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 574184610Salfred goto tr_handle_clear_wakeup; 575184610Salfred default: 576184610Salfred goto tr_stalled; 577184610Salfred } 578184610Salfred break; 579184610Salfred case UR_SET_FEATURE: 580184610Salfred switch (wValue) { 581184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 582184610Salfred goto tr_handle_set_wakeup; 583184610Salfred default: 584184610Salfred goto tr_stalled; 585184610Salfred } 586184610Salfred break; 587184610Salfred default: 588184610Salfred goto tr_stalled; 589184610Salfred } 590184610Salfred break; 591184610Salfred 592184610Salfred case UT_WRITE_ENDPOINT: 593184610Salfred switch (req.bRequest) { 594184610Salfred case UR_CLEAR_FEATURE: 595184610Salfred switch (wValue) { 596184610Salfred case UF_ENDPOINT_HALT: 597184610Salfred goto tr_handle_clear_halt; 598184610Salfred default: 599184610Salfred goto tr_stalled; 600184610Salfred } 601184610Salfred break; 602184610Salfred case UR_SET_FEATURE: 603184610Salfred switch (wValue) { 604184610Salfred case UF_ENDPOINT_HALT: 605184610Salfred goto tr_handle_set_halt; 606184610Salfred default: 607184610Salfred goto tr_stalled; 608184610Salfred } 609184610Salfred break; 610184610Salfred default: 611184610Salfred goto tr_stalled; 612184610Salfred } 613184610Salfred break; 614184610Salfred 615184610Salfred case UT_READ_ENDPOINT: 616184610Salfred switch (req.bRequest) { 617184610Salfred case UR_GET_STATUS: 618184610Salfred goto tr_handle_get_ep_status; 619184610Salfred default: 620184610Salfred goto tr_stalled; 621184610Salfred } 622184610Salfred break; 623184610Salfred default: 624184610Salfred /* we use "USB_ADD_BYTES" to de-const the src_zcopy */ 625194228Sthompsa err = usb_handle_iface_request(xfer, 626184610Salfred USB_ADD_BYTES(&src_zcopy, 0), 627184610Salfred &max_len, req, off, state); 628184610Salfred if (err == 0) { 629195121Sthompsa is_complete = 0; 630184610Salfred goto tr_valid; 631195121Sthompsa } else if (err == USB_ERR_SHORT_XFER) { 632195121Sthompsa goto tr_valid; 633184610Salfred } 634184610Salfred /* 635184610Salfred * Reset zero-copy pointer and max length 636184610Salfred * variable in case they were unintentionally 637184610Salfred * set: 638184610Salfred */ 639184610Salfred src_zcopy = NULL; 640184610Salfred max_len = 0; 641184610Salfred 642184610Salfred /* 643184610Salfred * Check if we have a vendor specific 644184610Salfred * descriptor: 645184610Salfred */ 646184610Salfred goto tr_handle_get_descriptor; 647184610Salfred } 648184610Salfred goto tr_valid; 649184610Salfred 650184610Salfredtr_handle_get_descriptor: 651194228Sthompsa err = (usb_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len); 652191402Sthompsa if (err) 653184610Salfred goto tr_stalled; 654191402Sthompsa if (src_zcopy == NULL) 655191402Sthompsa goto tr_stalled; 656184610Salfred goto tr_valid; 657184610Salfred 658184610Salfredtr_handle_get_config: 659184610Salfred temp.buf[0] = udev->curr_config_no; 660184610Salfred src_mcopy = temp.buf; 661184610Salfred max_len = 1; 662184610Salfred goto tr_valid; 663184610Salfred 664184610Salfredtr_handle_get_status: 665184610Salfred 666184610Salfred wValue = 0; 667184610Salfred 668184824Sthompsa USB_BUS_LOCK(udev->bus); 669184610Salfred if (udev->flags.remote_wakeup) { 670184610Salfred wValue |= UDS_REMOTE_WAKEUP; 671184610Salfred } 672184610Salfred if (udev->flags.self_powered) { 673184610Salfred wValue |= UDS_SELF_POWERED; 674184610Salfred } 675184824Sthompsa USB_BUS_UNLOCK(udev->bus); 676184610Salfred 677184610Salfred USETW(temp.wStatus, wValue); 678184610Salfred src_mcopy = temp.wStatus; 679184610Salfred max_len = sizeof(temp.wStatus); 680184610Salfred goto tr_valid; 681184610Salfred 682184610Salfredtr_handle_set_address: 683194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 684184610Salfred if (wValue >= 0x80) { 685184610Salfred /* invalid value */ 686184610Salfred goto tr_stalled; 687184610Salfred } else if (udev->curr_config_no != 0) { 688184610Salfred /* we are configured ! */ 689184610Salfred goto tr_stalled; 690184610Salfred } 691194064Sthompsa } else if (state != USB_HR_NOT_COMPLETE) { 692184610Salfred udev->address = (wValue & 0x7F); 693184610Salfred goto tr_bad_context; 694184610Salfred } 695184610Salfred goto tr_valid; 696184610Salfred 697184610Salfredtr_handle_set_config: 698194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 699194228Sthompsa if (usb_handle_set_config(xfer, req.wValue[0])) { 700184610Salfred goto tr_stalled; 701184610Salfred } 702184610Salfred } 703184610Salfred goto tr_valid; 704184610Salfred 705184610Salfredtr_handle_clear_halt: 706194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 707194228Sthompsa if (usb_handle_set_stall(xfer, req.wIndex[0], 0)) { 708184610Salfred goto tr_stalled; 709184610Salfred } 710184610Salfred } 711184610Salfred goto tr_valid; 712184610Salfred 713184610Salfredtr_handle_clear_wakeup: 714194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 715194228Sthompsa if (usb_handle_remote_wakeup(xfer, 0)) { 716184610Salfred goto tr_stalled; 717184610Salfred } 718184610Salfred } 719184610Salfred goto tr_valid; 720184610Salfred 721184610Salfredtr_handle_set_halt: 722194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 723194228Sthompsa if (usb_handle_set_stall(xfer, req.wIndex[0], 1)) { 724184610Salfred goto tr_stalled; 725184610Salfred } 726184610Salfred } 727184610Salfred goto tr_valid; 728184610Salfred 729184610Salfredtr_handle_set_wakeup: 730194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 731194228Sthompsa if (usb_handle_remote_wakeup(xfer, 1)) { 732184610Salfred goto tr_stalled; 733184610Salfred } 734184610Salfred } 735184610Salfred goto tr_valid; 736184610Salfred 737184610Salfredtr_handle_get_ep_status: 738194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 739184610Salfred temp.wStatus[0] = 740194228Sthompsa usb_handle_get_stall(udev, req.wIndex[0]); 741184610Salfred temp.wStatus[1] = 0; 742184610Salfred src_mcopy = temp.wStatus; 743184610Salfred max_len = sizeof(temp.wStatus); 744184610Salfred } 745184610Salfred goto tr_valid; 746184610Salfred 747184610Salfredtr_valid: 748194064Sthompsa if (state != USB_HR_NOT_COMPLETE) { 749184610Salfred goto tr_stalled; 750184610Salfred } 751184610Salfred /* subtract offset from length */ 752184610Salfred 753184610Salfred max_len -= off; 754184610Salfred 755184610Salfred /* Compute the real maximum data length */ 756184610Salfred 757184610Salfred if (max_len > xfer->max_data_length) { 758194677Sthompsa max_len = usbd_xfer_max_len(xfer); 759184610Salfred } 760184610Salfred if (max_len > rem) { 761184610Salfred max_len = rem; 762184610Salfred } 763184610Salfred /* 764184610Salfred * If the remainder is greater than the maximum data length, 765184610Salfred * we need to truncate the value for the sake of the 766184610Salfred * comparison below: 767184610Salfred */ 768184610Salfred if (rem > xfer->max_data_length) { 769194677Sthompsa rem = usbd_xfer_max_len(xfer); 770184610Salfred } 771195121Sthompsa if ((rem != max_len) && (is_complete != 0)) { 772184610Salfred /* 773184610Salfred * If we don't transfer the data we can transfer, then 774184610Salfred * the transfer is short ! 775184610Salfred */ 776184610Salfred xfer->flags.force_short_xfer = 1; 777184610Salfred xfer->nframes = 2; 778184610Salfred } else { 779184610Salfred /* 780184610Salfred * Default case 781184610Salfred */ 782184610Salfred xfer->flags.force_short_xfer = 0; 783184610Salfred xfer->nframes = max_len ? 2 : 1; 784184610Salfred } 785184610Salfred if (max_len > 0) { 786184610Salfred if (src_mcopy) { 787184610Salfred src_mcopy = USB_ADD_BYTES(src_mcopy, off); 788194228Sthompsa usbd_copy_in(xfer->frbuffers + 1, 0, 789184610Salfred src_mcopy, max_len); 790194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, max_len); 791184610Salfred } else { 792194677Sthompsa usbd_xfer_set_frame_data(xfer, 1, 793194677Sthompsa USB_ADD_BYTES(src_zcopy, off), max_len); 794184610Salfred } 795184610Salfred } else { 796184610Salfred /* the end is reached, send status */ 797184610Salfred xfer->flags.manual_status = 0; 798194677Sthompsa usbd_xfer_set_frame_len(xfer, 1, 0); 799184610Salfred } 800184610Salfred DPRINTF("success\n"); 801184610Salfred return (0); /* success */ 802184610Salfred 803184610Salfredtr_stalled: 804194064Sthompsa DPRINTF("%s\n", (state != USB_HR_NOT_COMPLETE) ? 805184610Salfred "complete" : "stalled"); 806184610Salfred return (USB_ERR_STALLED); 807184610Salfred 808184610Salfredtr_bad_context: 809184610Salfred DPRINTF("bad context\n"); 810184610Salfred return (USB_ERR_BAD_CONTEXT); 811184610Salfred} 812