usb_handle_request.c revision 194064
1184610Salfred/* $FreeBSD: head/sys/dev/usb/usb_handle_request.c 194064 2009-06-12 15:58:55Z thompsa $ */ 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 27188942Sthompsa#include <dev/usb/usb_mfunc.h> 28188942Sthompsa#include <dev/usb/usb_error.h> 29188942Sthompsa#include <dev/usb/usb.h> 30184610Salfred 31184610Salfred#define USB_DEBUG_VAR usb2_debug 32184610Salfred 33188942Sthompsa#include <dev/usb/usb_core.h> 34188942Sthompsa#include <dev/usb/usb_process.h> 35188942Sthompsa#include <dev/usb/usb_busdma.h> 36188942Sthompsa#include <dev/usb/usb_transfer.h> 37188942Sthompsa#include <dev/usb/usb_device.h> 38188942Sthompsa#include <dev/usb/usb_debug.h> 39188942Sthompsa#include <dev/usb/usb_dynamic.h> 40188942Sthompsa#include <dev/usb/usb_hub.h> 41184610Salfred 42188942Sthompsa#include <dev/usb/usb_controller.h> 43188942Sthompsa#include <dev/usb/usb_bus.h> 44184610Salfred 45184610Salfred/* function prototypes */ 46184610Salfred 47192984Sthompsastatic uint8_t usb2_handle_get_stall(struct usb_device *, uint8_t); 48193045Sthompsastatic usb_error_t usb2_handle_remote_wakeup(struct usb_xfer *, uint8_t); 49193045Sthompsastatic usb_error_t usb2_handle_request(struct usb_xfer *); 50193045Sthompsastatic usb_error_t usb2_handle_set_config(struct usb_xfer *, uint8_t); 51193045Sthompsastatic usb_error_t usb2_handle_set_stall(struct usb_xfer *, uint8_t, 52185948Sthompsa uint8_t); 53193045Sthompsastatic usb_error_t usb2_handle_iface_request(struct usb_xfer *, void **, 54192984Sthompsa uint16_t *, struct usb_device_request, uint16_t, 55185948Sthompsa uint8_t); 56184610Salfred 57184610Salfred/*------------------------------------------------------------------------* 58184610Salfred * usb2_handle_request_callback 59184610Salfred * 60184610Salfred * This function is the USB callback for generic USB Device control 61184610Salfred * transfers. 62184610Salfred *------------------------------------------------------------------------*/ 63184610Salfredvoid 64192984Sthompsausb2_handle_request_callback(struct usb_xfer *xfer) 65184610Salfred{ 66193045Sthompsa usb_error_t err; 67184610Salfred 68184610Salfred /* check the current transfer state */ 69184610Salfred 70184610Salfred switch (USB_GET_STATE(xfer)) { 71184610Salfred case USB_ST_SETUP: 72184610Salfred case USB_ST_TRANSFERRED: 73184610Salfred 74184610Salfred /* handle the request */ 75184610Salfred err = usb2_handle_request(xfer); 76184610Salfred 77184610Salfred if (err) { 78184610Salfred 79184610Salfred if (err == USB_ERR_BAD_CONTEXT) { 80184610Salfred /* we need to re-setup the control transfer */ 81187173Sthompsa usb2_needs_explore(xfer->xroot->bus, 0); 82184610Salfred break; 83184610Salfred } 84184610Salfred goto tr_restart; 85184610Salfred } 86184610Salfred usb2_start_hardware(xfer); 87184610Salfred break; 88184610Salfred 89184610Salfred default: 90194064Sthompsa /* check if a control transfer is active */ 91194064Sthompsa if (xfer->flags_int.control_rem != 0xFFFF) { 92194064Sthompsa /* handle the request */ 93194064Sthompsa err = usb2_handle_request(xfer); 94194064Sthompsa } 95184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 96184610Salfred /* should not happen - try stalling */ 97184610Salfred goto tr_restart; 98184610Salfred } 99184610Salfred break; 100184610Salfred } 101184610Salfred return; 102184610Salfred 103184610Salfredtr_restart: 104194064Sthompsa /* 105194064Sthompsa * If a control transfer is active, stall it, and wait for the 106194064Sthompsa * next control transfer. 107194064Sthompsa */ 108192984Sthompsa xfer->frlengths[0] = sizeof(struct usb_device_request); 109184610Salfred xfer->nframes = 1; 110184610Salfred xfer->flags.manual_status = 1; 111184610Salfred xfer->flags.force_short_xfer = 0; 112184610Salfred xfer->flags.stall_pipe = 1; /* cancel previous transfer, if any */ 113184610Salfred usb2_start_hardware(xfer); 114184610Salfred} 115184610Salfred 116184610Salfred/*------------------------------------------------------------------------* 117184610Salfred * usb2_handle_set_config 118184610Salfred * 119184610Salfred * Returns: 120184610Salfred * 0: Success 121184610Salfred * Else: Failure 122184610Salfred *------------------------------------------------------------------------*/ 123193045Sthompsastatic usb_error_t 124192984Sthompsausb2_handle_set_config(struct usb_xfer *xfer, uint8_t conf_no) 125184610Salfred{ 126192984Sthompsa struct usb_device *udev = xfer->xroot->udev; 127193045Sthompsa usb_error_t err = 0; 128184610Salfred 129184610Salfred /* 130184610Salfred * We need to protect against other threads doing probe and 131184610Salfred * attach: 132184610Salfred */ 133184824Sthompsa USB_XFER_UNLOCK(xfer); 134184610Salfred mtx_lock(&Giant); /* XXX */ 135187173Sthompsa sx_xlock(udev->default_sx + 1); 136184610Salfred 137184610Salfred if (conf_no == USB_UNCONFIG_NO) { 138184610Salfred conf_no = USB_UNCONFIG_INDEX; 139184610Salfred } else { 140184610Salfred /* 141184610Salfred * The relationship between config number and config index 142184610Salfred * is very simple in our case: 143184610Salfred */ 144184610Salfred conf_no--; 145184610Salfred } 146184610Salfred 147187173Sthompsa if (usb2_set_config_index(udev, conf_no)) { 148184610Salfred DPRINTF("set config %d failed\n", conf_no); 149184610Salfred err = USB_ERR_STALLED; 150184610Salfred goto done; 151184610Salfred } 152187173Sthompsa if (usb2_probe_and_attach(udev, USB_IFACE_INDEX_ANY)) { 153184610Salfred DPRINTF("probe and attach failed\n"); 154184610Salfred err = USB_ERR_STALLED; 155184610Salfred goto done; 156184610Salfred } 157184610Salfreddone: 158184610Salfred mtx_unlock(&Giant); /* XXX */ 159187173Sthompsa sx_unlock(udev->default_sx + 1); 160184824Sthompsa USB_XFER_LOCK(xfer); 161184610Salfred return (err); 162184610Salfred} 163184610Salfred 164184610Salfred/*------------------------------------------------------------------------* 165184610Salfred * usb2_handle_iface_request 166184610Salfred * 167184610Salfred * Returns: 168184610Salfred * 0: Success 169184610Salfred * Else: Failure 170184610Salfred *------------------------------------------------------------------------*/ 171193045Sthompsastatic usb_error_t 172192984Sthompsausb2_handle_iface_request(struct usb_xfer *xfer, 173184610Salfred void **ppdata, uint16_t *plen, 174192984Sthompsa struct usb_device_request req, uint16_t off, uint8_t state) 175184610Salfred{ 176192984Sthompsa struct usb_interface *iface; 177192984Sthompsa struct usb_interface *iface_parent; /* parent interface */ 178192984Sthompsa struct usb_device *udev = xfer->xroot->udev; 179184610Salfred int error; 180184610Salfred uint8_t iface_index; 181184610Salfred 182184610Salfred if ((req.bmRequestType & 0x1F) == UT_INTERFACE) { 183184610Salfred iface_index = req.wIndex[0]; /* unicast */ 184184610Salfred } else { 185184610Salfred iface_index = 0; /* broadcast */ 186184610Salfred } 187184610Salfred 188184610Salfred /* 189184610Salfred * We need to protect against other threads doing probe and 190184610Salfred * attach: 191184610Salfred */ 192184824Sthompsa USB_XFER_UNLOCK(xfer); 193184610Salfred mtx_lock(&Giant); /* XXX */ 194184610Salfred sx_xlock(udev->default_sx + 1); 195184610Salfred 196184610Salfred error = ENXIO; 197184610Salfred 198184610Salfredtr_repeat: 199184610Salfred iface = usb2_get_iface(udev, iface_index); 200184610Salfred if ((iface == NULL) || 201184610Salfred (iface->idesc == NULL)) { 202184610Salfred /* end of interfaces non-existing interface */ 203184610Salfred goto tr_stalled; 204184610Salfred } 205184610Salfred /* forward request to interface, if any */ 206184610Salfred 207184610Salfred if ((error != 0) && 208184610Salfred (error != ENOTTY) && 209184610Salfred (iface->subdev != NULL) && 210184610Salfred device_is_attached(iface->subdev)) { 211184610Salfred#if 0 212190186Sthompsa DEVMETHOD(usb_handle_request, NULL); /* dummy */ 213184610Salfred#endif 214188942Sthompsa error = USB_HANDLE_REQUEST(iface->subdev, 215184610Salfred &req, ppdata, plen, 216194064Sthompsa off, state); 217184610Salfred } 218184610Salfred iface_parent = usb2_get_iface(udev, iface->parent_iface_index); 219184610Salfred 220184610Salfred if ((iface_parent == NULL) || 221184610Salfred (iface_parent->idesc == NULL)) { 222184610Salfred /* non-existing interface */ 223184610Salfred iface_parent = NULL; 224184610Salfred } 225184610Salfred /* forward request to parent interface, if any */ 226184610Salfred 227184610Salfred if ((error != 0) && 228184610Salfred (error != ENOTTY) && 229184610Salfred (iface_parent != NULL) && 230184610Salfred (iface_parent->subdev != NULL) && 231184610Salfred ((req.bmRequestType & 0x1F) == UT_INTERFACE) && 232184610Salfred (iface_parent->subdev != iface->subdev) && 233184610Salfred device_is_attached(iface_parent->subdev)) { 234188942Sthompsa error = USB_HANDLE_REQUEST(iface_parent->subdev, 235184610Salfred &req, ppdata, plen, off, 236194064Sthompsa state); 237184610Salfred } 238184610Salfred if (error == 0) { 239184610Salfred /* negativly adjust pointer and length */ 240184610Salfred *ppdata = ((uint8_t *)(*ppdata)) - off; 241184610Salfred *plen += off; 242184610Salfred goto tr_valid; 243184610Salfred } else if (error == ENOTTY) { 244184610Salfred goto tr_stalled; 245184610Salfred } 246184610Salfred if ((req.bmRequestType & 0x1F) != UT_INTERFACE) { 247184610Salfred iface_index++; /* iterate */ 248184610Salfred goto tr_repeat; 249184610Salfred } 250194064Sthompsa if (state != USB_HR_NOT_COMPLETE) { 251184610Salfred /* we are complete */ 252184610Salfred goto tr_valid; 253184610Salfred } 254184610Salfred switch (req.bmRequestType) { 255184610Salfred case UT_WRITE_INTERFACE: 256184610Salfred switch (req.bRequest) { 257184610Salfred case UR_SET_INTERFACE: 258184610Salfred /* 259184610Salfred * Handle special case. If we have parent interface 260184610Salfred * we just reset the endpoints, because this is a 261184610Salfred * multi interface device and re-attaching only a 262184610Salfred * part of the device is not possible. Also if the 263184610Salfred * alternate setting is the same like before we just 264184610Salfred * reset the interface endoints. 265184610Salfred */ 266184610Salfred if ((iface_parent != NULL) || 267184610Salfred (iface->alt_index == req.wValue[0])) { 268184610Salfred error = usb2_reset_iface_endpoints(udev, 269184610Salfred iface_index); 270184610Salfred if (error) { 271184610Salfred DPRINTF("alt setting failed %s\n", 272184610Salfred usb2_errstr(error)); 273184610Salfred goto tr_stalled; 274184610Salfred } 275184610Salfred break; 276184610Salfred } 277188986Sthompsa /* 278188986Sthompsa * Doing the alternate setting will detach the 279188986Sthompsa * interface aswell: 280188986Sthompsa */ 281184610Salfred error = usb2_set_alt_interface_index(udev, 282184610Salfred iface_index, req.wValue[0]); 283184610Salfred if (error) { 284184610Salfred DPRINTF("alt setting failed %s\n", 285184610Salfred usb2_errstr(error)); 286184610Salfred goto tr_stalled; 287184610Salfred } 288184610Salfred error = usb2_probe_and_attach(udev, 289184610Salfred iface_index); 290184610Salfred if (error) { 291184610Salfred DPRINTF("alt setting probe failed\n"); 292184610Salfred goto tr_stalled; 293184610Salfred } 294184610Salfred break; 295184610Salfred default: 296184610Salfred goto tr_stalled; 297184610Salfred } 298184610Salfred break; 299184610Salfred 300184610Salfred case UT_READ_INTERFACE: 301184610Salfred switch (req.bRequest) { 302184610Salfred case UR_GET_INTERFACE: 303184610Salfred *ppdata = &iface->alt_index; 304184610Salfred *plen = 1; 305184610Salfred break; 306184610Salfred 307184610Salfred default: 308184610Salfred goto tr_stalled; 309184610Salfred } 310184610Salfred break; 311184610Salfred default: 312184610Salfred goto tr_stalled; 313184610Salfred } 314184610Salfredtr_valid: 315184610Salfred mtx_unlock(&Giant); 316184610Salfred sx_unlock(udev->default_sx + 1); 317184824Sthompsa USB_XFER_LOCK(xfer); 318184610Salfred return (0); 319184610Salfred 320184610Salfredtr_stalled: 321184610Salfred mtx_unlock(&Giant); 322184610Salfred sx_unlock(udev->default_sx + 1); 323184824Sthompsa USB_XFER_LOCK(xfer); 324184610Salfred return (USB_ERR_STALLED); 325184610Salfred} 326184610Salfred 327184610Salfred/*------------------------------------------------------------------------* 328184610Salfred * usb2_handle_stall 329184610Salfred * 330184610Salfred * Returns: 331184610Salfred * 0: Success 332184610Salfred * Else: Failure 333184610Salfred *------------------------------------------------------------------------*/ 334193045Sthompsastatic usb_error_t 335192984Sthompsausb2_handle_set_stall(struct usb_xfer *xfer, uint8_t ep, uint8_t do_stall) 336184610Salfred{ 337192984Sthompsa struct usb_device *udev = xfer->xroot->udev; 338193045Sthompsa usb_error_t err; 339184610Salfred 340184824Sthompsa USB_XFER_UNLOCK(xfer); 341187173Sthompsa err = usb2_set_endpoint_stall(udev, 342193644Sthompsa usb2_get_ep_by_addr(udev, ep), do_stall); 343184824Sthompsa USB_XFER_LOCK(xfer); 344184610Salfred return (err); 345184610Salfred} 346184610Salfred 347184610Salfred/*------------------------------------------------------------------------* 348184610Salfred * usb2_handle_get_stall 349184610Salfred * 350184610Salfred * Returns: 351184610Salfred * 0: Success 352184610Salfred * Else: Failure 353184610Salfred *------------------------------------------------------------------------*/ 354184610Salfredstatic uint8_t 355192984Sthompsausb2_handle_get_stall(struct usb_device *udev, uint8_t ea_val) 356184610Salfred{ 357193644Sthompsa struct usb_endpoint *ep; 358184610Salfred uint8_t halted; 359184610Salfred 360193644Sthompsa ep = usb2_get_ep_by_addr(udev, ea_val); 361193644Sthompsa if (ep == NULL) { 362184610Salfred /* nothing to do */ 363184610Salfred return (0); 364184610Salfred } 365184824Sthompsa USB_BUS_LOCK(udev->bus); 366193644Sthompsa halted = ep->is_stalled; 367184824Sthompsa USB_BUS_UNLOCK(udev->bus); 368184610Salfred 369184610Salfred return (halted); 370184610Salfred} 371184610Salfred 372184610Salfred/*------------------------------------------------------------------------* 373184610Salfred * usb2_handle_remote_wakeup 374184610Salfred * 375184610Salfred * Returns: 376184610Salfred * 0: Success 377184610Salfred * Else: Failure 378184610Salfred *------------------------------------------------------------------------*/ 379193045Sthompsastatic usb_error_t 380192984Sthompsausb2_handle_remote_wakeup(struct usb_xfer *xfer, uint8_t is_on) 381184610Salfred{ 382192984Sthompsa struct usb_device *udev; 383192984Sthompsa struct usb_bus *bus; 384184610Salfred 385187173Sthompsa udev = xfer->xroot->udev; 386184610Salfred bus = udev->bus; 387184610Salfred 388184824Sthompsa USB_BUS_LOCK(bus); 389184610Salfred 390184610Salfred if (is_on) { 391184610Salfred udev->flags.remote_wakeup = 1; 392184610Salfred } else { 393184610Salfred udev->flags.remote_wakeup = 0; 394184610Salfred } 395184610Salfred 396184824Sthompsa USB_BUS_UNLOCK(bus); 397184610Salfred 398186730Salfred /* In case we are out of sync, update the power state. */ 399186730Salfred usb2_bus_power_update(udev->bus); 400184610Salfred return (0); /* success */ 401184610Salfred} 402184610Salfred 403184610Salfred/*------------------------------------------------------------------------* 404184610Salfred * usb2_handle_request 405184610Salfred * 406184610Salfred * Internal state sequence: 407184610Salfred * 408194064Sthompsa * USB_HR_NOT_COMPLETE -> USB_HR_COMPLETE_OK v USB_HR_COMPLETE_ERR 409184610Salfred * 410184610Salfred * Returns: 411184610Salfred * 0: Ready to start hardware 412184610Salfred * Else: Stall current transfer, if any 413184610Salfred *------------------------------------------------------------------------*/ 414193045Sthompsastatic usb_error_t 415192984Sthompsausb2_handle_request(struct usb_xfer *xfer) 416184610Salfred{ 417192984Sthompsa struct usb_device_request req; 418192984Sthompsa struct usb_device *udev; 419184610Salfred const void *src_zcopy; /* zero-copy source pointer */ 420184610Salfred const void *src_mcopy; /* non zero-copy source pointer */ 421184610Salfred uint16_t off; /* data offset */ 422184610Salfred uint16_t rem; /* data remainder */ 423184610Salfred uint16_t max_len; /* max fragment length */ 424184610Salfred uint16_t wValue; 425184610Salfred uint16_t wIndex; 426184610Salfred uint8_t state; 427193045Sthompsa usb_error_t err; 428184610Salfred union { 429184610Salfred uWord wStatus; 430184610Salfred uint8_t buf[2]; 431184610Salfred } temp; 432184610Salfred 433184610Salfred /* 434184610Salfred * Filter the USB transfer state into 435184610Salfred * something which we understand: 436184610Salfred */ 437184610Salfred 438184610Salfred switch (USB_GET_STATE(xfer)) { 439184610Salfred case USB_ST_SETUP: 440194064Sthompsa state = USB_HR_NOT_COMPLETE; 441184610Salfred 442184610Salfred if (!xfer->flags_int.control_act) { 443184610Salfred /* nothing to do */ 444184610Salfred goto tr_stalled; 445184610Salfred } 446184610Salfred break; 447194064Sthompsa case USB_ST_TRANSFERRED: 448184610Salfred if (!xfer->flags_int.control_act) { 449194064Sthompsa state = USB_HR_COMPLETE_OK; 450184610Salfred } else { 451194064Sthompsa state = USB_HR_NOT_COMPLETE; 452184610Salfred } 453184610Salfred break; 454194064Sthompsa default: 455194064Sthompsa state = USB_HR_COMPLETE_ERR; 456194064Sthompsa break; 457184610Salfred } 458184610Salfred 459184610Salfred /* reset frame stuff */ 460184610Salfred 461184610Salfred xfer->frlengths[0] = 0; 462184610Salfred 463184610Salfred usb2_set_frame_offset(xfer, 0, 0); 464184610Salfred usb2_set_frame_offset(xfer, sizeof(req), 1); 465184610Salfred 466184610Salfred /* get the current request, if any */ 467184610Salfred 468184610Salfred usb2_copy_out(xfer->frbuffers, 0, &req, sizeof(req)); 469184610Salfred 470184610Salfred if (xfer->flags_int.control_rem == 0xFFFF) { 471184610Salfred /* first time - not initialised */ 472184610Salfred rem = UGETW(req.wLength); 473184610Salfred off = 0; 474184610Salfred } else { 475184610Salfred /* not first time - initialised */ 476184610Salfred rem = xfer->flags_int.control_rem; 477184610Salfred off = UGETW(req.wLength) - rem; 478184610Salfred } 479184610Salfred 480184610Salfred /* set some defaults */ 481184610Salfred 482184610Salfred max_len = 0; 483184610Salfred src_zcopy = NULL; 484184610Salfred src_mcopy = NULL; 485187173Sthompsa udev = xfer->xroot->udev; 486184610Salfred 487184610Salfred /* get some request fields decoded */ 488184610Salfred 489184610Salfred wValue = UGETW(req.wValue); 490184610Salfred wIndex = UGETW(req.wIndex); 491184610Salfred 492184610Salfred DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x " 493184610Salfred "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType, 494184610Salfred req.bRequest, wValue, wIndex, off, rem, state); 495184610Salfred 496184610Salfred /* demultiplex the control request */ 497184610Salfred 498184610Salfred switch (req.bmRequestType) { 499184610Salfred case UT_READ_DEVICE: 500194064Sthompsa if (state != USB_HR_NOT_COMPLETE) { 501184610Salfred break; 502184610Salfred } 503184610Salfred switch (req.bRequest) { 504184610Salfred case UR_GET_DESCRIPTOR: 505184610Salfred goto tr_handle_get_descriptor; 506184610Salfred case UR_GET_CONFIG: 507184610Salfred goto tr_handle_get_config; 508184610Salfred case UR_GET_STATUS: 509184610Salfred goto tr_handle_get_status; 510184610Salfred default: 511184610Salfred goto tr_stalled; 512184610Salfred } 513184610Salfred break; 514184610Salfred 515184610Salfred case UT_WRITE_DEVICE: 516184610Salfred switch (req.bRequest) { 517184610Salfred case UR_SET_ADDRESS: 518184610Salfred goto tr_handle_set_address; 519184610Salfred case UR_SET_CONFIG: 520184610Salfred goto tr_handle_set_config; 521184610Salfred case UR_CLEAR_FEATURE: 522184610Salfred switch (wValue) { 523184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 524184610Salfred goto tr_handle_clear_wakeup; 525184610Salfred default: 526184610Salfred goto tr_stalled; 527184610Salfred } 528184610Salfred break; 529184610Salfred case UR_SET_FEATURE: 530184610Salfred switch (wValue) { 531184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 532184610Salfred goto tr_handle_set_wakeup; 533184610Salfred default: 534184610Salfred goto tr_stalled; 535184610Salfred } 536184610Salfred break; 537184610Salfred default: 538184610Salfred goto tr_stalled; 539184610Salfred } 540184610Salfred break; 541184610Salfred 542184610Salfred case UT_WRITE_ENDPOINT: 543184610Salfred switch (req.bRequest) { 544184610Salfred case UR_CLEAR_FEATURE: 545184610Salfred switch (wValue) { 546184610Salfred case UF_ENDPOINT_HALT: 547184610Salfred goto tr_handle_clear_halt; 548184610Salfred default: 549184610Salfred goto tr_stalled; 550184610Salfred } 551184610Salfred break; 552184610Salfred case UR_SET_FEATURE: 553184610Salfred switch (wValue) { 554184610Salfred case UF_ENDPOINT_HALT: 555184610Salfred goto tr_handle_set_halt; 556184610Salfred default: 557184610Salfred goto tr_stalled; 558184610Salfred } 559184610Salfred break; 560184610Salfred default: 561184610Salfred goto tr_stalled; 562184610Salfred } 563184610Salfred break; 564184610Salfred 565184610Salfred case UT_READ_ENDPOINT: 566184610Salfred switch (req.bRequest) { 567184610Salfred case UR_GET_STATUS: 568184610Salfred goto tr_handle_get_ep_status; 569184610Salfred default: 570184610Salfred goto tr_stalled; 571184610Salfred } 572184610Salfred break; 573184610Salfred default: 574184610Salfred /* we use "USB_ADD_BYTES" to de-const the src_zcopy */ 575184610Salfred err = usb2_handle_iface_request(xfer, 576184610Salfred USB_ADD_BYTES(&src_zcopy, 0), 577184610Salfred &max_len, req, off, state); 578184610Salfred if (err == 0) { 579184610Salfred goto tr_valid; 580184610Salfred } 581184610Salfred /* 582184610Salfred * Reset zero-copy pointer and max length 583184610Salfred * variable in case they were unintentionally 584184610Salfred * set: 585184610Salfred */ 586184610Salfred src_zcopy = NULL; 587184610Salfred max_len = 0; 588184610Salfred 589184610Salfred /* 590184610Salfred * Check if we have a vendor specific 591184610Salfred * descriptor: 592184610Salfred */ 593184610Salfred goto tr_handle_get_descriptor; 594184610Salfred } 595184610Salfred goto tr_valid; 596184610Salfred 597184610Salfredtr_handle_get_descriptor: 598191402Sthompsa err = (usb2_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len); 599191402Sthompsa if (err) 600184610Salfred goto tr_stalled; 601191402Sthompsa if (src_zcopy == NULL) 602191402Sthompsa goto tr_stalled; 603184610Salfred goto tr_valid; 604184610Salfred 605184610Salfredtr_handle_get_config: 606184610Salfred temp.buf[0] = udev->curr_config_no; 607184610Salfred src_mcopy = temp.buf; 608184610Salfred max_len = 1; 609184610Salfred goto tr_valid; 610184610Salfred 611184610Salfredtr_handle_get_status: 612184610Salfred 613184610Salfred wValue = 0; 614184610Salfred 615184824Sthompsa USB_BUS_LOCK(udev->bus); 616184610Salfred if (udev->flags.remote_wakeup) { 617184610Salfred wValue |= UDS_REMOTE_WAKEUP; 618184610Salfred } 619184610Salfred if (udev->flags.self_powered) { 620184610Salfred wValue |= UDS_SELF_POWERED; 621184610Salfred } 622184824Sthompsa USB_BUS_UNLOCK(udev->bus); 623184610Salfred 624184610Salfred USETW(temp.wStatus, wValue); 625184610Salfred src_mcopy = temp.wStatus; 626184610Salfred max_len = sizeof(temp.wStatus); 627184610Salfred goto tr_valid; 628184610Salfred 629184610Salfredtr_handle_set_address: 630194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 631184610Salfred if (wValue >= 0x80) { 632184610Salfred /* invalid value */ 633184610Salfred goto tr_stalled; 634184610Salfred } else if (udev->curr_config_no != 0) { 635184610Salfred /* we are configured ! */ 636184610Salfred goto tr_stalled; 637184610Salfred } 638194064Sthompsa } else if (state != USB_HR_NOT_COMPLETE) { 639184610Salfred udev->address = (wValue & 0x7F); 640184610Salfred goto tr_bad_context; 641184610Salfred } 642184610Salfred goto tr_valid; 643184610Salfred 644184610Salfredtr_handle_set_config: 645194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 646184610Salfred if (usb2_handle_set_config(xfer, req.wValue[0])) { 647184610Salfred goto tr_stalled; 648184610Salfred } 649184610Salfred } 650184610Salfred goto tr_valid; 651184610Salfred 652184610Salfredtr_handle_clear_halt: 653194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 654184610Salfred if (usb2_handle_set_stall(xfer, req.wIndex[0], 0)) { 655184610Salfred goto tr_stalled; 656184610Salfred } 657184610Salfred } 658184610Salfred goto tr_valid; 659184610Salfred 660184610Salfredtr_handle_clear_wakeup: 661194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 662184610Salfred if (usb2_handle_remote_wakeup(xfer, 0)) { 663184610Salfred goto tr_stalled; 664184610Salfred } 665184610Salfred } 666184610Salfred goto tr_valid; 667184610Salfred 668184610Salfredtr_handle_set_halt: 669194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 670184610Salfred if (usb2_handle_set_stall(xfer, req.wIndex[0], 1)) { 671184610Salfred goto tr_stalled; 672184610Salfred } 673184610Salfred } 674184610Salfred goto tr_valid; 675184610Salfred 676184610Salfredtr_handle_set_wakeup: 677194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 678184610Salfred if (usb2_handle_remote_wakeup(xfer, 1)) { 679184610Salfred goto tr_stalled; 680184610Salfred } 681184610Salfred } 682184610Salfred goto tr_valid; 683184610Salfred 684184610Salfredtr_handle_get_ep_status: 685194064Sthompsa if (state == USB_HR_NOT_COMPLETE) { 686184610Salfred temp.wStatus[0] = 687184610Salfred usb2_handle_get_stall(udev, req.wIndex[0]); 688184610Salfred temp.wStatus[1] = 0; 689184610Salfred src_mcopy = temp.wStatus; 690184610Salfred max_len = sizeof(temp.wStatus); 691184610Salfred } 692184610Salfred goto tr_valid; 693184610Salfred 694184610Salfredtr_valid: 695194064Sthompsa if (state != USB_HR_NOT_COMPLETE) { 696184610Salfred goto tr_stalled; 697184610Salfred } 698184610Salfred /* subtract offset from length */ 699184610Salfred 700184610Salfred max_len -= off; 701184610Salfred 702184610Salfred /* Compute the real maximum data length */ 703184610Salfred 704184610Salfred if (max_len > xfer->max_data_length) { 705184610Salfred max_len = xfer->max_data_length; 706184610Salfred } 707184610Salfred if (max_len > rem) { 708184610Salfred max_len = rem; 709184610Salfred } 710184610Salfred /* 711184610Salfred * If the remainder is greater than the maximum data length, 712184610Salfred * we need to truncate the value for the sake of the 713184610Salfred * comparison below: 714184610Salfred */ 715184610Salfred if (rem > xfer->max_data_length) { 716184610Salfred rem = xfer->max_data_length; 717184610Salfred } 718184610Salfred if (rem != max_len) { 719184610Salfred /* 720184610Salfred * If we don't transfer the data we can transfer, then 721184610Salfred * the transfer is short ! 722184610Salfred */ 723184610Salfred xfer->flags.force_short_xfer = 1; 724184610Salfred xfer->nframes = 2; 725184610Salfred } else { 726184610Salfred /* 727184610Salfred * Default case 728184610Salfred */ 729184610Salfred xfer->flags.force_short_xfer = 0; 730184610Salfred xfer->nframes = max_len ? 2 : 1; 731184610Salfred } 732184610Salfred if (max_len > 0) { 733184610Salfred if (src_mcopy) { 734184610Salfred src_mcopy = USB_ADD_BYTES(src_mcopy, off); 735184610Salfred usb2_copy_in(xfer->frbuffers + 1, 0, 736184610Salfred src_mcopy, max_len); 737184610Salfred } else { 738184610Salfred usb2_set_frame_data(xfer, 739184610Salfred USB_ADD_BYTES(src_zcopy, off), 1); 740184610Salfred } 741184610Salfred xfer->frlengths[1] = max_len; 742184610Salfred } else { 743184610Salfred /* the end is reached, send status */ 744184610Salfred xfer->flags.manual_status = 0; 745184610Salfred xfer->frlengths[1] = 0; 746184610Salfred } 747184610Salfred DPRINTF("success\n"); 748184610Salfred return (0); /* success */ 749184610Salfred 750184610Salfredtr_stalled: 751194064Sthompsa DPRINTF("%s\n", (state != USB_HR_NOT_COMPLETE) ? 752184610Salfred "complete" : "stalled"); 753184610Salfred return (USB_ERR_STALLED); 754184610Salfred 755184610Salfredtr_bad_context: 756184610Salfred DPRINTF("bad context\n"); 757184610Salfred return (USB_ERR_BAD_CONTEXT); 758184610Salfred} 759