linux_usb.c revision 184610
1184610Salfred/* $FreeBSD: head/sys/dev/usb2/core/usb2_compat_linux.c 184610 2008-11-04 02:31:03Z alfred $ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved. 4184610Salfred * Copyright (c) 2007 Hans Petter Selasky. All rights reserved. 5184610Salfred * 6184610Salfred * Redistribution and use in source and binary forms, with or without 7184610Salfred * modification, are permitted provided that the following conditions 8184610Salfred * are met: 9184610Salfred * 1. Redistributions of source code must retain the above copyright 10184610Salfred * notice, this list of conditions and the following disclaimer. 11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 12184610Salfred * notice, this list of conditions and the following disclaimer in the 13184610Salfred * documentation and/or other materials provided with the distribution. 14184610Salfred * 15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184610Salfred * SUCH DAMAGE. 26184610Salfred */ 27184610Salfred 28184610Salfred#include <dev/usb2/include/usb2_defs.h> 29184610Salfred#include <dev/usb2/include/usb2_mfunc.h> 30184610Salfred#include <dev/usb2/include/usb2_standard.h> 31184610Salfred#include <dev/usb2/include/usb2_error.h> 32184610Salfred#include <dev/usb2/include/usb2_ioctl.h> 33184610Salfred 34184610Salfred#define USB_DEBUG_VAR usb2_debug 35184610Salfred 36184610Salfred#include <dev/usb2/core/usb2_core.h> 37184610Salfred#include <dev/usb2/core/usb2_compat_linux.h> 38184610Salfred#include <dev/usb2/core/usb2_process.h> 39184610Salfred#include <dev/usb2/core/usb2_device.h> 40184610Salfred#include <dev/usb2/core/usb2_util.h> 41184610Salfred#include <dev/usb2/core/usb2_busdma.h> 42184610Salfred#include <dev/usb2/core/usb2_transfer.h> 43184610Salfred#include <dev/usb2/core/usb2_parse.h> 44184610Salfred#include <dev/usb2/core/usb2_hub.h> 45184610Salfred#include <dev/usb2/core/usb2_request.h> 46184610Salfred#include <dev/usb2/core/usb2_debug.h> 47184610Salfred 48184610Salfredstruct usb_linux_softc { 49184610Salfred LIST_ENTRY(usb_linux_softc) sc_attached_list; 50184610Salfred 51184610Salfred device_t sc_fbsd_dev; 52184610Salfred struct usb2_device *sc_fbsd_udev; 53184610Salfred struct usb_interface *sc_ui; 54184610Salfred struct usb_driver *sc_udrv; 55184610Salfred}; 56184610Salfred 57184610Salfred/* prototypes */ 58184610Salfredstatic device_probe_t usb_linux_probe; 59184610Salfredstatic device_attach_t usb_linux_attach; 60184610Salfredstatic device_detach_t usb_linux_detach; 61184610Salfredstatic device_suspend_t usb_linux_suspend; 62184610Salfredstatic device_resume_t usb_linux_resume; 63184610Salfredstatic device_shutdown_t usb_linux_shutdown; 64184610Salfred 65184610Salfredstatic usb2_callback_t usb_linux_isoc_callback; 66184610Salfredstatic usb2_callback_t usb_linux_non_isoc_callback; 67184610Salfred 68184610Salfredstatic usb_complete_t usb_linux_wait_complete; 69184610Salfred 70184610Salfredstatic uint16_t usb_max_isoc_frames(struct usb_device *dev); 71184610Salfredstatic int usb_start_wait_urb(struct urb *urb, uint32_t timeout, uint16_t *p_actlen); 72184610Salfredstatic const struct usb_device_id *usb_linux_lookup_id(const struct usb_device_id *id, struct usb2_attach_arg *uaa); 73184610Salfredstatic struct usb_driver *usb_linux_get_usb_driver(struct usb_linux_softc *sc); 74184610Salfredstatic struct usb_device *usb_linux_create_usb_device(struct usb2_device *udev, device_t dev); 75184610Salfredstatic void usb_linux_cleanup_interface(struct usb_device *dev, struct usb_interface *iface); 76184610Salfredstatic void usb_linux_complete(struct usb2_xfer *xfer); 77184610Salfredstatic int usb_unlink_urb_sub(struct urb *urb, uint8_t drain); 78184610Salfred 79184610Salfred/*------------------------------------------------------------------------* 80184610Salfred * FreeBSD USB interface 81184610Salfred *------------------------------------------------------------------------*/ 82184610Salfred 83184610Salfredstatic LIST_HEAD(, usb_linux_softc) usb_linux_attached_list; 84184610Salfredstatic LIST_HEAD(, usb_driver) usb_linux_driver_list; 85184610Salfred 86184610Salfredstatic device_method_t usb_linux_methods[] = { 87184610Salfred /* Device interface */ 88184610Salfred DEVMETHOD(device_probe, usb_linux_probe), 89184610Salfred DEVMETHOD(device_attach, usb_linux_attach), 90184610Salfred DEVMETHOD(device_detach, usb_linux_detach), 91184610Salfred DEVMETHOD(device_suspend, usb_linux_suspend), 92184610Salfred DEVMETHOD(device_resume, usb_linux_resume), 93184610Salfred DEVMETHOD(device_shutdown, usb_linux_shutdown), 94184610Salfred 95184610Salfred {0, 0} 96184610Salfred}; 97184610Salfred 98184610Salfredstatic driver_t usb_linux_driver = { 99184610Salfred .name = "usb_linux", 100184610Salfred .methods = usb_linux_methods, 101184610Salfred .size = sizeof(struct usb_linux_softc), 102184610Salfred}; 103184610Salfred 104184610Salfredstatic devclass_t usb_linux_devclass; 105184610Salfred 106184610SalfredDRIVER_MODULE(usb_linux, ushub, usb_linux_driver, usb_linux_devclass, NULL, 0); 107184610Salfred 108184610Salfred/*------------------------------------------------------------------------* 109184610Salfred * usb_linux_lookup_id 110184610Salfred * 111184610Salfred * This functions takes an array of "struct usb_device_id" and tries 112184610Salfred * to match the entries with the information in "struct usb2_attach_arg". 113184610Salfred * If it finds a match the matching entry will be returned. 114184610Salfred * Else "NULL" will be returned. 115184610Salfred *------------------------------------------------------------------------*/ 116184610Salfredstatic const struct usb_device_id * 117184610Salfredusb_linux_lookup_id(const struct usb_device_id *id, struct usb2_attach_arg *uaa) 118184610Salfred{ 119184610Salfred if (id == NULL) { 120184610Salfred goto done; 121184610Salfred } 122184610Salfred /* 123184610Salfred * Keep on matching array entries until we find one with 124184610Salfred * "match_flags" equal to zero, which indicates the end of the 125184610Salfred * array: 126184610Salfred */ 127184610Salfred for (; id->match_flags; id++) { 128184610Salfred 129184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && 130184610Salfred (id->idVendor != uaa->info.idVendor)) { 131184610Salfred continue; 132184610Salfred } 133184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && 134184610Salfred (id->idProduct != uaa->info.idProduct)) { 135184610Salfred continue; 136184610Salfred } 137184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && 138184610Salfred (id->bcdDevice_lo > uaa->info.bcdDevice)) { 139184610Salfred continue; 140184610Salfred } 141184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && 142184610Salfred (id->bcdDevice_hi < uaa->info.bcdDevice)) { 143184610Salfred continue; 144184610Salfred } 145184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && 146184610Salfred (id->bDeviceClass != uaa->info.bDeviceClass)) { 147184610Salfred continue; 148184610Salfred } 149184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && 150184610Salfred (id->bDeviceSubClass != uaa->info.bDeviceSubClass)) { 151184610Salfred continue; 152184610Salfred } 153184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && 154184610Salfred (id->bDeviceProtocol != uaa->info.bDeviceProtocol)) { 155184610Salfred continue; 156184610Salfred } 157184610Salfred if ((uaa->info.bDeviceClass == 0xFF) && 158184610Salfred !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && 159184610Salfred (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | 160184610Salfred USB_DEVICE_ID_MATCH_INT_SUBCLASS | 161184610Salfred USB_DEVICE_ID_MATCH_INT_PROTOCOL))) { 162184610Salfred continue; 163184610Salfred } 164184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && 165184610Salfred (id->bInterfaceClass != uaa->info.bInterfaceClass)) { 166184610Salfred continue; 167184610Salfred } 168184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && 169184610Salfred (id->bInterfaceSubClass != uaa->info.bInterfaceSubClass)) { 170184610Salfred continue; 171184610Salfred } 172184610Salfred if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && 173184610Salfred (id->bInterfaceProtocol != uaa->info.bInterfaceProtocol)) { 174184610Salfred continue; 175184610Salfred } 176184610Salfred /* we found a match! */ 177184610Salfred return (id); 178184610Salfred } 179184610Salfred 180184610Salfreddone: 181184610Salfred return (NULL); 182184610Salfred} 183184610Salfred 184184610Salfred/*------------------------------------------------------------------------* 185184610Salfred * usb_linux_probe 186184610Salfred * 187184610Salfred * This function is the FreeBSD probe callback. It is called from the 188184610Salfred * FreeBSD USB stack through the "device_probe_and_attach()" function. 189184610Salfred *------------------------------------------------------------------------*/ 190184610Salfredstatic int 191184610Salfredusb_linux_probe(device_t dev) 192184610Salfred{ 193184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 194184610Salfred struct usb_driver *udrv; 195184610Salfred int err = ENXIO; 196184610Salfred 197184610Salfred if (uaa->usb2_mode != USB_MODE_HOST) { 198184610Salfred return (ENXIO); 199184610Salfred } 200184610Salfred mtx_lock(&Giant); 201184610Salfred LIST_FOREACH(udrv, &usb_linux_driver_list, linux_driver_list) { 202184610Salfred if (usb_linux_lookup_id(udrv->id_table, uaa)) { 203184610Salfred err = 0; 204184610Salfred break; 205184610Salfred } 206184610Salfred } 207184610Salfred mtx_unlock(&Giant); 208184610Salfred 209184610Salfred return (err); 210184610Salfred} 211184610Salfred 212184610Salfred/*------------------------------------------------------------------------* 213184610Salfred * usb_linux_get_usb_driver 214184610Salfred * 215184610Salfred * This function returns the pointer to the "struct usb_driver" where 216184610Salfred * the Linux USB device driver "struct usb_device_id" match was found. 217184610Salfred * We apply a lock before reading out the pointer to avoid races. 218184610Salfred *------------------------------------------------------------------------*/ 219184610Salfredstatic struct usb_driver * 220184610Salfredusb_linux_get_usb_driver(struct usb_linux_softc *sc) 221184610Salfred{ 222184610Salfred struct usb_driver *udrv; 223184610Salfred 224184610Salfred mtx_lock(&Giant); 225184610Salfred udrv = sc->sc_udrv; 226184610Salfred mtx_unlock(&Giant); 227184610Salfred return (udrv); 228184610Salfred} 229184610Salfred 230184610Salfred/*------------------------------------------------------------------------* 231184610Salfred * usb_linux_attach 232184610Salfred * 233184610Salfred * This function is the FreeBSD attach callback. It is called from the 234184610Salfred * FreeBSD USB stack through the "device_probe_and_attach()" function. 235184610Salfred * This function is called when "usb_linux_probe()" returns zero. 236184610Salfred *------------------------------------------------------------------------*/ 237184610Salfredstatic int 238184610Salfredusb_linux_attach(device_t dev) 239184610Salfred{ 240184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 241184610Salfred struct usb_linux_softc *sc = device_get_softc(dev); 242184610Salfred struct usb_driver *udrv; 243184610Salfred struct usb_device *p_dev; 244184610Salfred const struct usb_device_id *id = NULL; 245184610Salfred 246184610Salfred if (sc == NULL) { 247184610Salfred return (ENOMEM); 248184610Salfred } 249184610Salfred mtx_lock(&Giant); 250184610Salfred LIST_FOREACH(udrv, &usb_linux_driver_list, linux_driver_list) { 251184610Salfred id = usb_linux_lookup_id(udrv->id_table, uaa); 252184610Salfred if (id) 253184610Salfred break; 254184610Salfred } 255184610Salfred mtx_unlock(&Giant); 256184610Salfred 257184610Salfred if (id == NULL) { 258184610Salfred return (ENXIO); 259184610Salfred } 260184610Salfred /* 261184610Salfred * Save some memory and only create the Linux compat structure when 262184610Salfred * needed: 263184610Salfred */ 264184610Salfred p_dev = uaa->device->linux_dev; 265184610Salfred if (p_dev == NULL) { 266184610Salfred p_dev = usb_linux_create_usb_device(uaa->device, dev); 267184610Salfred if (p_dev == NULL) { 268184610Salfred return (ENOMEM); 269184610Salfred } 270184610Salfred uaa->device->linux_dev = p_dev; 271184610Salfred } 272184610Salfred device_set_usb2_desc(dev); 273184610Salfred 274184610Salfred sc->sc_fbsd_udev = uaa->device; 275184610Salfred sc->sc_fbsd_dev = dev; 276184610Salfred sc->sc_udrv = udrv; 277184610Salfred sc->sc_ui = usb_ifnum_to_if(p_dev, uaa->info.bIfaceNum); 278184610Salfred if (sc->sc_ui == NULL) { 279184610Salfred return (EINVAL); 280184610Salfred } 281184610Salfred if (udrv->probe) { 282184610Salfred if ((udrv->probe) (sc->sc_ui, id)) { 283184610Salfred return (ENXIO); 284184610Salfred } 285184610Salfred } 286184610Salfred mtx_lock(&Giant); 287184610Salfred LIST_INSERT_HEAD(&usb_linux_attached_list, sc, sc_attached_list); 288184610Salfred mtx_unlock(&Giant); 289184610Salfred 290184610Salfred /* success */ 291184610Salfred return (0); 292184610Salfred} 293184610Salfred 294184610Salfred/*------------------------------------------------------------------------* 295184610Salfred * usb_linux_detach 296184610Salfred * 297184610Salfred * This function is the FreeBSD detach callback. It is called from the 298184610Salfred * FreeBSD USB stack through the "device_detach()" function. 299184610Salfred *------------------------------------------------------------------------*/ 300184610Salfredstatic int 301184610Salfredusb_linux_detach(device_t dev) 302184610Salfred{ 303184610Salfred struct usb_linux_softc *sc = device_get_softc(dev); 304184610Salfred struct usb_driver *udrv = NULL; 305184610Salfred 306184610Salfred mtx_lock(&Giant); 307184610Salfred if (sc->sc_attached_list.le_prev) { 308184610Salfred LIST_REMOVE(sc, sc_attached_list); 309184610Salfred sc->sc_attached_list.le_prev = NULL; 310184610Salfred udrv = sc->sc_udrv; 311184610Salfred sc->sc_udrv = NULL; 312184610Salfred } 313184610Salfred mtx_unlock(&Giant); 314184610Salfred 315184610Salfred if (udrv && udrv->disconnect) { 316184610Salfred (udrv->disconnect) (sc->sc_ui); 317184610Salfred } 318184610Salfred /* 319184610Salfred * Make sure that we free all FreeBSD USB transfers belonging to 320184610Salfred * this Linux "usb_interface", hence they will most likely not be 321184610Salfred * needed any more. 322184610Salfred */ 323184610Salfred usb_linux_cleanup_interface(sc->sc_fbsd_udev->linux_dev, sc->sc_ui); 324184610Salfred return (0); 325184610Salfred} 326184610Salfred 327184610Salfred/*------------------------------------------------------------------------* 328184610Salfred * usb_linux_suspend 329184610Salfred * 330184610Salfred * This function is the FreeBSD suspend callback. Usually it does nothing. 331184610Salfred *------------------------------------------------------------------------*/ 332184610Salfredstatic int 333184610Salfredusb_linux_suspend(device_t dev) 334184610Salfred{ 335184610Salfred struct usb_linux_softc *sc = device_get_softc(dev); 336184610Salfred struct usb_driver *udrv = usb_linux_get_usb_driver(sc); 337184610Salfred int err; 338184610Salfred 339184610Salfred if (udrv && udrv->suspend) { 340184610Salfred err = (udrv->suspend) (sc->sc_ui, 0); 341184610Salfred } 342184610Salfred return (0); 343184610Salfred} 344184610Salfred 345184610Salfred/*------------------------------------------------------------------------* 346184610Salfred * usb_linux_resume 347184610Salfred * 348184610Salfred * This function is the FreeBSD resume callback. Usually it does nothing. 349184610Salfred *------------------------------------------------------------------------*/ 350184610Salfredstatic int 351184610Salfredusb_linux_resume(device_t dev) 352184610Salfred{ 353184610Salfred struct usb_linux_softc *sc = device_get_softc(dev); 354184610Salfred struct usb_driver *udrv = usb_linux_get_usb_driver(sc); 355184610Salfred int err; 356184610Salfred 357184610Salfred if (udrv && udrv->resume) { 358184610Salfred err = (udrv->resume) (sc->sc_ui); 359184610Salfred } 360184610Salfred return (0); 361184610Salfred} 362184610Salfred 363184610Salfred/*------------------------------------------------------------------------* 364184610Salfred * usb_linux_shutdown 365184610Salfred * 366184610Salfred * This function is the FreeBSD shutdown callback. Usually it does nothing. 367184610Salfred *------------------------------------------------------------------------*/ 368184610Salfredstatic int 369184610Salfredusb_linux_shutdown(device_t dev) 370184610Salfred{ 371184610Salfred struct usb_linux_softc *sc = device_get_softc(dev); 372184610Salfred struct usb_driver *udrv = usb_linux_get_usb_driver(sc); 373184610Salfred 374184610Salfred if (udrv && udrv->shutdown) { 375184610Salfred (udrv->shutdown) (sc->sc_ui); 376184610Salfred } 377184610Salfred return (0); 378184610Salfred} 379184610Salfred 380184610Salfred/*------------------------------------------------------------------------* 381184610Salfred * Linux emulation layer 382184610Salfred *------------------------------------------------------------------------*/ 383184610Salfred 384184610Salfred/*------------------------------------------------------------------------* 385184610Salfred * usb_max_isoc_frames 386184610Salfred * 387184610Salfred * The following function returns the maximum number of isochronous 388184610Salfred * frames that we support per URB. It is not part of the Linux USB API. 389184610Salfred *------------------------------------------------------------------------*/ 390184610Salfredstatic uint16_t 391184610Salfredusb_max_isoc_frames(struct usb_device *dev) 392184610Salfred{ 393184610Salfred return ((usb2_get_speed(dev->bsd_udev) == USB_SPEED_HIGH) ? 394184610Salfred USB_MAX_HIGH_SPEED_ISOC_FRAMES : USB_MAX_FULL_SPEED_ISOC_FRAMES); 395184610Salfred} 396184610Salfred 397184610Salfred/*------------------------------------------------------------------------* 398184610Salfred * usb_submit_urb 399184610Salfred * 400184610Salfred * This function is used to queue an URB after that it has been 401184610Salfred * initialized. If it returns non-zero, it means that the URB was not 402184610Salfred * queued. 403184610Salfred *------------------------------------------------------------------------*/ 404184610Salfredint 405184610Salfredusb_submit_urb(struct urb *urb, uint16_t mem_flags) 406184610Salfred{ 407184610Salfred struct usb_host_endpoint *uhe; 408184610Salfred 409184610Salfred if (urb == NULL) { 410184610Salfred return (-EINVAL); 411184610Salfred } 412184610Salfred mtx_assert(&Giant, MA_OWNED); 413184610Salfred 414184610Salfred if (urb->pipe == NULL) { 415184610Salfred return (-EINVAL); 416184610Salfred } 417184610Salfred uhe = urb->pipe; 418184610Salfred 419184610Salfred /* 420184610Salfred * Check that we have got a FreeBSD USB transfer that will dequeue 421184610Salfred * the URB structure and do the real transfer. If there are no USB 422184610Salfred * transfers, then we return an error. 423184610Salfred */ 424184610Salfred if (uhe->bsd_xfer[0] || 425184610Salfred uhe->bsd_xfer[1]) { 426184610Salfred /* we are ready! */ 427184610Salfred 428184610Salfred TAILQ_INSERT_HEAD(&uhe->bsd_urb_list, urb, bsd_urb_list); 429184610Salfred 430184610Salfred urb->status = -EINPROGRESS; 431184610Salfred 432184610Salfred usb2_transfer_start(uhe->bsd_xfer[0]); 433184610Salfred usb2_transfer_start(uhe->bsd_xfer[1]); 434184610Salfred } else { 435184610Salfred /* no pipes have been setup yet! */ 436184610Salfred urb->status = -EINVAL; 437184610Salfred return (-EINVAL); 438184610Salfred } 439184610Salfred return (0); 440184610Salfred} 441184610Salfred 442184610Salfred/*------------------------------------------------------------------------* 443184610Salfred * usb_unlink_urb 444184610Salfred * 445184610Salfred * This function is used to stop an URB after that it is been 446184610Salfred * submitted, but before the "complete" callback has been called. On 447184610Salfred *------------------------------------------------------------------------*/ 448184610Salfredint 449184610Salfredusb_unlink_urb(struct urb *urb) 450184610Salfred{ 451184610Salfred return (usb_unlink_urb_sub(urb, 0)); 452184610Salfred} 453184610Salfred 454184610Salfredstatic void 455184610Salfredusb_unlink_bsd(struct usb2_xfer *xfer, 456184610Salfred struct urb *urb, uint8_t drain) 457184610Salfred{ 458184610Salfred if (xfer && 459184610Salfred usb2_transfer_pending(xfer) && 460184610Salfred (xfer->priv_fifo == (void *)urb)) { 461184610Salfred if (drain) { 462184610Salfred mtx_unlock(&Giant); 463184610Salfred usb2_transfer_drain(xfer); 464184610Salfred mtx_lock(&Giant); 465184610Salfred } else { 466184610Salfred usb2_transfer_stop(xfer); 467184610Salfred } 468184610Salfred usb2_transfer_start(xfer); 469184610Salfred } 470184610Salfred return; 471184610Salfred} 472184610Salfred 473184610Salfredstatic int 474184610Salfredusb_unlink_urb_sub(struct urb *urb, uint8_t drain) 475184610Salfred{ 476184610Salfred struct usb_host_endpoint *uhe; 477184610Salfred uint16_t x; 478184610Salfred 479184610Salfred if (urb == NULL) { 480184610Salfred return (-EINVAL); 481184610Salfred } 482184610Salfred mtx_assert(&Giant, MA_OWNED); 483184610Salfred 484184610Salfred if (urb->pipe == NULL) { 485184610Salfred return (-EINVAL); 486184610Salfred } 487184610Salfred uhe = urb->pipe; 488184610Salfred 489184610Salfred if (urb->bsd_urb_list.tqe_prev) { 490184610Salfred 491184610Salfred /* not started yet, just remove it from the queue */ 492184610Salfred TAILQ_REMOVE(&uhe->bsd_urb_list, urb, bsd_urb_list); 493184610Salfred urb->bsd_urb_list.tqe_prev = NULL; 494184610Salfred urb->status = -ECONNRESET; 495184610Salfred urb->actual_length = 0; 496184610Salfred 497184610Salfred for (x = 0; x < urb->number_of_packets; x++) { 498184610Salfred urb->iso_frame_desc[x].actual_length = 0; 499184610Salfred } 500184610Salfred 501184610Salfred if (urb->complete) { 502184610Salfred (urb->complete) (urb); 503184610Salfred } 504184610Salfred } else { 505184610Salfred 506184610Salfred /* 507184610Salfred * If the URB is not on the URB list, then check if one of 508184610Salfred * the FreeBSD USB transfer are processing the current URB. 509184610Salfred * If so, re-start that transfer, which will lead to the 510184610Salfred * termination of that URB: 511184610Salfred */ 512184610Salfred usb_unlink_bsd(uhe->bsd_xfer[0], urb, drain); 513184610Salfred usb_unlink_bsd(uhe->bsd_xfer[1], urb, drain); 514184610Salfred } 515184610Salfred return (0); 516184610Salfred} 517184610Salfred 518184610Salfred/*------------------------------------------------------------------------* 519184610Salfred * usb_clear_halt 520184610Salfred * 521184610Salfred * This function must always be used to clear the stall. Stall is when 522184610Salfred * an USB endpoint returns a stall message to the USB host controller. 523184610Salfred * Until the stall is cleared, no data can be transferred. 524184610Salfred *------------------------------------------------------------------------*/ 525184610Salfredint 526184610Salfredusb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe) 527184610Salfred{ 528184610Salfred struct usb2_config cfg[1]; 529184610Salfred struct usb2_pipe *pipe; 530184610Salfred uint8_t type; 531184610Salfred uint8_t addr; 532184610Salfred 533184610Salfred if (uhe == NULL) 534184610Salfred return (-EINVAL); 535184610Salfred 536184610Salfred type = uhe->desc.bmAttributes & UE_XFERTYPE; 537184610Salfred addr = uhe->desc.bEndpointAddress; 538184610Salfred 539184610Salfred bzero(cfg, sizeof(cfg)); 540184610Salfred 541184610Salfred cfg[0].type = type; 542184610Salfred cfg[0].endpoint = addr & UE_ADDR; 543184610Salfred cfg[0].direction = addr & (UE_DIR_OUT | UE_DIR_IN); 544184610Salfred 545184610Salfred pipe = usb2_get_pipe(dev->bsd_udev, uhe->bsd_iface_index, cfg); 546184610Salfred if (pipe == NULL) 547184610Salfred return (-EINVAL); 548184610Salfred 549184610Salfred usb2_clear_data_toggle(dev->bsd_udev, pipe); 550184610Salfred 551184610Salfred return (usb_control_msg(dev, &dev->ep0, 552184610Salfred UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT, 553184610Salfred UF_ENDPOINT_HALT, addr, NULL, 0, 1000)); 554184610Salfred} 555184610Salfred 556184610Salfred/*------------------------------------------------------------------------* 557184610Salfred * usb_start_wait_urb 558184610Salfred * 559184610Salfred * This is an internal function that is used to perform synchronous 560184610Salfred * Linux USB transfers. 561184610Salfred *------------------------------------------------------------------------*/ 562184610Salfredstatic int 563184610Salfredusb_start_wait_urb(struct urb *urb, uint32_t timeout, uint16_t *p_actlen) 564184610Salfred{ 565184610Salfred int err; 566184610Salfred 567184610Salfred /* you must have a timeout! */ 568184610Salfred if (timeout == 0) { 569184610Salfred timeout = 1; 570184610Salfred } 571184610Salfred urb->complete = &usb_linux_wait_complete; 572184610Salfred urb->timeout = timeout; 573184610Salfred urb->transfer_flags |= URB_WAIT_WAKEUP; 574184610Salfred urb->transfer_flags &= ~URB_IS_SLEEPING; 575184610Salfred 576184610Salfred err = usb_submit_urb(urb, 0); 577184610Salfred if (err) 578184610Salfred goto done; 579184610Salfred 580184610Salfred /* 581184610Salfred * the URB might have completed before we get here, so check that by 582184610Salfred * using some flags! 583184610Salfred */ 584184610Salfred while (urb->transfer_flags & URB_WAIT_WAKEUP) { 585184610Salfred urb->transfer_flags |= URB_IS_SLEEPING; 586184610Salfred usb2_cv_wait(&urb->cv_wait, &Giant); 587184610Salfred urb->transfer_flags &= ~URB_IS_SLEEPING; 588184610Salfred } 589184610Salfred 590184610Salfred err = urb->status; 591184610Salfred 592184610Salfreddone: 593184610Salfred if (err) { 594184610Salfred *p_actlen = 0; 595184610Salfred } else { 596184610Salfred *p_actlen = urb->actual_length; 597184610Salfred } 598184610Salfred return (err); 599184610Salfred} 600184610Salfred 601184610Salfred/*------------------------------------------------------------------------* 602184610Salfred * usb_control_msg 603184610Salfred * 604184610Salfred * The following function performs a control transfer sequence one any 605184610Salfred * control, bulk or interrupt endpoint, specified by "uhe". A control 606184610Salfred * transfer means that you transfer an 8-byte header first followed by 607184610Salfred * a data-phase as indicated by the 8-byte header. The "timeout" is 608184610Salfred * given in milliseconds. 609184610Salfred * 610184610Salfred * Return values: 611184610Salfred * 0: Success 612184610Salfred * < 0: Failure 613184610Salfred * > 0: Acutal length 614184610Salfred *------------------------------------------------------------------------*/ 615184610Salfredint 616184610Salfredusb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, 617184610Salfred uint8_t request, uint8_t requesttype, 618184610Salfred uint16_t value, uint16_t index, void *data, 619184610Salfred uint16_t size, uint32_t timeout) 620184610Salfred{ 621184610Salfred struct usb2_device_request req; 622184610Salfred struct urb *urb; 623184610Salfred int err; 624184610Salfred uint16_t actlen; 625184610Salfred uint8_t type; 626184610Salfred uint8_t addr; 627184610Salfred 628184610Salfred req.bmRequestType = requesttype; 629184610Salfred req.bRequest = request; 630184610Salfred USETW(req.wValue, value); 631184610Salfred USETW(req.wIndex, index); 632184610Salfred USETW(req.wLength, size); 633184610Salfred 634184610Salfred if (uhe == NULL) { 635184610Salfred return (-EINVAL); 636184610Salfred } 637184610Salfred type = (uhe->desc.bmAttributes & UE_XFERTYPE); 638184610Salfred addr = (uhe->desc.bEndpointAddress & UE_ADDR); 639184610Salfred 640184610Salfred if (type != UE_CONTROL) { 641184610Salfred return (-EINVAL); 642184610Salfred } 643184610Salfred if (addr == 0) { 644184610Salfred /* 645184610Salfred * The FreeBSD USB stack supports standard control 646184610Salfred * transfers on control endpoint zero: 647184610Salfred */ 648184610Salfred err = usb2_do_request_flags(dev->bsd_udev, 649184610Salfred &Giant, &req, data, USB_SHORT_XFER_OK, 650184610Salfred &actlen, timeout); 651184610Salfred if (err) { 652184610Salfred err = -EPIPE; 653184610Salfred } else { 654184610Salfred err = actlen; 655184610Salfred } 656184610Salfred return (err); 657184610Salfred } 658184610Salfred if (dev->bsd_udev->flags.usb2_mode != USB_MODE_HOST) { 659184610Salfred /* not supported */ 660184610Salfred return (-EINVAL); 661184610Salfred } 662184610Salfred err = usb_setup_endpoint(dev, uhe, 1 /* dummy */ ); 663184610Salfred 664184610Salfred /* 665184610Salfred * NOTE: we need to allocate real memory here so that we don't 666184610Salfred * transfer data to/from the stack! 667184610Salfred * 668184610Salfred * 0xFFFF is a FreeBSD specific magic value. 669184610Salfred */ 670184610Salfred urb = usb_alloc_urb(0xFFFF, size); 671184610Salfred if (urb == NULL) 672184610Salfred return (-ENOMEM); 673184610Salfred 674184610Salfred urb->dev = dev; 675184610Salfred urb->pipe = uhe; 676184610Salfred 677184610Salfred bcopy(&req, urb->setup_packet, sizeof(req)); 678184610Salfred 679184610Salfred if (size && (!(req.bmRequestType & UT_READ))) { 680184610Salfred /* move the data to a real buffer */ 681184610Salfred bcopy(data, USB_ADD_BYTES(urb->setup_packet, 682184610Salfred sizeof(req)), size); 683184610Salfred } 684184610Salfred err = usb_start_wait_urb(urb, timeout, &actlen); 685184610Salfred 686184610Salfred if (req.bmRequestType & UT_READ) { 687184610Salfred if (actlen) { 688184610Salfred bcopy(USB_ADD_BYTES(urb->setup_packet, 689184610Salfred sizeof(req)), data, actlen); 690184610Salfred } 691184610Salfred } 692184610Salfred usb_free_urb(urb); 693184610Salfred 694184610Salfred if (err == 0) { 695184610Salfred err = actlen; 696184610Salfred } 697184610Salfred return (err); 698184610Salfred} 699184610Salfred 700184610Salfred/*------------------------------------------------------------------------* 701184610Salfred * usb_set_interface 702184610Salfred * 703184610Salfred * The following function will select which alternate setting of an 704184610Salfred * USB interface you plan to use. By default alternate setting with 705184610Salfred * index zero is selected. Note that "iface_no" is not the interface 706184610Salfred * index, but rather the value of "bInterfaceNumber". 707184610Salfred *------------------------------------------------------------------------*/ 708184610Salfredint 709184610Salfredusb_set_interface(struct usb_device *dev, uint8_t iface_no, uint8_t alt_index) 710184610Salfred{ 711184610Salfred struct usb_interface *p_ui = usb_ifnum_to_if(dev, iface_no); 712184610Salfred int err; 713184610Salfred 714184610Salfred if (p_ui == NULL) 715184610Salfred return (-EINVAL); 716184610Salfred if (alt_index >= p_ui->num_altsetting) 717184610Salfred return (-EINVAL); 718184610Salfred usb_linux_cleanup_interface(dev, p_ui); 719184610Salfred err = -usb2_set_alt_interface_index(dev->bsd_udev, 720184610Salfred p_ui->bsd_iface_index, alt_index); 721184610Salfred if (err == 0) { 722184610Salfred p_ui->cur_altsetting = p_ui->altsetting + alt_index; 723184610Salfred } 724184610Salfred return (err); 725184610Salfred} 726184610Salfred 727184610Salfred/*------------------------------------------------------------------------* 728184610Salfred * usb_setup_endpoint 729184610Salfred * 730184610Salfred * The following function is an extension to the Linux USB API that 731184610Salfred * allows you to set a maximum buffer size for a given USB endpoint. 732184610Salfred * The maximum buffer size is per URB. If you don't call this function 733184610Salfred * to set a maximum buffer size, the endpoint will not be functional. 734184610Salfred * Note that for isochronous endpoints the maximum buffer size must be 735184610Salfred * a non-zero dummy, hence this function will base the maximum buffer 736184610Salfred * size on "wMaxPacketSize". 737184610Salfred *------------------------------------------------------------------------*/ 738184610Salfredint 739184610Salfredusb_setup_endpoint(struct usb_device *dev, 740184610Salfred struct usb_host_endpoint *uhe, uint32_t bufsize) 741184610Salfred{ 742184610Salfred struct usb2_config cfg[2]; 743184610Salfred uint8_t type = uhe->desc.bmAttributes & UE_XFERTYPE; 744184610Salfred uint8_t addr = uhe->desc.bEndpointAddress; 745184610Salfred 746184610Salfred if (uhe->fbsd_buf_size == bufsize) { 747184610Salfred /* optimize */ 748184610Salfred return (0); 749184610Salfred } 750184610Salfred usb2_transfer_unsetup(uhe->bsd_xfer, 2); 751184610Salfred 752184610Salfred uhe->fbsd_buf_size = bufsize; 753184610Salfred 754184610Salfred if (bufsize == 0) { 755184610Salfred return (0); 756184610Salfred } 757184610Salfred bzero(cfg, sizeof(cfg)); 758184610Salfred 759184610Salfred if (type == UE_ISOCHRONOUS) { 760184610Salfred 761184610Salfred /* 762184610Salfred * Isochronous transfers are special in that they don't fit 763184610Salfred * into the BULK/INTR/CONTROL transfer model. 764184610Salfred */ 765184610Salfred 766184610Salfred cfg[0].type = type; 767184610Salfred cfg[0].endpoint = addr & UE_ADDR; 768184610Salfred cfg[0].direction = addr & (UE_DIR_OUT | UE_DIR_IN); 769184610Salfred cfg[0].mh.callback = &usb_linux_isoc_callback; 770184610Salfred cfg[0].mh.bufsize = 0; /* use wMaxPacketSize */ 771184610Salfred cfg[0].mh.frames = usb_max_isoc_frames(dev); 772184610Salfred cfg[0].mh.flags.proxy_buffer = 1; 773184610Salfred#if 0 774184610Salfred /* 775184610Salfred * The Linux USB API allows non back-to-back 776184610Salfred * isochronous frames which we do not support. If the 777184610Salfred * isochronous frames are not back-to-back we need to 778184610Salfred * do a copy, and then we need a buffer for 779184610Salfred * that. Enable this at your own risk. 780184610Salfred */ 781184610Salfred cfg[0].mh.flags.ext_buffer = 1; 782184610Salfred#endif 783184610Salfred cfg[0].mh.flags.short_xfer_ok = 1; 784184610Salfred 785184610Salfred bcopy(cfg, cfg + 1, sizeof(*cfg)); 786184610Salfred 787184610Salfred /* Allocate and setup two generic FreeBSD USB transfers */ 788184610Salfred 789184610Salfred if (usb2_transfer_setup(dev->bsd_udev, &uhe->bsd_iface_index, 790184610Salfred uhe->bsd_xfer, cfg, 2, uhe, &Giant)) { 791184610Salfred return (-EINVAL); 792184610Salfred } 793184610Salfred } else { 794184610Salfred if (bufsize > (1 << 22)) { 795184610Salfred /* limit buffer size */ 796184610Salfred bufsize = (1 << 22); 797184610Salfred } 798184610Salfred /* Allocate and setup one generic FreeBSD USB transfer */ 799184610Salfred 800184610Salfred cfg[0].type = type; 801184610Salfred cfg[0].endpoint = addr & UE_ADDR; 802184610Salfred cfg[0].direction = addr & (UE_DIR_OUT | UE_DIR_IN); 803184610Salfred cfg[0].mh.callback = &usb_linux_non_isoc_callback; 804184610Salfred cfg[0].mh.bufsize = bufsize; 805184610Salfred cfg[0].mh.flags.ext_buffer = 1; /* enable zero-copy */ 806184610Salfred cfg[0].mh.flags.proxy_buffer = 1; 807184610Salfred cfg[0].mh.flags.short_xfer_ok = 1; 808184610Salfred 809184610Salfred if (usb2_transfer_setup(dev->bsd_udev, &uhe->bsd_iface_index, 810184610Salfred uhe->bsd_xfer, cfg, 1, uhe, &Giant)) { 811184610Salfred return (-EINVAL); 812184610Salfred } 813184610Salfred } 814184610Salfred return (0); 815184610Salfred} 816184610Salfred 817184610Salfred/*------------------------------------------------------------------------* 818184610Salfred * usb_linux_create_usb_device 819184610Salfred * 820184610Salfred * The following function is used to build up a per USB device 821184610Salfred * structure tree, that mimics the Linux one. The root structure 822184610Salfred * is returned by this function. 823184610Salfred *------------------------------------------------------------------------*/ 824184610Salfredstatic struct usb_device * 825184610Salfredusb_linux_create_usb_device(struct usb2_device *udev, device_t dev) 826184610Salfred{ 827184610Salfred struct usb2_config_descriptor *cd = usb2_get_config_descriptor(udev); 828184610Salfred struct usb2_descriptor *desc; 829184610Salfred struct usb2_interface_descriptor *id; 830184610Salfred struct usb2_endpoint_descriptor *ed; 831184610Salfred struct usb_device *p_ud = NULL; 832184610Salfred struct usb_interface *p_ui = NULL; 833184610Salfred struct usb_host_interface *p_uhi = NULL; 834184610Salfred struct usb_host_endpoint *p_uhe = NULL; 835184610Salfred uint32_t size; 836184610Salfred uint16_t niface_total; 837184610Salfred uint16_t nedesc; 838184610Salfred uint16_t iface_no_curr; 839184610Salfred uint16_t iface_index; 840184610Salfred uint8_t pass; 841184610Salfred uint8_t iface_no; 842184610Salfred 843184610Salfred /* 844184610Salfred * We do two passes. One pass for computing necessary memory size 845184610Salfred * and one pass to initialize all the allocated memory structures. 846184610Salfred */ 847184610Salfred for (pass = 0; pass < 2; pass++) { 848184610Salfred 849184610Salfred iface_no_curr = 0 - 1; 850184610Salfred niface_total = 0; 851184610Salfred iface_index = 0; 852184610Salfred nedesc = 0; 853184610Salfred desc = NULL; 854184610Salfred 855184610Salfred /* 856184610Salfred * Iterate over all the USB descriptors. Use the USB config 857184610Salfred * descriptor pointer provided by the FreeBSD USB stack. 858184610Salfred */ 859184610Salfred while ((desc = usb2_desc_foreach(cd, desc))) { 860184610Salfred 861184610Salfred /* 862184610Salfred * Build up a tree according to the descriptors we 863184610Salfred * find: 864184610Salfred */ 865184610Salfred switch (desc->bDescriptorType) { 866184610Salfred case UDESC_DEVICE: 867184610Salfred break; 868184610Salfred 869184610Salfred case UDESC_ENDPOINT: 870184610Salfred ed = (void *)desc; 871184610Salfred if ((ed->bLength < sizeof(*ed)) || 872184610Salfred (iface_index == 0)) 873184610Salfred break; 874184610Salfred if (p_uhe) { 875184610Salfred bcopy(ed, &p_uhe->desc, sizeof(p_uhe->desc)); 876184610Salfred p_uhe->bsd_iface_index = iface_index - 1; 877184610Salfred p_uhe++; 878184610Salfred } 879184610Salfred if (p_uhi) { 880184610Salfred (p_uhi - 1)->desc.bNumEndpoints++; 881184610Salfred } 882184610Salfred nedesc++; 883184610Salfred break; 884184610Salfred 885184610Salfred case UDESC_INTERFACE: 886184610Salfred id = (void *)desc; 887184610Salfred if (id->bLength < sizeof(*id)) 888184610Salfred break; 889184610Salfred if (p_uhi) { 890184610Salfred bcopy(id, &p_uhi->desc, sizeof(p_uhi->desc)); 891184610Salfred p_uhi->desc.bNumEndpoints = 0; 892184610Salfred p_uhi->endpoint = p_uhe; 893184610Salfred p_uhi->string = ""; 894184610Salfred p_uhi->bsd_iface_index = iface_index; 895184610Salfred p_uhi++; 896184610Salfred } 897184610Salfred iface_no = id->bInterfaceNumber; 898184610Salfred niface_total++; 899184610Salfred if (iface_no_curr != iface_no) { 900184610Salfred if (p_ui) { 901184610Salfred p_ui->altsetting = p_uhi - 1; 902184610Salfred p_ui->cur_altsetting = p_uhi - 1; 903184610Salfred p_ui->num_altsetting = 1; 904184610Salfred p_ui->bsd_iface_index = iface_index; 905184610Salfred p_ui->linux_udev = p_ud; 906184610Salfred p_ui++; 907184610Salfred } 908184610Salfred iface_no_curr = iface_no; 909184610Salfred iface_index++; 910184610Salfred } else { 911184610Salfred if (p_ui) { 912184610Salfred (p_ui - 1)->num_altsetting++; 913184610Salfred } 914184610Salfred } 915184610Salfred break; 916184610Salfred 917184610Salfred default: 918184610Salfred break; 919184610Salfred } 920184610Salfred } 921184610Salfred 922184610Salfred if (pass == 0) { 923184610Salfred 924184610Salfred size = ((sizeof(*p_ud) * 1) + 925184610Salfred (sizeof(*p_uhe) * nedesc) + 926184610Salfred (sizeof(*p_ui) * iface_index) + 927184610Salfred (sizeof(*p_uhi) * niface_total)); 928184610Salfred 929184610Salfred p_ud = malloc(size, M_USBDEV, M_WAITOK | M_ZERO); 930184610Salfred if (p_ud == NULL) { 931184610Salfred goto done; 932184610Salfred } 933184610Salfred p_uhe = (void *)(p_ud + 1); 934184610Salfred p_ui = (void *)(p_uhe + nedesc); 935184610Salfred p_uhi = (void *)(p_ui + iface_index); 936184610Salfred 937184610Salfred p_ud->product = ""; 938184610Salfred p_ud->manufacturer = ""; 939184610Salfred p_ud->serial = ""; 940184610Salfred p_ud->speed = usb2_get_speed(udev); 941184610Salfred p_ud->bsd_udev = udev; 942184610Salfred p_ud->bsd_iface_start = p_ui; 943184610Salfred p_ud->bsd_iface_end = p_ui + iface_index; 944184610Salfred p_ud->bsd_endpoint_start = p_uhe; 945184610Salfred p_ud->bsd_endpoint_end = p_uhe + nedesc; 946184610Salfred p_ud->devnum = device_get_unit(dev); 947184610Salfred bcopy(&udev->ddesc, &p_ud->descriptor, 948184610Salfred sizeof(p_ud->descriptor)); 949184610Salfred bcopy(udev->default_pipe.edesc, &p_ud->ep0.desc, 950184610Salfred sizeof(p_ud->ep0.desc)); 951184610Salfred } 952184610Salfred } 953184610Salfreddone: 954184610Salfred return (p_ud); 955184610Salfred} 956184610Salfred 957184610Salfred/*------------------------------------------------------------------------* 958184610Salfred * usb_alloc_urb 959184610Salfred * 960184610Salfred * This function should always be used when you allocate an URB for 961184610Salfred * use with the USB Linux stack. In case of an isochronous transfer 962184610Salfred * you must specifiy the maximum number of "iso_packets" which you 963184610Salfred * plan to transfer per URB. This function is always blocking, and 964184610Salfred * "mem_flags" are not regarded like on Linux. 965184610Salfred *------------------------------------------------------------------------*/ 966184610Salfredstruct urb * 967184610Salfredusb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags) 968184610Salfred{ 969184610Salfred struct urb *urb; 970184610Salfred uint32_t size; 971184610Salfred 972184610Salfred if (iso_packets == 0xFFFF) { 973184610Salfred /* 974184610Salfred * FreeBSD specific magic value to ask for control transfer 975184610Salfred * memory allocation: 976184610Salfred */ 977184610Salfred size = sizeof(*urb) + sizeof(struct usb2_device_request) + mem_flags; 978184610Salfred } else { 979184610Salfred size = sizeof(*urb) + (iso_packets * sizeof(urb->iso_frame_desc[0])); 980184610Salfred } 981184610Salfred 982184610Salfred urb = malloc(size, M_USBDEV, M_WAITOK | M_ZERO); 983184610Salfred if (urb) { 984184610Salfred 985184610Salfred usb2_cv_init(&urb->cv_wait, "URBWAIT"); 986184610Salfred if (iso_packets == 0xFFFF) { 987184610Salfred urb->setup_packet = (void *)(urb + 1); 988184610Salfred urb->transfer_buffer = (void *)(urb->setup_packet + 989184610Salfred sizeof(struct usb2_device_request)); 990184610Salfred } else { 991184610Salfred urb->number_of_packets = iso_packets; 992184610Salfred } 993184610Salfred } 994184610Salfred return (urb); 995184610Salfred} 996184610Salfred 997184610Salfred/*------------------------------------------------------------------------* 998184610Salfred * usb_find_host_endpoint 999184610Salfred * 1000184610Salfred * The following function will return the Linux USB host endpoint 1001184610Salfred * structure that matches the given endpoint type and endpoint 1002184610Salfred * value. If no match is found, NULL is returned. This function is not 1003184610Salfred * part of the Linux USB API and is only used internally. 1004184610Salfred *------------------------------------------------------------------------*/ 1005184610Salfredstruct usb_host_endpoint * 1006184610Salfredusb_find_host_endpoint(struct usb_device *dev, uint8_t type, uint8_t ep) 1007184610Salfred{ 1008184610Salfred struct usb_host_endpoint *uhe; 1009184610Salfred struct usb_host_endpoint *uhe_end; 1010184610Salfred struct usb_host_interface *uhi; 1011184610Salfred struct usb_interface *ui; 1012184610Salfred uint8_t ea; 1013184610Salfred uint8_t at; 1014184610Salfred uint8_t mask; 1015184610Salfred 1016184610Salfred if (dev == NULL) { 1017184610Salfred return (NULL); 1018184610Salfred } 1019184610Salfred if (type == UE_CONTROL) { 1020184610Salfred mask = UE_ADDR; 1021184610Salfred } else { 1022184610Salfred mask = (UE_DIR_IN | UE_DIR_OUT | UE_ADDR); 1023184610Salfred } 1024184610Salfred 1025184610Salfred ep &= mask; 1026184610Salfred 1027184610Salfred /* 1028184610Salfred * Iterate over all the interfaces searching the selected alternate 1029184610Salfred * setting only, and all belonging endpoints. 1030184610Salfred */ 1031184610Salfred for (ui = dev->bsd_iface_start; 1032184610Salfred ui != dev->bsd_iface_end; 1033184610Salfred ui++) { 1034184610Salfred uhi = ui->cur_altsetting; 1035184610Salfred if (uhi) { 1036184610Salfred uhe_end = uhi->endpoint + uhi->desc.bNumEndpoints; 1037184610Salfred for (uhe = uhi->endpoint; 1038184610Salfred uhe != uhe_end; 1039184610Salfred uhe++) { 1040184610Salfred ea = uhe->desc.bEndpointAddress; 1041184610Salfred at = uhe->desc.bmAttributes; 1042184610Salfred 1043184610Salfred if (((ea & mask) == ep) && 1044184610Salfred ((at & UE_XFERTYPE) == type)) { 1045184610Salfred return (uhe); 1046184610Salfred } 1047184610Salfred } 1048184610Salfred } 1049184610Salfred } 1050184610Salfred 1051184610Salfred if ((type == UE_CONTROL) && ((ep & UE_ADDR) == 0)) { 1052184610Salfred return (&dev->ep0); 1053184610Salfred } 1054184610Salfred return (NULL); 1055184610Salfred} 1056184610Salfred 1057184610Salfred/*------------------------------------------------------------------------* 1058184610Salfred * usb_altnum_to_altsetting 1059184610Salfred * 1060184610Salfred * The following function returns a pointer to an alternate setting by 1061184610Salfred * index given a "usb_interface" pointer. If the alternate setting by 1062184610Salfred * index does not exist, NULL is returned. And alternate setting is a 1063184610Salfred * variant of an interface, but usually with slightly different 1064184610Salfred * characteristics. 1065184610Salfred *------------------------------------------------------------------------*/ 1066184610Salfredstruct usb_host_interface * 1067184610Salfredusb_altnum_to_altsetting(const struct usb_interface *intf, uint8_t alt_index) 1068184610Salfred{ 1069184610Salfred if (alt_index >= intf->num_altsetting) { 1070184610Salfred return (NULL); 1071184610Salfred } 1072184610Salfred return (intf->altsetting + alt_index); 1073184610Salfred} 1074184610Salfred 1075184610Salfred/*------------------------------------------------------------------------* 1076184610Salfred * usb_ifnum_to_if 1077184610Salfred * 1078184610Salfred * The following function searches up an USB interface by 1079184610Salfred * "bInterfaceNumber". If no match is found, NULL is returned. 1080184610Salfred *------------------------------------------------------------------------*/ 1081184610Salfredstruct usb_interface * 1082184610Salfredusb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no) 1083184610Salfred{ 1084184610Salfred struct usb_interface *p_ui; 1085184610Salfred 1086184610Salfred for (p_ui = dev->bsd_iface_start; 1087184610Salfred p_ui != dev->bsd_iface_end; 1088184610Salfred p_ui++) { 1089184610Salfred if ((p_ui->num_altsetting > 0) && 1090184610Salfred (p_ui->altsetting->desc.bInterfaceNumber == iface_no)) { 1091184610Salfred return (p_ui); 1092184610Salfred } 1093184610Salfred } 1094184610Salfred return (NULL); 1095184610Salfred} 1096184610Salfred 1097184610Salfred/*------------------------------------------------------------------------* 1098184610Salfred * usb_buffer_alloc 1099184610Salfred *------------------------------------------------------------------------*/ 1100184610Salfredvoid * 1101184610Salfredusb_buffer_alloc(struct usb_device *dev, uint32_t size, uint16_t mem_flags, uint8_t *dma_addr) 1102184610Salfred{ 1103184610Salfred return (malloc(size, M_USBDEV, M_WAITOK | M_ZERO)); 1104184610Salfred} 1105184610Salfred 1106184610Salfred/*------------------------------------------------------------------------* 1107184610Salfred * usb_get_intfdata 1108184610Salfred *------------------------------------------------------------------------*/ 1109184610Salfredvoid * 1110184610Salfredusb_get_intfdata(struct usb_interface *intf) 1111184610Salfred{ 1112184610Salfred return (intf->bsd_priv_sc); 1113184610Salfred} 1114184610Salfred 1115184610Salfred/*------------------------------------------------------------------------* 1116184610Salfred * usb_linux_register 1117184610Salfred * 1118184610Salfred * The following function is used by the "USB_DRIVER_EXPORT()" macro, 1119184610Salfred * and is used to register a Linux USB driver, so that its 1120184610Salfred * "usb_device_id" structures gets searched a probe time. This 1121184610Salfred * function is not part of the Linux USB API, and is for internal use 1122184610Salfred * only. 1123184610Salfred *------------------------------------------------------------------------*/ 1124184610Salfredvoid 1125184610Salfredusb_linux_register(void *arg) 1126184610Salfred{ 1127184610Salfred struct usb_driver *drv = arg; 1128184610Salfred 1129184610Salfred mtx_lock(&Giant); 1130184610Salfred LIST_INSERT_HEAD(&usb_linux_driver_list, drv, linux_driver_list); 1131184610Salfred mtx_unlock(&Giant); 1132184610Salfred 1133184610Salfred usb2_needs_explore_all(); 1134184610Salfred return; 1135184610Salfred} 1136184610Salfred 1137184610Salfred/*------------------------------------------------------------------------* 1138184610Salfred * usb_linux_deregister 1139184610Salfred * 1140184610Salfred * The following function is used by the "USB_DRIVER_EXPORT()" macro, 1141184610Salfred * and is used to deregister a Linux USB driver. This function will 1142184610Salfred * ensure that all driver instances belonging to the Linux USB device 1143184610Salfred * driver in question, gets detached before the driver is 1144184610Salfred * unloaded. This function is not part of the Linux USB API, and is 1145184610Salfred * for internal use only. 1146184610Salfred *------------------------------------------------------------------------*/ 1147184610Salfredvoid 1148184610Salfredusb_linux_deregister(void *arg) 1149184610Salfred{ 1150184610Salfred struct usb_driver *drv = arg; 1151184610Salfred struct usb_linux_softc *sc; 1152184610Salfred 1153184610Salfredrepeat: 1154184610Salfred mtx_lock(&Giant); 1155184610Salfred LIST_FOREACH(sc, &usb_linux_attached_list, sc_attached_list) { 1156184610Salfred if (sc->sc_udrv == drv) { 1157184610Salfred mtx_unlock(&Giant); 1158184610Salfred device_detach(sc->sc_fbsd_dev); 1159184610Salfred goto repeat; 1160184610Salfred } 1161184610Salfred } 1162184610Salfred LIST_REMOVE(drv, linux_driver_list); 1163184610Salfred mtx_unlock(&Giant); 1164184610Salfred return; 1165184610Salfred} 1166184610Salfred 1167184610Salfred/*------------------------------------------------------------------------* 1168184610Salfred * usb_linux_free_device 1169184610Salfred * 1170184610Salfred * The following function is only used by the FreeBSD USB stack, to 1171184610Salfred * cleanup and free memory after that a Linux USB device was attached. 1172184610Salfred *------------------------------------------------------------------------*/ 1173184610Salfredvoid 1174184610Salfredusb_linux_free_device(struct usb_device *dev) 1175184610Salfred{ 1176184610Salfred struct usb_host_endpoint *uhe; 1177184610Salfred struct usb_host_endpoint *uhe_end; 1178184610Salfred int err; 1179184610Salfred 1180184610Salfred uhe = dev->bsd_endpoint_start; 1181184610Salfred uhe_end = dev->bsd_endpoint_end; 1182184610Salfred while (uhe != uhe_end) { 1183184610Salfred err = usb_setup_endpoint(dev, uhe, 0); 1184184610Salfred uhe++; 1185184610Salfred } 1186184610Salfred err = usb_setup_endpoint(dev, &dev->ep0, 0); 1187184610Salfred free(dev, M_USBDEV); 1188184610Salfred return; 1189184610Salfred} 1190184610Salfred 1191184610Salfred/*------------------------------------------------------------------------* 1192184610Salfred * usb_buffer_free 1193184610Salfred *------------------------------------------------------------------------*/ 1194184610Salfredvoid 1195184610Salfredusb_buffer_free(struct usb_device *dev, uint32_t size, 1196184610Salfred void *addr, uint8_t dma_addr) 1197184610Salfred{ 1198184610Salfred free(addr, M_USBDEV); 1199184610Salfred return; 1200184610Salfred} 1201184610Salfred 1202184610Salfred/*------------------------------------------------------------------------* 1203184610Salfred * usb_free_urb 1204184610Salfred *------------------------------------------------------------------------*/ 1205184610Salfredvoid 1206184610Salfredusb_free_urb(struct urb *urb) 1207184610Salfred{ 1208184610Salfred if (urb == NULL) { 1209184610Salfred return; 1210184610Salfred } 1211184610Salfred /* make sure that the current URB is not active */ 1212184610Salfred usb_kill_urb(urb); 1213184610Salfred 1214184610Salfred /* destroy condition variable */ 1215184610Salfred usb2_cv_destroy(&urb->cv_wait); 1216184610Salfred 1217184610Salfred /* just free it */ 1218184610Salfred free(urb, M_USBDEV); 1219184610Salfred return; 1220184610Salfred} 1221184610Salfred 1222184610Salfred/*------------------------------------------------------------------------* 1223184610Salfred * usb_init_urb 1224184610Salfred * 1225184610Salfred * The following function can be used to initialize a custom URB. It 1226184610Salfred * is not recommended to use this function. Use "usb_alloc_urb()" 1227184610Salfred * instead. 1228184610Salfred *------------------------------------------------------------------------*/ 1229184610Salfredvoid 1230184610Salfredusb_init_urb(struct urb *urb) 1231184610Salfred{ 1232184610Salfred if (urb == NULL) { 1233184610Salfred return; 1234184610Salfred } 1235184610Salfred bzero(urb, sizeof(*urb)); 1236184610Salfred return; 1237184610Salfred} 1238184610Salfred 1239184610Salfred/*------------------------------------------------------------------------* 1240184610Salfred * usb_kill_urb 1241184610Salfred *------------------------------------------------------------------------*/ 1242184610Salfredvoid 1243184610Salfredusb_kill_urb(struct urb *urb) 1244184610Salfred{ 1245184610Salfred if (usb_unlink_urb_sub(urb, 1)) { 1246184610Salfred /* ignore */ 1247184610Salfred } 1248184610Salfred return; 1249184610Salfred} 1250184610Salfred 1251184610Salfred/*------------------------------------------------------------------------* 1252184610Salfred * usb_set_intfdata 1253184610Salfred * 1254184610Salfred * The following function sets the per Linux USB interface private 1255184610Salfred * data pointer. It is used by most Linux USB device drivers. 1256184610Salfred *------------------------------------------------------------------------*/ 1257184610Salfredvoid 1258184610Salfredusb_set_intfdata(struct usb_interface *intf, void *data) 1259184610Salfred{ 1260184610Salfred intf->bsd_priv_sc = data; 1261184610Salfred return; 1262184610Salfred} 1263184610Salfred 1264184610Salfred/*------------------------------------------------------------------------* 1265184610Salfred * usb_linux_cleanup_interface 1266184610Salfred * 1267184610Salfred * The following function will release all FreeBSD USB transfers 1268184610Salfred * associated with a Linux USB interface. It is for internal use only. 1269184610Salfred *------------------------------------------------------------------------*/ 1270184610Salfredstatic void 1271184610Salfredusb_linux_cleanup_interface(struct usb_device *dev, struct usb_interface *iface) 1272184610Salfred{ 1273184610Salfred struct usb_host_interface *uhi; 1274184610Salfred struct usb_host_interface *uhi_end; 1275184610Salfred struct usb_host_endpoint *uhe; 1276184610Salfred struct usb_host_endpoint *uhe_end; 1277184610Salfred int err; 1278184610Salfred 1279184610Salfred uhi = iface->altsetting; 1280184610Salfred uhi_end = iface->altsetting + iface->num_altsetting; 1281184610Salfred while (uhi != uhi_end) { 1282184610Salfred uhe = uhi->endpoint; 1283184610Salfred uhe_end = uhi->endpoint + uhi->desc.bNumEndpoints; 1284184610Salfred while (uhe != uhe_end) { 1285184610Salfred err = usb_setup_endpoint(dev, uhe, 0); 1286184610Salfred uhe++; 1287184610Salfred } 1288184610Salfred uhi++; 1289184610Salfred } 1290184610Salfred return; 1291184610Salfred} 1292184610Salfred 1293184610Salfred/*------------------------------------------------------------------------* 1294184610Salfred * usb_linux_wait_complete 1295184610Salfred * 1296184610Salfred * The following function is used by "usb_start_wait_urb()" to wake it 1297184610Salfred * up, when an USB transfer has finished. 1298184610Salfred *------------------------------------------------------------------------*/ 1299184610Salfredstatic void 1300184610Salfredusb_linux_wait_complete(struct urb *urb) 1301184610Salfred{ 1302184610Salfred if (urb->transfer_flags & URB_IS_SLEEPING) { 1303184610Salfred usb2_cv_signal(&urb->cv_wait); 1304184610Salfred } 1305184610Salfred urb->transfer_flags &= ~URB_WAIT_WAKEUP; 1306184610Salfred return; 1307184610Salfred} 1308184610Salfred 1309184610Salfred/*------------------------------------------------------------------------* 1310184610Salfred * usb_linux_complete 1311184610Salfred *------------------------------------------------------------------------*/ 1312184610Salfredstatic void 1313184610Salfredusb_linux_complete(struct usb2_xfer *xfer) 1314184610Salfred{ 1315184610Salfred struct urb *urb; 1316184610Salfred 1317184610Salfred urb = xfer->priv_fifo; 1318184610Salfred xfer->priv_fifo = NULL; 1319184610Salfred if (urb->complete) { 1320184610Salfred (urb->complete) (urb); 1321184610Salfred } 1322184610Salfred return; 1323184610Salfred} 1324184610Salfred 1325184610Salfred/*------------------------------------------------------------------------* 1326184610Salfred * usb_linux_isoc_callback 1327184610Salfred * 1328184610Salfred * The following is the FreeBSD isochronous USB callback. Isochronous 1329184610Salfred * frames are USB packets transferred 1000 or 8000 times per second, 1330184610Salfred * depending on whether a full- or high- speed USB transfer is 1331184610Salfred * used. 1332184610Salfred *------------------------------------------------------------------------*/ 1333184610Salfredstatic void 1334184610Salfredusb_linux_isoc_callback(struct usb2_xfer *xfer) 1335184610Salfred{ 1336184610Salfred uint32_t max_frame = xfer->max_frame_size; 1337184610Salfred uint32_t offset; 1338184610Salfred uint16_t x; 1339184610Salfred struct urb *urb = xfer->priv_fifo; 1340184610Salfred struct usb_host_endpoint *uhe = xfer->priv_sc; 1341184610Salfred struct usb_iso_packet_descriptor *uipd; 1342184610Salfred 1343184610Salfred DPRINTF("\n"); 1344184610Salfred 1345184610Salfred switch (USB_GET_STATE(xfer)) { 1346184610Salfred case USB_ST_TRANSFERRED: 1347184610Salfred 1348184610Salfred if (urb->bsd_isread) { 1349184610Salfred 1350184610Salfred /* copy in data with regard to the URB */ 1351184610Salfred 1352184610Salfred offset = 0; 1353184610Salfred 1354184610Salfred for (x = 0; x < urb->number_of_packets; x++) { 1355184610Salfred uipd = urb->iso_frame_desc + x; 1356184610Salfred uipd->actual_length = xfer->frlengths[x]; 1357184610Salfred uipd->status = 0; 1358184610Salfred if (!xfer->flags.ext_buffer) { 1359184610Salfred usb2_copy_out(xfer->frbuffers, offset, 1360184610Salfred USB_ADD_BYTES(urb->transfer_buffer, 1361184610Salfred uipd->offset), uipd->actual_length); 1362184610Salfred } 1363184610Salfred offset += max_frame; 1364184610Salfred } 1365184610Salfred } else { 1366184610Salfred for (x = 0; x < urb->number_of_packets; x++) { 1367184610Salfred uipd = urb->iso_frame_desc + x; 1368184610Salfred uipd->actual_length = xfer->frlengths[x]; 1369184610Salfred uipd->status = 0; 1370184610Salfred } 1371184610Salfred } 1372184610Salfred 1373184610Salfred urb->actual_length = xfer->actlen; 1374184610Salfred 1375184610Salfred /* check for short transfer */ 1376184610Salfred if (xfer->actlen < xfer->sumlen) { 1377184610Salfred /* short transfer */ 1378184610Salfred if (urb->transfer_flags & URB_SHORT_NOT_OK) { 1379184610Salfred urb->status = -EPIPE; /* XXX should be 1380184610Salfred * EREMOTEIO */ 1381184610Salfred } else { 1382184610Salfred urb->status = 0; 1383184610Salfred } 1384184610Salfred } else { 1385184610Salfred /* success */ 1386184610Salfred urb->status = 0; 1387184610Salfred } 1388184610Salfred 1389184610Salfred /* call callback */ 1390184610Salfred usb_linux_complete(xfer); 1391184610Salfred 1392184610Salfred case USB_ST_SETUP: 1393184610Salfredtr_setup: 1394184610Salfred 1395184610Salfred if (xfer->priv_fifo == NULL) { 1396184610Salfred 1397184610Salfred /* get next transfer */ 1398184610Salfred urb = TAILQ_FIRST(&uhe->bsd_urb_list); 1399184610Salfred if (urb == NULL) { 1400184610Salfred /* nothing to do */ 1401184610Salfred return; 1402184610Salfred } 1403184610Salfred TAILQ_REMOVE(&uhe->bsd_urb_list, urb, bsd_urb_list); 1404184610Salfred urb->bsd_urb_list.tqe_prev = NULL; 1405184610Salfred 1406184610Salfred x = xfer->max_frame_count; 1407184610Salfred if (urb->number_of_packets > x) { 1408184610Salfred /* XXX simply truncate the transfer */ 1409184610Salfred urb->number_of_packets = x; 1410184610Salfred } 1411184610Salfred } else { 1412184610Salfred DPRINTF("Already got a transfer\n"); 1413184610Salfred 1414184610Salfred /* already got a transfer (should not happen) */ 1415184610Salfred urb = xfer->priv_fifo; 1416184610Salfred } 1417184610Salfred 1418184610Salfred urb->bsd_isread = (uhe->desc.bEndpointAddress & UE_DIR_IN) ? 1 : 0; 1419184610Salfred 1420184610Salfred if (!(urb->bsd_isread)) { 1421184610Salfred 1422184610Salfred /* copy out data with regard to the URB */ 1423184610Salfred 1424184610Salfred offset = 0; 1425184610Salfred 1426184610Salfred for (x = 0; x < urb->number_of_packets; x++) { 1427184610Salfred uipd = urb->iso_frame_desc + x; 1428184610Salfred xfer->frlengths[x] = uipd->length; 1429184610Salfred if (!xfer->flags.ext_buffer) { 1430184610Salfred usb2_copy_in(xfer->frbuffers, offset, 1431184610Salfred USB_ADD_BYTES(urb->transfer_buffer, 1432184610Salfred uipd->offset), uipd->length); 1433184610Salfred } 1434184610Salfred offset += uipd->length; 1435184610Salfred } 1436184610Salfred } else { 1437184610Salfred 1438184610Salfred /* 1439184610Salfred * compute the transfer length into the "offset" 1440184610Salfred * variable 1441184610Salfred */ 1442184610Salfred 1443184610Salfred offset = urb->number_of_packets * max_frame; 1444184610Salfred 1445184610Salfred /* setup "frlengths" array */ 1446184610Salfred 1447184610Salfred for (x = 0; x < urb->number_of_packets; x++) { 1448184610Salfred uipd = urb->iso_frame_desc + x; 1449184610Salfred xfer->frlengths[x] = max_frame; 1450184610Salfred } 1451184610Salfred } 1452184610Salfred 1453184610Salfred if (xfer->flags.ext_buffer) { 1454184610Salfred /* set virtual address to load */ 1455184610Salfred usb2_set_frame_data(xfer, 1456184610Salfred urb->transfer_buffer, 0); 1457184610Salfred } 1458184610Salfred xfer->priv_fifo = urb; 1459184610Salfred xfer->flags.force_short_xfer = 0; 1460184610Salfred xfer->timeout = urb->timeout; 1461184610Salfred xfer->nframes = urb->number_of_packets; 1462184610Salfred usb2_start_hardware(xfer); 1463184610Salfred return; 1464184610Salfred 1465184610Salfred default: /* Error */ 1466184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 1467184610Salfred urb->status = -ECONNRESET; 1468184610Salfred } else { 1469184610Salfred urb->status = -EPIPE; /* stalled */ 1470184610Salfred } 1471184610Salfred 1472184610Salfred /* Set zero for "actual_length" */ 1473184610Salfred urb->actual_length = 0; 1474184610Salfred 1475184610Salfred /* Set zero for "actual_length" */ 1476184610Salfred for (x = 0; x < urb->number_of_packets; x++) { 1477184610Salfred urb->iso_frame_desc[x].actual_length = 0; 1478184610Salfred } 1479184610Salfred 1480184610Salfred /* call callback */ 1481184610Salfred usb_linux_complete(xfer); 1482184610Salfred 1483184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 1484184610Salfred /* we need to return in this case */ 1485184610Salfred return; 1486184610Salfred } 1487184610Salfred goto tr_setup; 1488184610Salfred 1489184610Salfred } 1490184610Salfred} 1491184610Salfred 1492184610Salfred/*------------------------------------------------------------------------* 1493184610Salfred * usb_linux_non_isoc_callback 1494184610Salfred * 1495184610Salfred * The following is the FreeBSD BULK/INTERRUPT and CONTROL USB 1496184610Salfred * callback. It dequeues Linux USB stack compatible URB's, transforms 1497184610Salfred * the URB fields into a FreeBSD USB transfer, and defragments the USB 1498184610Salfred * transfer as required. When the transfer is complete the "complete" 1499184610Salfred * callback is called. 1500184610Salfred *------------------------------------------------------------------------*/ 1501184610Salfredstatic void 1502184610Salfredusb_linux_non_isoc_callback(struct usb2_xfer *xfer) 1503184610Salfred{ 1504184610Salfred enum { 1505184610Salfred REQ_SIZE = sizeof(struct usb2_device_request) 1506184610Salfred }; 1507184610Salfred struct urb *urb = xfer->priv_fifo; 1508184610Salfred struct usb_host_endpoint *uhe = xfer->priv_sc; 1509184610Salfred uint8_t *ptr; 1510184610Salfred uint32_t max_bulk = xfer->max_data_length; 1511184610Salfred uint8_t data_frame = xfer->flags_int.control_xfr ? 1 : 0; 1512184610Salfred 1513184610Salfred DPRINTF("\n"); 1514184610Salfred 1515184610Salfred switch (USB_GET_STATE(xfer)) { 1516184610Salfred case USB_ST_TRANSFERRED: 1517184610Salfred 1518184610Salfred if (xfer->flags_int.control_xfr) { 1519184610Salfred 1520184610Salfred /* don't transfer the setup packet again: */ 1521184610Salfred 1522184610Salfred xfer->frlengths[0] = 0; 1523184610Salfred } 1524184610Salfred if (urb->bsd_isread && (!xfer->flags.ext_buffer)) { 1525184610Salfred /* copy in data with regard to the URB */ 1526184610Salfred usb2_copy_out(xfer->frbuffers + data_frame, 0, 1527184610Salfred urb->bsd_data_ptr, xfer->frlengths[data_frame]); 1528184610Salfred } 1529184610Salfred urb->bsd_length_rem -= xfer->frlengths[data_frame]; 1530184610Salfred urb->bsd_data_ptr += xfer->frlengths[data_frame]; 1531184610Salfred urb->actual_length += xfer->frlengths[data_frame]; 1532184610Salfred 1533184610Salfred /* check for short transfer */ 1534184610Salfred if (xfer->actlen < xfer->sumlen) { 1535184610Salfred urb->bsd_length_rem = 0; 1536184610Salfred 1537184610Salfred /* short transfer */ 1538184610Salfred if (urb->transfer_flags & URB_SHORT_NOT_OK) { 1539184610Salfred urb->status = -EPIPE; 1540184610Salfred } else { 1541184610Salfred urb->status = 0; 1542184610Salfred } 1543184610Salfred } else { 1544184610Salfred /* check remainder */ 1545184610Salfred if (urb->bsd_length_rem > 0) { 1546184610Salfred goto setup_bulk; 1547184610Salfred } 1548184610Salfred /* success */ 1549184610Salfred urb->status = 0; 1550184610Salfred } 1551184610Salfred 1552184610Salfred /* call callback */ 1553184610Salfred usb_linux_complete(xfer); 1554184610Salfred 1555184610Salfred case USB_ST_SETUP: 1556184610Salfredtr_setup: 1557184610Salfred /* get next transfer */ 1558184610Salfred urb = TAILQ_FIRST(&uhe->bsd_urb_list); 1559184610Salfred if (urb == NULL) { 1560184610Salfred /* nothing to do */ 1561184610Salfred return; 1562184610Salfred } 1563184610Salfred TAILQ_REMOVE(&uhe->bsd_urb_list, urb, bsd_urb_list); 1564184610Salfred urb->bsd_urb_list.tqe_prev = NULL; 1565184610Salfred 1566184610Salfred xfer->priv_fifo = urb; 1567184610Salfred xfer->flags.force_short_xfer = 0; 1568184610Salfred xfer->timeout = urb->timeout; 1569184610Salfred 1570184610Salfred if (xfer->flags_int.control_xfr) { 1571184610Salfred 1572184610Salfred /* 1573184610Salfred * USB control transfers need special handling. 1574184610Salfred * First copy in the header, then copy in data! 1575184610Salfred */ 1576184610Salfred if (!xfer->flags.ext_buffer) { 1577184610Salfred usb2_copy_in(xfer->frbuffers, 0, 1578184610Salfred urb->setup_packet, REQ_SIZE); 1579184610Salfred } else { 1580184610Salfred /* set virtual address to load */ 1581184610Salfred usb2_set_frame_data(xfer, 1582184610Salfred urb->setup_packet, 0); 1583184610Salfred } 1584184610Salfred 1585184610Salfred xfer->frlengths[0] = REQ_SIZE; 1586184610Salfred 1587184610Salfred ptr = urb->setup_packet; 1588184610Salfred 1589184610Salfred /* setup data transfer direction and length */ 1590184610Salfred urb->bsd_isread = (ptr[0] & UT_READ) ? 1 : 0; 1591184610Salfred urb->bsd_length_rem = ptr[6] | (ptr[7] << 8); 1592184610Salfred 1593184610Salfred } else { 1594184610Salfred 1595184610Salfred /* setup data transfer direction */ 1596184610Salfred 1597184610Salfred urb->bsd_length_rem = urb->transfer_buffer_length; 1598184610Salfred urb->bsd_isread = (uhe->desc.bEndpointAddress & 1599184610Salfred UE_DIR_IN) ? 1 : 0; 1600184610Salfred } 1601184610Salfred 1602184610Salfred urb->bsd_data_ptr = urb->transfer_buffer; 1603184610Salfred urb->actual_length = 0; 1604184610Salfred 1605184610Salfredsetup_bulk: 1606184610Salfred if (max_bulk > urb->bsd_length_rem) { 1607184610Salfred max_bulk = urb->bsd_length_rem; 1608184610Salfred } 1609184610Salfred /* check if we need to force a short transfer */ 1610184610Salfred 1611184610Salfred if ((max_bulk == urb->bsd_length_rem) && 1612184610Salfred (urb->transfer_flags & URB_ZERO_PACKET) && 1613184610Salfred (!xfer->flags_int.control_xfr)) { 1614184610Salfred xfer->flags.force_short_xfer = 1; 1615184610Salfred } 1616184610Salfred /* check if we need to copy in data */ 1617184610Salfred 1618184610Salfred if (xfer->flags.ext_buffer) { 1619184610Salfred /* set virtual address to load */ 1620184610Salfred usb2_set_frame_data(xfer, urb->bsd_data_ptr, 1621184610Salfred data_frame); 1622184610Salfred } else if (!urb->bsd_isread) { 1623184610Salfred /* copy out data with regard to the URB */ 1624184610Salfred usb2_copy_in(xfer->frbuffers + data_frame, 0, 1625184610Salfred urb->bsd_data_ptr, max_bulk); 1626184610Salfred } 1627184610Salfred xfer->frlengths[data_frame] = max_bulk; 1628184610Salfred if (xfer->flags_int.control_xfr) { 1629184610Salfred if (max_bulk > 0) { 1630184610Salfred xfer->nframes = 2; 1631184610Salfred } else { 1632184610Salfred xfer->nframes = 1; 1633184610Salfred } 1634184610Salfred } else { 1635184610Salfred xfer->nframes = 1; 1636184610Salfred } 1637184610Salfred usb2_start_hardware(xfer); 1638184610Salfred return; 1639184610Salfred 1640184610Salfred default: 1641184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 1642184610Salfred urb->status = -ECONNRESET; 1643184610Salfred } else { 1644184610Salfred urb->status = -EPIPE; 1645184610Salfred } 1646184610Salfred 1647184610Salfred /* Set zero for "actual_length" */ 1648184610Salfred urb->actual_length = 0; 1649184610Salfred 1650184610Salfred /* call callback */ 1651184610Salfred usb_linux_complete(xfer); 1652184610Salfred 1653184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 1654184610Salfred /* we need to return in this case */ 1655184610Salfred return; 1656184610Salfred } 1657184610Salfred goto tr_setup; 1658184610Salfred } 1659184610Salfred} 1660