| 1 | /* $NetBSD: usbdi.c,v 1.171 2016/05/17 11:37:50 pooka Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc. |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * This code is derived from software contributed to The NetBSD Foundation |
| 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
| 9 | * Carlstedt Research & Technology, Matthew R. Green (mrg@eterna.com.au), |
| 10 | * and Nick Hudson. |
| 11 | * |
| 12 | * Redistribution and use in source and binary forms, with or without |
| 13 | * modification, are permitted provided that the following conditions |
| 14 | * are met: |
| 15 | * 1. Redistributions of source code must retain the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer. |
| 17 | * 2. Redistributions in binary form must reproduce the above copyright |
| 18 | * notice, this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| 23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
| 25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 31 | * POSSIBILITY OF SUCH DAMAGE. |
| 32 | */ |
| 33 | |
| 34 | #include <sys/cdefs.h> |
| 35 | __KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.171 2016/05/17 11:37:50 pooka Exp $" ); |
| 36 | |
| 37 | #ifdef _KERNEL_OPT |
| 38 | #include "opt_usb.h" |
| 39 | #include "opt_compat_netbsd.h" |
| 40 | #include "usb_dma.h" |
| 41 | #endif |
| 42 | |
| 43 | #include <sys/param.h> |
| 44 | #include <sys/systm.h> |
| 45 | #include <sys/kernel.h> |
| 46 | #include <sys/device.h> |
| 47 | #include <sys/kmem.h> |
| 48 | #include <sys/proc.h> |
| 49 | #include <sys/bus.h> |
| 50 | #include <sys/cpu.h> |
| 51 | |
| 52 | #include <dev/usb/usb.h> |
| 53 | #include <dev/usb/usbdi.h> |
| 54 | #include <dev/usb/usbdi_util.h> |
| 55 | #include <dev/usb/usbdivar.h> |
| 56 | #include <dev/usb/usb_mem.h> |
| 57 | #include <dev/usb/usb_quirks.h> |
| 58 | #include <dev/usb/usbhist.h> |
| 59 | |
| 60 | /* UTF-8 encoding stuff */ |
| 61 | #include <fs/unicode.h> |
| 62 | |
| 63 | extern int usbdebug; |
| 64 | |
| 65 | Static usbd_status usbd_ar_pipe(struct usbd_pipe *); |
| 66 | Static void usbd_start_next(struct usbd_pipe *); |
| 67 | Static usbd_status usbd_open_pipe_ival |
| 68 | (struct usbd_interface *, uint8_t, uint8_t, struct usbd_pipe **, int); |
| 69 | static void *usbd_alloc_buffer(struct usbd_xfer *, uint32_t); |
| 70 | static void usbd_free_buffer(struct usbd_xfer *); |
| 71 | static struct usbd_xfer *usbd_alloc_xfer(struct usbd_device *, unsigned int); |
| 72 | static usbd_status usbd_free_xfer(struct usbd_xfer *); |
| 73 | |
| 74 | #if defined(USB_DEBUG) |
| 75 | void |
| 76 | usbd_dump_iface(struct usbd_interface *iface) |
| 77 | { |
| 78 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 79 | |
| 80 | USBHIST_LOG(usbdebug, "iface %p" , iface, 0, 0, 0); |
| 81 | if (iface == NULL) |
| 82 | return; |
| 83 | USBHIST_LOG(usbdebug, " device = %p idesc = %p index = %d" , |
| 84 | iface->ui_dev, iface->ui_idesc, iface->ui_index, 0); |
| 85 | USBHIST_LOG(usbdebug, " altindex=%d priv=%p" , |
| 86 | iface->ui_altindex, iface->ui_priv, 0, 0); |
| 87 | } |
| 88 | |
| 89 | void |
| 90 | usbd_dump_device(struct usbd_device *dev) |
| 91 | { |
| 92 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 93 | |
| 94 | USBHIST_LOG(usbdebug, "dev = %p" , dev, 0, 0, 0); |
| 95 | if (dev == NULL) |
| 96 | return; |
| 97 | USBHIST_LOG(usbdebug, " bus = %p default_pipe = %p" , |
| 98 | dev->ud_bus, dev->ud_pipe0, 0, 0); |
| 99 | USBHIST_LOG(usbdebug, " address = %d config = %d depth = %d " , |
| 100 | dev->ud_addr, dev->ud_config, dev->ud_depth, 0); |
| 101 | USBHIST_LOG(usbdebug, " speed = %d self_powered = %d " |
| 102 | "power = %d langid = %d" , |
| 103 | dev->ud_speed, dev->ud_selfpowered, dev->ud_power, dev->ud_langid); |
| 104 | } |
| 105 | |
| 106 | void |
| 107 | usbd_dump_endpoint(struct usbd_endpoint *endp) |
| 108 | { |
| 109 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 110 | |
| 111 | USBHIST_LOG(usbdebug, "endp = %p" , endp, 0, 0, 0); |
| 112 | if (endp == NULL) |
| 113 | return; |
| 114 | USBHIST_LOG(usbdebug, " edesc = %p refcnt = %d" , |
| 115 | endp->ue_edesc, endp->ue_refcnt, 0, 0); |
| 116 | if (endp->ue_edesc) |
| 117 | USBHIST_LOG(usbdebug, " bEndpointAddress=0x%02x" , |
| 118 | endp->ue_edesc->bEndpointAddress, 0, 0, 0); |
| 119 | } |
| 120 | |
| 121 | void |
| 122 | usbd_dump_queue(struct usbd_pipe *pipe) |
| 123 | { |
| 124 | struct usbd_xfer *xfer; |
| 125 | |
| 126 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 127 | |
| 128 | USBHIST_LOG(usbdebug, "pipe = %p" , pipe, 0, 0, 0); |
| 129 | SIMPLEQ_FOREACH(xfer, &pipe->up_queue, ux_next) { |
| 130 | USBHIST_LOG(usbdebug, " xfer = %p" , xfer, 0, 0, 0); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | void |
| 135 | usbd_dump_pipe(struct usbd_pipe *pipe) |
| 136 | { |
| 137 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 138 | |
| 139 | USBHIST_LOG(usbdebug, "pipe = %p" , pipe, 0, 0, 0); |
| 140 | if (pipe == NULL) |
| 141 | return; |
| 142 | usbd_dump_iface(pipe->up_iface); |
| 143 | usbd_dump_device(pipe->up_dev); |
| 144 | usbd_dump_endpoint(pipe->up_endpoint); |
| 145 | USBHIST_LOG(usbdebug, "(usbd_dump_pipe)" , 0, 0, 0, 0); |
| 146 | USBHIST_LOG(usbdebug, " running = %d aborting = %d" , |
| 147 | pipe->up_running, pipe->up_aborting, 0, 0); |
| 148 | USBHIST_LOG(usbdebug, " intrxfer = %p, repeat = %d, interval = %d" , |
| 149 | pipe->up_intrxfer, pipe->up_repeat, pipe->up_interval, 0); |
| 150 | } |
| 151 | #endif |
| 152 | |
| 153 | usbd_status |
| 154 | usbd_open_pipe(struct usbd_interface *iface, uint8_t address, |
| 155 | uint8_t flags, struct usbd_pipe **pipe) |
| 156 | { |
| 157 | return (usbd_open_pipe_ival(iface, address, flags, pipe, |
| 158 | USBD_DEFAULT_INTERVAL)); |
| 159 | } |
| 160 | |
| 161 | usbd_status |
| 162 | usbd_open_pipe_ival(struct usbd_interface *iface, uint8_t address, |
| 163 | uint8_t flags, struct usbd_pipe **pipe, int ival) |
| 164 | { |
| 165 | struct usbd_pipe *p; |
| 166 | struct usbd_endpoint *ep; |
| 167 | usbd_status err; |
| 168 | int i; |
| 169 | |
| 170 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 171 | |
| 172 | USBHIST_LOG(usbdebug, "iface = %p address = 0x%x flags = 0x%x" , |
| 173 | iface, address, flags, 0); |
| 174 | |
| 175 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { |
| 176 | ep = &iface->ui_endpoints[i]; |
| 177 | if (ep->ue_edesc == NULL) |
| 178 | return USBD_IOERROR; |
| 179 | if (ep->ue_edesc->bEndpointAddress == address) |
| 180 | goto found; |
| 181 | } |
| 182 | return USBD_BAD_ADDRESS; |
| 183 | found: |
| 184 | if ((flags & USBD_EXCLUSIVE_USE) && ep->ue_refcnt != 0) |
| 185 | return USBD_IN_USE; |
| 186 | err = usbd_setup_pipe_flags(iface->ui_dev, iface, ep, ival, &p, flags); |
| 187 | if (err) |
| 188 | return err; |
| 189 | LIST_INSERT_HEAD(&iface->ui_pipes, p, up_next); |
| 190 | *pipe = p; |
| 191 | return USBD_NORMAL_COMPLETION; |
| 192 | } |
| 193 | |
| 194 | usbd_status |
| 195 | usbd_open_pipe_intr(struct usbd_interface *iface, uint8_t address, |
| 196 | uint8_t flags, struct usbd_pipe **pipe, |
| 197 | void *priv, void *buffer, uint32_t len, |
| 198 | usbd_callback cb, int ival) |
| 199 | { |
| 200 | usbd_status err; |
| 201 | struct usbd_xfer *xfer; |
| 202 | struct usbd_pipe *ipipe; |
| 203 | |
| 204 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 205 | |
| 206 | USBHIST_LOG(usbdebug, "address = 0x%x flags = 0x%x len = %d" , |
| 207 | address, flags, len, 0); |
| 208 | |
| 209 | err = usbd_open_pipe_ival(iface, address, |
| 210 | USBD_EXCLUSIVE_USE | (flags & USBD_MPSAFE), |
| 211 | &ipipe, ival); |
| 212 | if (err) |
| 213 | return err; |
| 214 | err = usbd_create_xfer(ipipe, len, flags, 0, &xfer); |
| 215 | if (err) |
| 216 | goto bad1; |
| 217 | |
| 218 | usbd_setup_xfer(xfer, priv, buffer, len, flags, USBD_NO_TIMEOUT, cb); |
| 219 | ipipe->up_intrxfer = xfer; |
| 220 | ipipe->up_repeat = 1; |
| 221 | err = usbd_transfer(xfer); |
| 222 | *pipe = ipipe; |
| 223 | if (err != USBD_IN_PROGRESS) |
| 224 | goto bad3; |
| 225 | return USBD_NORMAL_COMPLETION; |
| 226 | |
| 227 | bad3: |
| 228 | ipipe->up_intrxfer = NULL; |
| 229 | ipipe->up_repeat = 0; |
| 230 | |
| 231 | usbd_destroy_xfer(xfer); |
| 232 | bad1: |
| 233 | usbd_close_pipe(ipipe); |
| 234 | return err; |
| 235 | } |
| 236 | |
| 237 | usbd_status |
| 238 | usbd_close_pipe(struct usbd_pipe *pipe) |
| 239 | { |
| 240 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 241 | |
| 242 | KASSERT(pipe != NULL); |
| 243 | |
| 244 | usbd_lock_pipe(pipe); |
| 245 | |
| 246 | if (!SIMPLEQ_EMPTY(&pipe->up_queue)) { |
| 247 | printf("WARNING: pipe closed with active xfers on addr %d\n" , |
| 248 | pipe->up_dev->ud_addr); |
| 249 | usbd_ar_pipe(pipe); |
| 250 | } |
| 251 | |
| 252 | KASSERT(SIMPLEQ_EMPTY(&pipe->up_queue)); |
| 253 | |
| 254 | LIST_REMOVE(pipe, up_next); |
| 255 | pipe->up_endpoint->ue_refcnt--; |
| 256 | |
| 257 | if (pipe->up_intrxfer != NULL) { |
| 258 | usbd_unlock_pipe(pipe); |
| 259 | usbd_destroy_xfer(pipe->up_intrxfer); |
| 260 | usbd_lock_pipe(pipe); |
| 261 | } |
| 262 | |
| 263 | pipe->up_methods->upm_close(pipe); |
| 264 | usbd_unlock_pipe(pipe); |
| 265 | kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize); |
| 266 | |
| 267 | return USBD_NORMAL_COMPLETION; |
| 268 | } |
| 269 | |
| 270 | usbd_status |
| 271 | usbd_transfer(struct usbd_xfer *xfer) |
| 272 | { |
| 273 | struct usbd_pipe *pipe = xfer->ux_pipe; |
| 274 | usbd_status err; |
| 275 | unsigned int size, flags; |
| 276 | |
| 277 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 278 | |
| 279 | USBHIST_LOG(usbdebug, |
| 280 | "xfer = %p, flags = %#x, pipe = %p, running = %d" , |
| 281 | xfer, xfer->ux_flags, pipe, pipe->up_running); |
| 282 | |
| 283 | #ifdef USB_DEBUG |
| 284 | if (usbdebug > 5) |
| 285 | usbd_dump_queue(pipe); |
| 286 | #endif |
| 287 | xfer->ux_done = 0; |
| 288 | |
| 289 | if (pipe->up_aborting) { |
| 290 | USBHIST_LOG(usbdebug, "<- done xfer %p, aborting" , xfer, 0, 0, |
| 291 | 0); |
| 292 | return USBD_CANCELLED; |
| 293 | } |
| 294 | |
| 295 | KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL); |
| 296 | |
| 297 | size = xfer->ux_length; |
| 298 | flags = xfer->ux_flags; |
| 299 | |
| 300 | if (size != 0) { |
| 301 | /* |
| 302 | * Use the xfer buffer if none specified in transfer setup. |
| 303 | * isoc transfers always use the xfer buffer, i.e. |
| 304 | * ux_buffer is always NULL for isoc. |
| 305 | */ |
| 306 | if (xfer->ux_buffer == NULL) { |
| 307 | xfer->ux_buffer = xfer->ux_buf; |
| 308 | } |
| 309 | |
| 310 | /* |
| 311 | * If not using the xfer buffer copy data to the |
| 312 | * xfer buffer for OUT transfers of >0 length |
| 313 | */ |
| 314 | if (xfer->ux_buffer != xfer->ux_buf) { |
| 315 | KASSERT(xfer->ux_buf); |
| 316 | if (!usbd_xfer_isread(xfer)) { |
| 317 | memcpy(xfer->ux_buf, xfer->ux_buffer, size); |
| 318 | } |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | /* xfer is not valid after the transfer method unless synchronous */ |
| 323 | err = pipe->up_methods->upm_transfer(xfer); |
| 324 | USBHIST_LOG(usbdebug, "<- done transfer %p, err = %d" , xfer, err, 0, 0); |
| 325 | |
| 326 | if (err != USBD_IN_PROGRESS && err) { |
| 327 | /* |
| 328 | * The transfer made it onto the pipe queue, but didn't get |
| 329 | * accepted by the HCD for some reason. It needs removing |
| 330 | * from the pipe queue. |
| 331 | */ |
| 332 | usbd_lock_pipe(pipe); |
| 333 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); |
| 334 | if (pipe->up_serialise) |
| 335 | usbd_start_next(pipe); |
| 336 | usbd_unlock_pipe(pipe); |
| 337 | } |
| 338 | |
| 339 | if (!(flags & USBD_SYNCHRONOUS)) { |
| 340 | USBHIST_LOG(usbdebug, "<- done xfer %p, not sync (err %d)" , |
| 341 | xfer, err, 0, 0); |
| 342 | return err; |
| 343 | } |
| 344 | |
| 345 | if (err != USBD_IN_PROGRESS) { |
| 346 | USBHIST_LOG(usbdebug, "<- done xfer %p, err %d (complete/error)" , xfer, |
| 347 | err, 0, 0); |
| 348 | return err; |
| 349 | } |
| 350 | |
| 351 | /* Sync transfer, wait for completion. */ |
| 352 | usbd_lock_pipe(pipe); |
| 353 | while (!xfer->ux_done) { |
| 354 | if (pipe->up_dev->ud_bus->ub_usepolling) |
| 355 | panic("usbd_transfer: not done" ); |
| 356 | USBHIST_LOG(usbdebug, "<- sleeping on xfer %p" , xfer, 0, 0, 0); |
| 357 | |
| 358 | err = 0; |
| 359 | if ((flags & USBD_SYNCHRONOUS_SIG) != 0) { |
| 360 | err = cv_wait_sig(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); |
| 361 | } else { |
| 362 | cv_wait(&xfer->ux_cv, pipe->up_dev->ud_bus->ub_lock); |
| 363 | } |
| 364 | if (err) { |
| 365 | if (!xfer->ux_done) |
| 366 | pipe->up_methods->upm_abort(xfer); |
| 367 | break; |
| 368 | } |
| 369 | } |
| 370 | usbd_unlock_pipe(pipe); |
| 371 | return xfer->ux_status; |
| 372 | } |
| 373 | |
| 374 | /* Like usbd_transfer(), but waits for completion. */ |
| 375 | usbd_status |
| 376 | usbd_sync_transfer(struct usbd_xfer *xfer) |
| 377 | { |
| 378 | xfer->ux_flags |= USBD_SYNCHRONOUS; |
| 379 | return usbd_transfer(xfer); |
| 380 | } |
| 381 | |
| 382 | /* Like usbd_transfer(), but waits for completion and listens for signals. */ |
| 383 | usbd_status |
| 384 | usbd_sync_transfer_sig(struct usbd_xfer *xfer) |
| 385 | { |
| 386 | xfer->ux_flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG; |
| 387 | return usbd_transfer(xfer); |
| 388 | } |
| 389 | |
| 390 | static void * |
| 391 | usbd_alloc_buffer(struct usbd_xfer *xfer, uint32_t size) |
| 392 | { |
| 393 | KASSERT(xfer->ux_buf == NULL); |
| 394 | KASSERT(size != 0); |
| 395 | |
| 396 | xfer->ux_bufsize = 0; |
| 397 | #if NUSB_DMA > 0 |
| 398 | struct usbd_bus *bus = xfer->ux_bus; |
| 399 | |
| 400 | if (bus->ub_usedma) { |
| 401 | usb_dma_t *dmap = &xfer->ux_dmabuf; |
| 402 | |
| 403 | int err = usb_allocmem_flags(bus, size, 0, dmap, bus->ub_dmaflags); |
| 404 | if (err) { |
| 405 | return NULL; |
| 406 | } |
| 407 | xfer->ux_buf = KERNADDR(&xfer->ux_dmabuf, 0); |
| 408 | xfer->ux_bufsize = size; |
| 409 | |
| 410 | return xfer->ux_buf; |
| 411 | } |
| 412 | #endif |
| 413 | KASSERT(xfer->ux_bus->ub_usedma == false); |
| 414 | xfer->ux_buf = kmem_alloc(size, KM_SLEEP); |
| 415 | |
| 416 | if (xfer->ux_buf != NULL) { |
| 417 | xfer->ux_bufsize = size; |
| 418 | } |
| 419 | |
| 420 | return xfer->ux_buf; |
| 421 | } |
| 422 | |
| 423 | static void |
| 424 | usbd_free_buffer(struct usbd_xfer *xfer) |
| 425 | { |
| 426 | KASSERT(xfer->ux_buf != NULL); |
| 427 | KASSERT(xfer->ux_bufsize != 0); |
| 428 | |
| 429 | void *buf = xfer->ux_buf; |
| 430 | uint32_t size = xfer->ux_bufsize; |
| 431 | |
| 432 | xfer->ux_buf = NULL; |
| 433 | xfer->ux_bufsize = 0; |
| 434 | |
| 435 | #if NUSB_DMA > 0 |
| 436 | struct usbd_bus *bus = xfer->ux_bus; |
| 437 | |
| 438 | if (bus->ub_usedma) { |
| 439 | usb_dma_t *dmap = &xfer->ux_dmabuf; |
| 440 | |
| 441 | usb_freemem(bus, dmap); |
| 442 | return; |
| 443 | } |
| 444 | #endif |
| 445 | KASSERT(xfer->ux_bus->ub_usedma == false); |
| 446 | |
| 447 | kmem_free(buf, size); |
| 448 | } |
| 449 | |
| 450 | void * |
| 451 | usbd_get_buffer(struct usbd_xfer *xfer) |
| 452 | { |
| 453 | return xfer->ux_buf; |
| 454 | } |
| 455 | |
| 456 | struct usbd_pipe * |
| 457 | usbd_get_pipe0(struct usbd_device *dev) |
| 458 | { |
| 459 | |
| 460 | return dev->ud_pipe0; |
| 461 | } |
| 462 | |
| 463 | static struct usbd_xfer * |
| 464 | usbd_alloc_xfer(struct usbd_device *dev, unsigned int nframes) |
| 465 | { |
| 466 | struct usbd_xfer *xfer; |
| 467 | |
| 468 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 469 | |
| 470 | ASSERT_SLEEPABLE(); |
| 471 | |
| 472 | xfer = dev->ud_bus->ub_methods->ubm_allocx(dev->ud_bus, nframes); |
| 473 | if (xfer == NULL) |
| 474 | return NULL; |
| 475 | xfer->ux_bus = dev->ud_bus; |
| 476 | callout_init(&xfer->ux_callout, CALLOUT_MPSAFE); |
| 477 | cv_init(&xfer->ux_cv, "usbxfer" ); |
| 478 | cv_init(&xfer->ux_hccv, "usbhcxfer" ); |
| 479 | |
| 480 | USBHIST_LOG(usbdebug, "returns %p" , xfer, 0, 0, 0); |
| 481 | |
| 482 | return xfer; |
| 483 | } |
| 484 | |
| 485 | static usbd_status |
| 486 | usbd_free_xfer(struct usbd_xfer *xfer) |
| 487 | { |
| 488 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 489 | |
| 490 | USBHIST_LOG(usbdebug, "%p" , xfer, 0, 0, 0); |
| 491 | if (xfer->ux_buf) { |
| 492 | usbd_free_buffer(xfer); |
| 493 | } |
| 494 | #if defined(DIAGNOSTIC) |
| 495 | if (callout_pending(&xfer->ux_callout)) { |
| 496 | callout_stop(&xfer->ux_callout); |
| 497 | printf("usbd_free_xfer: timeout_handle pending\n" ); |
| 498 | } |
| 499 | #endif |
| 500 | cv_destroy(&xfer->ux_cv); |
| 501 | cv_destroy(&xfer->ux_hccv); |
| 502 | xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer); |
| 503 | return USBD_NORMAL_COMPLETION; |
| 504 | } |
| 505 | |
| 506 | int |
| 507 | usbd_create_xfer(struct usbd_pipe *pipe, size_t len, unsigned int flags, |
| 508 | unsigned int nframes, struct usbd_xfer **xp) |
| 509 | { |
| 510 | KASSERT(xp != NULL); |
| 511 | void *buf = NULL; |
| 512 | |
| 513 | struct usbd_xfer *xfer = usbd_alloc_xfer(pipe->up_dev, nframes); |
| 514 | if (xfer == NULL) |
| 515 | return ENOMEM; |
| 516 | |
| 517 | if (len) { |
| 518 | buf = usbd_alloc_buffer(xfer, len); |
| 519 | if (!buf) { |
| 520 | usbd_free_xfer(xfer); |
| 521 | return ENOMEM; |
| 522 | } |
| 523 | } |
| 524 | xfer->ux_pipe = pipe; |
| 525 | xfer->ux_flags = flags; |
| 526 | xfer->ux_nframes = nframes; |
| 527 | xfer->ux_methods = pipe->up_methods; |
| 528 | |
| 529 | if (xfer->ux_methods->upm_init) { |
| 530 | int err = xfer->ux_methods->upm_init(xfer); |
| 531 | if (err) { |
| 532 | if (buf) |
| 533 | usbd_free_buffer(xfer); |
| 534 | usbd_free_xfer(xfer); |
| 535 | return err; |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | *xp = xfer; |
| 540 | return 0; |
| 541 | } |
| 542 | |
| 543 | void |
| 544 | usbd_destroy_xfer(struct usbd_xfer *xfer) |
| 545 | { |
| 546 | |
| 547 | if (xfer->ux_methods->upm_fini) { |
| 548 | xfer->ux_methods->upm_fini(xfer); |
| 549 | } |
| 550 | |
| 551 | usbd_free_xfer(xfer); |
| 552 | } |
| 553 | |
| 554 | void |
| 555 | usbd_setup_xfer(struct usbd_xfer *xfer, void *priv, void *buffer, |
| 556 | uint32_t length, uint16_t flags, uint32_t timeout, usbd_callback callback) |
| 557 | { |
| 558 | KASSERT(xfer->ux_pipe); |
| 559 | |
| 560 | xfer->ux_priv = priv; |
| 561 | xfer->ux_buffer = buffer; |
| 562 | xfer->ux_length = length; |
| 563 | xfer->ux_actlen = 0; |
| 564 | xfer->ux_flags = flags; |
| 565 | xfer->ux_timeout = timeout; |
| 566 | xfer->ux_status = USBD_NOT_STARTED; |
| 567 | xfer->ux_callback = callback; |
| 568 | xfer->ux_rqflags &= ~URQ_REQUEST; |
| 569 | xfer->ux_nframes = 0; |
| 570 | } |
| 571 | |
| 572 | void |
| 573 | usbd_setup_default_xfer(struct usbd_xfer *xfer, struct usbd_device *dev, |
| 574 | void *priv, uint32_t timeout, usb_device_request_t *req, void *buffer, |
| 575 | uint32_t length, uint16_t flags, usbd_callback callback) |
| 576 | { |
| 577 | KASSERT(xfer->ux_pipe == dev->ud_pipe0); |
| 578 | |
| 579 | xfer->ux_priv = priv; |
| 580 | xfer->ux_buffer = buffer; |
| 581 | xfer->ux_length = length; |
| 582 | xfer->ux_actlen = 0; |
| 583 | xfer->ux_flags = flags; |
| 584 | xfer->ux_timeout = timeout; |
| 585 | xfer->ux_status = USBD_NOT_STARTED; |
| 586 | xfer->ux_callback = callback; |
| 587 | xfer->ux_request = *req; |
| 588 | xfer->ux_rqflags |= URQ_REQUEST; |
| 589 | xfer->ux_nframes = 0; |
| 590 | } |
| 591 | |
| 592 | void |
| 593 | usbd_setup_isoc_xfer(struct usbd_xfer *xfer, void *priv, uint16_t *frlengths, |
| 594 | uint32_t nframes, uint16_t flags, usbd_callback callback) |
| 595 | { |
| 596 | xfer->ux_priv = priv; |
| 597 | xfer->ux_buffer = NULL; |
| 598 | xfer->ux_length = 0; |
| 599 | xfer->ux_actlen = 0; |
| 600 | xfer->ux_flags = flags; |
| 601 | xfer->ux_timeout = USBD_NO_TIMEOUT; |
| 602 | xfer->ux_status = USBD_NOT_STARTED; |
| 603 | xfer->ux_callback = callback; |
| 604 | xfer->ux_rqflags &= ~URQ_REQUEST; |
| 605 | xfer->ux_frlengths = frlengths; |
| 606 | xfer->ux_nframes = nframes; |
| 607 | } |
| 608 | |
| 609 | void |
| 610 | usbd_get_xfer_status(struct usbd_xfer *xfer, void **priv, |
| 611 | void **buffer, uint32_t *count, usbd_status *status) |
| 612 | { |
| 613 | if (priv != NULL) |
| 614 | *priv = xfer->ux_priv; |
| 615 | if (buffer != NULL) |
| 616 | *buffer = xfer->ux_buffer; |
| 617 | if (count != NULL) |
| 618 | *count = xfer->ux_actlen; |
| 619 | if (status != NULL) |
| 620 | *status = xfer->ux_status; |
| 621 | } |
| 622 | |
| 623 | usb_config_descriptor_t * |
| 624 | usbd_get_config_descriptor(struct usbd_device *dev) |
| 625 | { |
| 626 | KASSERT(dev != NULL); |
| 627 | |
| 628 | return dev->ud_cdesc; |
| 629 | } |
| 630 | |
| 631 | usb_interface_descriptor_t * |
| 632 | usbd_get_interface_descriptor(struct usbd_interface *iface) |
| 633 | { |
| 634 | KASSERT(iface != NULL); |
| 635 | |
| 636 | return iface->ui_idesc; |
| 637 | } |
| 638 | |
| 639 | usb_device_descriptor_t * |
| 640 | usbd_get_device_descriptor(struct usbd_device *dev) |
| 641 | { |
| 642 | KASSERT(dev != NULL); |
| 643 | |
| 644 | return &dev->ud_ddesc; |
| 645 | } |
| 646 | |
| 647 | usb_endpoint_descriptor_t * |
| 648 | usbd_interface2endpoint_descriptor(struct usbd_interface *iface, uint8_t index) |
| 649 | { |
| 650 | |
| 651 | if (index >= iface->ui_idesc->bNumEndpoints) |
| 652 | return NULL; |
| 653 | return iface->ui_endpoints[index].ue_edesc; |
| 654 | } |
| 655 | |
| 656 | /* Some drivers may wish to abort requests on the default pipe, * |
| 657 | * but there is no mechanism for getting a handle on it. */ |
| 658 | usbd_status |
| 659 | usbd_abort_default_pipe(struct usbd_device *device) |
| 660 | { |
| 661 | return usbd_abort_pipe(device->ud_pipe0); |
| 662 | } |
| 663 | |
| 664 | usbd_status |
| 665 | usbd_abort_pipe(struct usbd_pipe *pipe) |
| 666 | { |
| 667 | usbd_status err; |
| 668 | |
| 669 | KASSERT(pipe != NULL); |
| 670 | |
| 671 | usbd_lock_pipe(pipe); |
| 672 | err = usbd_ar_pipe(pipe); |
| 673 | usbd_unlock_pipe(pipe); |
| 674 | return err; |
| 675 | } |
| 676 | |
| 677 | usbd_status |
| 678 | usbd_clear_endpoint_stall(struct usbd_pipe *pipe) |
| 679 | { |
| 680 | struct usbd_device *dev = pipe->up_dev; |
| 681 | usb_device_request_t req; |
| 682 | usbd_status err; |
| 683 | |
| 684 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 685 | |
| 686 | /* |
| 687 | * Clearing en endpoint stall resets the endpoint toggle, so |
| 688 | * do the same to the HC toggle. |
| 689 | */ |
| 690 | pipe->up_methods->upm_cleartoggle(pipe); |
| 691 | |
| 692 | req.bmRequestType = UT_WRITE_ENDPOINT; |
| 693 | req.bRequest = UR_CLEAR_FEATURE; |
| 694 | USETW(req.wValue, UF_ENDPOINT_HALT); |
| 695 | USETW(req.wIndex, pipe->up_endpoint->ue_edesc->bEndpointAddress); |
| 696 | USETW(req.wLength, 0); |
| 697 | err = usbd_do_request(dev, &req, 0); |
| 698 | #if 0 |
| 699 | XXX should we do this? |
| 700 | if (!err) { |
| 701 | pipe->state = USBD_PIPE_ACTIVE; |
| 702 | /* XXX activate pipe */ |
| 703 | } |
| 704 | #endif |
| 705 | return err; |
| 706 | } |
| 707 | |
| 708 | void |
| 709 | usbd_clear_endpoint_stall_task(void *arg) |
| 710 | { |
| 711 | struct usbd_pipe *pipe = arg; |
| 712 | struct usbd_device *dev = pipe->up_dev; |
| 713 | usb_device_request_t req; |
| 714 | |
| 715 | pipe->up_methods->upm_cleartoggle(pipe); |
| 716 | |
| 717 | req.bmRequestType = UT_WRITE_ENDPOINT; |
| 718 | req.bRequest = UR_CLEAR_FEATURE; |
| 719 | USETW(req.wValue, UF_ENDPOINT_HALT); |
| 720 | USETW(req.wIndex, pipe->up_endpoint->ue_edesc->bEndpointAddress); |
| 721 | USETW(req.wLength, 0); |
| 722 | (void)usbd_do_request(dev, &req, 0); |
| 723 | } |
| 724 | |
| 725 | void |
| 726 | usbd_clear_endpoint_stall_async(struct usbd_pipe *pipe) |
| 727 | { |
| 728 | usb_add_task(pipe->up_dev, &pipe->up_async_task, USB_TASKQ_DRIVER); |
| 729 | } |
| 730 | |
| 731 | void |
| 732 | usbd_clear_endpoint_toggle(struct usbd_pipe *pipe) |
| 733 | { |
| 734 | |
| 735 | pipe->up_methods->upm_cleartoggle(pipe); |
| 736 | } |
| 737 | |
| 738 | usbd_status |
| 739 | usbd_endpoint_count(struct usbd_interface *iface, uint8_t *count) |
| 740 | { |
| 741 | KASSERT(iface != NULL); |
| 742 | KASSERT(iface->ui_idesc != NULL); |
| 743 | |
| 744 | *count = iface->ui_idesc->bNumEndpoints; |
| 745 | return USBD_NORMAL_COMPLETION; |
| 746 | } |
| 747 | |
| 748 | usbd_status |
| 749 | usbd_interface_count(struct usbd_device *dev, uint8_t *count) |
| 750 | { |
| 751 | |
| 752 | if (dev->ud_cdesc == NULL) |
| 753 | return USBD_NOT_CONFIGURED; |
| 754 | *count = dev->ud_cdesc->bNumInterface; |
| 755 | return USBD_NORMAL_COMPLETION; |
| 756 | } |
| 757 | |
| 758 | void |
| 759 | usbd_interface2device_handle(struct usbd_interface *iface, |
| 760 | struct usbd_device **dev) |
| 761 | { |
| 762 | |
| 763 | *dev = iface->ui_dev; |
| 764 | } |
| 765 | |
| 766 | usbd_status |
| 767 | usbd_device2interface_handle(struct usbd_device *dev, |
| 768 | uint8_t ifaceno, struct usbd_interface **iface) |
| 769 | { |
| 770 | |
| 771 | if (dev->ud_cdesc == NULL) |
| 772 | return USBD_NOT_CONFIGURED; |
| 773 | if (ifaceno >= dev->ud_cdesc->bNumInterface) |
| 774 | return USBD_INVAL; |
| 775 | *iface = &dev->ud_ifaces[ifaceno]; |
| 776 | return USBD_NORMAL_COMPLETION; |
| 777 | } |
| 778 | |
| 779 | struct usbd_device * |
| 780 | usbd_pipe2device_handle(struct usbd_pipe *pipe) |
| 781 | { |
| 782 | KASSERT(pipe != NULL); |
| 783 | |
| 784 | return pipe->up_dev; |
| 785 | } |
| 786 | |
| 787 | /* XXXX use altno */ |
| 788 | usbd_status |
| 789 | usbd_set_interface(struct usbd_interface *iface, int altidx) |
| 790 | { |
| 791 | usb_device_request_t req; |
| 792 | usbd_status err; |
| 793 | void *endpoints; |
| 794 | |
| 795 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 796 | |
| 797 | if (LIST_FIRST(&iface->ui_pipes) != NULL) |
| 798 | return USBD_IN_USE; |
| 799 | |
| 800 | endpoints = iface->ui_endpoints; |
| 801 | int nendpt = iface->ui_idesc->bNumEndpoints; |
| 802 | USBHIST_LOG(usbdebug, "iface %p endpoints = %p nendpt" , iface, |
| 803 | endpoints, iface->ui_idesc->bNumEndpoints, 0); |
| 804 | err = usbd_fill_iface_data(iface->ui_dev, iface->ui_index, altidx); |
| 805 | if (err) |
| 806 | return err; |
| 807 | |
| 808 | /* new setting works, we can free old endpoints */ |
| 809 | if (endpoints != NULL) { |
| 810 | USBHIST_LOG(usbdebug, "iface %p endpoints = %p nendpt" , iface, |
| 811 | endpoints, nendpt, 0); |
| 812 | kmem_free(endpoints, nendpt * sizeof(struct usbd_endpoint)); |
| 813 | } |
| 814 | KASSERT(iface->ui_idesc != NULL); |
| 815 | |
| 816 | req.bmRequestType = UT_WRITE_INTERFACE; |
| 817 | req.bRequest = UR_SET_INTERFACE; |
| 818 | USETW(req.wValue, iface->ui_idesc->bAlternateSetting); |
| 819 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); |
| 820 | USETW(req.wLength, 0); |
| 821 | return usbd_do_request(iface->ui_dev, &req, 0); |
| 822 | } |
| 823 | |
| 824 | int |
| 825 | usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno) |
| 826 | { |
| 827 | char *p = (char *)cdesc; |
| 828 | char *end = p + UGETW(cdesc->wTotalLength); |
| 829 | usb_interface_descriptor_t *d; |
| 830 | int n; |
| 831 | |
| 832 | for (n = 0; p < end; p += d->bLength) { |
| 833 | d = (usb_interface_descriptor_t *)p; |
| 834 | if (p + d->bLength <= end && |
| 835 | d->bDescriptorType == UDESC_INTERFACE && |
| 836 | d->bInterfaceNumber == ifaceno) |
| 837 | n++; |
| 838 | } |
| 839 | return n; |
| 840 | } |
| 841 | |
| 842 | int |
| 843 | usbd_get_interface_altindex(struct usbd_interface *iface) |
| 844 | { |
| 845 | return iface->ui_altindex; |
| 846 | } |
| 847 | |
| 848 | usbd_status |
| 849 | usbd_get_interface(struct usbd_interface *iface, uint8_t *aiface) |
| 850 | { |
| 851 | usb_device_request_t req; |
| 852 | |
| 853 | req.bmRequestType = UT_READ_INTERFACE; |
| 854 | req.bRequest = UR_GET_INTERFACE; |
| 855 | USETW(req.wValue, 0); |
| 856 | USETW(req.wIndex, iface->ui_idesc->bInterfaceNumber); |
| 857 | USETW(req.wLength, 1); |
| 858 | return usbd_do_request(iface->ui_dev, &req, aiface); |
| 859 | } |
| 860 | |
| 861 | /*** Internal routines ***/ |
| 862 | |
| 863 | /* Dequeue all pipe operations, called at splusb(). */ |
| 864 | Static usbd_status |
| 865 | usbd_ar_pipe(struct usbd_pipe *pipe) |
| 866 | { |
| 867 | struct usbd_xfer *xfer; |
| 868 | |
| 869 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 870 | |
| 871 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
| 872 | |
| 873 | USBHIST_LOG(usbdebug, "pipe = %p" , pipe, 0, 0, 0); |
| 874 | #ifdef USB_DEBUG |
| 875 | if (usbdebug > 5) |
| 876 | usbd_dump_queue(pipe); |
| 877 | #endif |
| 878 | pipe->up_repeat = 0; |
| 879 | pipe->up_aborting = 1; |
| 880 | while ((xfer = SIMPLEQ_FIRST(&pipe->up_queue)) != NULL) { |
| 881 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p (methods = %p)" , |
| 882 | pipe, xfer, pipe->up_methods, 0); |
| 883 | /* Make the HC abort it (and invoke the callback). */ |
| 884 | pipe->up_methods->upm_abort(xfer); |
| 885 | /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */ |
| 886 | } |
| 887 | pipe->up_aborting = 0; |
| 888 | return USBD_NORMAL_COMPLETION; |
| 889 | } |
| 890 | |
| 891 | /* Called with USB lock held. */ |
| 892 | void |
| 893 | usb_transfer_complete(struct usbd_xfer *xfer) |
| 894 | { |
| 895 | struct usbd_pipe *pipe = xfer->ux_pipe; |
| 896 | struct usbd_bus *bus = pipe->up_dev->ud_bus; |
| 897 | int sync = xfer->ux_flags & USBD_SYNCHRONOUS; |
| 898 | int erred = |
| 899 | xfer->ux_status == USBD_CANCELLED || |
| 900 | xfer->ux_status == USBD_TIMEOUT; |
| 901 | int polling = bus->ub_usepolling; |
| 902 | int repeat = pipe->up_repeat; |
| 903 | |
| 904 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 905 | |
| 906 | USBHIST_LOG(usbdebug, "pipe = %p xfer = %p status = %d actlen = %d" , |
| 907 | pipe, xfer, xfer->ux_status, xfer->ux_actlen); |
| 908 | |
| 909 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
| 910 | KASSERT(xfer->ux_state == XFER_ONQU); |
| 911 | KASSERT(pipe != NULL); |
| 912 | |
| 913 | if (!repeat) { |
| 914 | /* Remove request from queue. */ |
| 915 | |
| 916 | KASSERTMSG(!SIMPLEQ_EMPTY(&pipe->up_queue), |
| 917 | "pipe %p is empty, but xfer %p wants to complete" , pipe, |
| 918 | xfer); |
| 919 | KASSERTMSG(xfer == SIMPLEQ_FIRST(&pipe->up_queue), |
| 920 | "xfer %p is not start of queue (%p is at start)" , xfer, |
| 921 | SIMPLEQ_FIRST(&pipe->up_queue)); |
| 922 | |
| 923 | #ifdef DIAGNOSTIC |
| 924 | xfer->ux_state = XFER_BUSY; |
| 925 | #endif |
| 926 | SIMPLEQ_REMOVE_HEAD(&pipe->up_queue, ux_next); |
| 927 | } |
| 928 | USBHIST_LOG(usbdebug, "xfer %p: repeat %d new head = %p" , |
| 929 | xfer, repeat, SIMPLEQ_FIRST(&pipe->up_queue), 0); |
| 930 | |
| 931 | /* Count completed transfers. */ |
| 932 | ++pipe->up_dev->ud_bus->ub_stats.uds_requests |
| 933 | [pipe->up_endpoint->ue_edesc->bmAttributes & UE_XFERTYPE]; |
| 934 | |
| 935 | xfer->ux_done = 1; |
| 936 | if (!xfer->ux_status && xfer->ux_actlen < xfer->ux_length && |
| 937 | !(xfer->ux_flags & USBD_SHORT_XFER_OK)) { |
| 938 | USBHIST_LOG(usbdebug, "short transfer %d < %d" , |
| 939 | xfer->ux_actlen, xfer->ux_length, 0, 0); |
| 940 | xfer->ux_status = USBD_SHORT_XFER; |
| 941 | } |
| 942 | |
| 943 | USBHIST_LOG(usbdebug, "xfer %p doing done %p" , xfer, |
| 944 | pipe->up_methods->upm_done, 0, 0); |
| 945 | pipe->up_methods->upm_done(xfer); |
| 946 | |
| 947 | if (xfer->ux_length != 0 && xfer->ux_buffer != xfer->ux_buf) { |
| 948 | KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length, |
| 949 | "actlen %d length %d" ,xfer->ux_actlen, xfer->ux_length); |
| 950 | |
| 951 | /* Only if IN transfer */ |
| 952 | if (usbd_xfer_isread(xfer)) { |
| 953 | memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen); |
| 954 | } |
| 955 | } |
| 956 | |
| 957 | USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %d" , |
| 958 | xfer, xfer->ux_callback, xfer->ux_status, 0); |
| 959 | |
| 960 | if (xfer->ux_callback) { |
| 961 | if (!polling) |
| 962 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); |
| 963 | |
| 964 | if (!(pipe->up_flags & USBD_MPSAFE)) |
| 965 | KERNEL_LOCK(1, curlwp); |
| 966 | |
| 967 | xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status); |
| 968 | |
| 969 | if (!(pipe->up_flags & USBD_MPSAFE)) |
| 970 | KERNEL_UNLOCK_ONE(curlwp); |
| 971 | |
| 972 | if (!polling) |
| 973 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); |
| 974 | } |
| 975 | |
| 976 | if (sync && !polling) { |
| 977 | USBHIST_LOG(usbdebug, "<- done xfer %p, wakeup" , xfer, 0, 0, 0); |
| 978 | cv_broadcast(&xfer->ux_cv); |
| 979 | } |
| 980 | |
| 981 | if (repeat) { |
| 982 | xfer->ux_actlen = 0; |
| 983 | xfer->ux_status = USBD_NOT_STARTED; |
| 984 | } else { |
| 985 | /* XXX should we stop the queue on all errors? */ |
| 986 | if (erred && pipe->up_iface != NULL) /* not control pipe */ |
| 987 | pipe->up_running = 0; |
| 988 | } |
| 989 | if (pipe->up_running && pipe->up_serialise) |
| 990 | usbd_start_next(pipe); |
| 991 | } |
| 992 | |
| 993 | /* Called with USB lock held. */ |
| 994 | usbd_status |
| 995 | usb_insert_transfer(struct usbd_xfer *xfer) |
| 996 | { |
| 997 | struct usbd_pipe *pipe = xfer->ux_pipe; |
| 998 | usbd_status err; |
| 999 | |
| 1000 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 1001 | |
| 1002 | USBHIST_LOG(usbdebug, "xfer = %p pipe = %p running = %d timeout = %d" , |
| 1003 | xfer, pipe, pipe->up_running, xfer->ux_timeout); |
| 1004 | |
| 1005 | KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
| 1006 | KASSERT(xfer->ux_state == XFER_BUSY); |
| 1007 | |
| 1008 | #ifdef DIAGNOSTIC |
| 1009 | xfer->ux_state = XFER_ONQU; |
| 1010 | #endif |
| 1011 | SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next); |
| 1012 | if (pipe->up_running && pipe->up_serialise) |
| 1013 | err = USBD_IN_PROGRESS; |
| 1014 | else { |
| 1015 | pipe->up_running = 1; |
| 1016 | err = USBD_NORMAL_COMPLETION; |
| 1017 | } |
| 1018 | USBHIST_LOG(usbdebug, "<- done xfer %p, err %d" , xfer, err, 0, 0); |
| 1019 | return err; |
| 1020 | } |
| 1021 | |
| 1022 | /* Called with USB lock held. */ |
| 1023 | void |
| 1024 | usbd_start_next(struct usbd_pipe *pipe) |
| 1025 | { |
| 1026 | struct usbd_xfer *xfer; |
| 1027 | usbd_status err; |
| 1028 | |
| 1029 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 1030 | |
| 1031 | KASSERT(pipe != NULL); |
| 1032 | KASSERT(pipe->up_methods != NULL); |
| 1033 | KASSERT(pipe->up_methods->upm_start != NULL); |
| 1034 | KASSERT(pipe->up_serialise == true); |
| 1035 | |
| 1036 | int polling = pipe->up_dev->ud_bus->ub_usepolling; |
| 1037 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
| 1038 | |
| 1039 | /* Get next request in queue. */ |
| 1040 | xfer = SIMPLEQ_FIRST(&pipe->up_queue); |
| 1041 | USBHIST_LOG(usbdebug, "pipe = %p, xfer = %p" , pipe, xfer, 0, 0); |
| 1042 | if (xfer == NULL) { |
| 1043 | pipe->up_running = 0; |
| 1044 | } else { |
| 1045 | if (!polling) |
| 1046 | mutex_exit(pipe->up_dev->ud_bus->ub_lock); |
| 1047 | err = pipe->up_methods->upm_start(xfer); |
| 1048 | if (!polling) |
| 1049 | mutex_enter(pipe->up_dev->ud_bus->ub_lock); |
| 1050 | |
| 1051 | if (err != USBD_IN_PROGRESS) { |
| 1052 | USBHIST_LOG(usbdebug, "error = %d" , err, 0, 0, 0); |
| 1053 | pipe->up_running = 0; |
| 1054 | /* XXX do what? */ |
| 1055 | } |
| 1056 | } |
| 1057 | |
| 1058 | KASSERT(polling || mutex_owned(pipe->up_dev->ud_bus->ub_lock)); |
| 1059 | } |
| 1060 | |
| 1061 | usbd_status |
| 1062 | usbd_do_request(struct usbd_device *dev, usb_device_request_t *req, void *data) |
| 1063 | { |
| 1064 | |
| 1065 | return usbd_do_request_flags(dev, req, data, 0, 0, |
| 1066 | USBD_DEFAULT_TIMEOUT); |
| 1067 | } |
| 1068 | |
| 1069 | usbd_status |
| 1070 | usbd_do_request_flags(struct usbd_device *dev, usb_device_request_t *req, |
| 1071 | void *data, uint16_t flags, int *actlen, uint32_t timeout) |
| 1072 | { |
| 1073 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 1074 | struct usbd_xfer *xfer; |
| 1075 | usbd_status err; |
| 1076 | |
| 1077 | ASSERT_SLEEPABLE(); |
| 1078 | |
| 1079 | size_t len = UGETW(req->wLength); |
| 1080 | int error = usbd_create_xfer(dev->ud_pipe0, len, 0, 0, &xfer); |
| 1081 | if (error) |
| 1082 | return error; |
| 1083 | |
| 1084 | usbd_setup_default_xfer(xfer, dev, 0, timeout, req, data, |
| 1085 | UGETW(req->wLength), flags, NULL); |
| 1086 | KASSERT(xfer->ux_pipe == dev->ud_pipe0); |
| 1087 | err = usbd_sync_transfer(xfer); |
| 1088 | #if defined(USB_DEBUG) || defined(DIAGNOSTIC) |
| 1089 | if (xfer->ux_actlen > xfer->ux_length) { |
| 1090 | USBHIST_LOG(usbdebug, "overrun addr = %d type = 0x%02x" , |
| 1091 | dev->ud_addr, xfer->ux_request.bmRequestType, 0, 0); |
| 1092 | USBHIST_LOG(usbdebug, " req = 0x%02x val = %d index = %d" , |
| 1093 | xfer->ux_request.bRequest, UGETW(xfer->ux_request.wValue), |
| 1094 | UGETW(xfer->ux_request.wIndex), 0); |
| 1095 | USBHIST_LOG(usbdebug, " rlen = %d length = %d actlen = %d" , |
| 1096 | UGETW(xfer->ux_request.wLength), |
| 1097 | xfer->ux_length, xfer->ux_actlen, 0); |
| 1098 | } |
| 1099 | #endif |
| 1100 | if (actlen != NULL) |
| 1101 | *actlen = xfer->ux_actlen; |
| 1102 | |
| 1103 | usbd_destroy_xfer(xfer); |
| 1104 | |
| 1105 | if (err) { |
| 1106 | USBHIST_LOG(usbdebug, "returning err = %d" , err, 0, 0, 0); |
| 1107 | } |
| 1108 | return err; |
| 1109 | } |
| 1110 | |
| 1111 | const struct usbd_quirks * |
| 1112 | usbd_get_quirks(struct usbd_device *dev) |
| 1113 | { |
| 1114 | #ifdef DIAGNOSTIC |
| 1115 | if (dev == NULL) { |
| 1116 | printf("usbd_get_quirks: dev == NULL\n" ); |
| 1117 | return 0; |
| 1118 | } |
| 1119 | #endif |
| 1120 | return dev->ud_quirks; |
| 1121 | } |
| 1122 | |
| 1123 | /* XXX do periodic free() of free list */ |
| 1124 | |
| 1125 | /* |
| 1126 | * Called from keyboard driver when in polling mode. |
| 1127 | */ |
| 1128 | void |
| 1129 | usbd_dopoll(struct usbd_interface *iface) |
| 1130 | { |
| 1131 | iface->ui_dev->ud_bus->ub_methods->ubm_dopoll(iface->ui_dev->ud_bus); |
| 1132 | } |
| 1133 | |
| 1134 | /* |
| 1135 | * XXX use this more??? ub_usepolling it touched manually all over |
| 1136 | */ |
| 1137 | void |
| 1138 | usbd_set_polling(struct usbd_device *dev, int on) |
| 1139 | { |
| 1140 | if (on) |
| 1141 | dev->ud_bus->ub_usepolling++; |
| 1142 | else |
| 1143 | dev->ud_bus->ub_usepolling--; |
| 1144 | |
| 1145 | /* Kick the host controller when switching modes */ |
| 1146 | mutex_enter(dev->ud_bus->ub_lock); |
| 1147 | dev->ud_bus->ub_methods->ubm_softint(dev->ud_bus); |
| 1148 | mutex_exit(dev->ud_bus->ub_lock); |
| 1149 | } |
| 1150 | |
| 1151 | |
| 1152 | usb_endpoint_descriptor_t * |
| 1153 | usbd_get_endpoint_descriptor(struct usbd_interface *iface, uint8_t address) |
| 1154 | { |
| 1155 | struct usbd_endpoint *ep; |
| 1156 | int i; |
| 1157 | |
| 1158 | for (i = 0; i < iface->ui_idesc->bNumEndpoints; i++) { |
| 1159 | ep = &iface->ui_endpoints[i]; |
| 1160 | if (ep->ue_edesc->bEndpointAddress == address) |
| 1161 | return iface->ui_endpoints[i].ue_edesc; |
| 1162 | } |
| 1163 | return NULL; |
| 1164 | } |
| 1165 | |
| 1166 | /* |
| 1167 | * usbd_ratecheck() can limit the number of error messages that occurs. |
| 1168 | * When a device is unplugged it may take up to 0.25s for the hub driver |
| 1169 | * to notice it. If the driver continuously tries to do I/O operations |
| 1170 | * this can generate a large number of messages. |
| 1171 | */ |
| 1172 | int |
| 1173 | usbd_ratecheck(struct timeval *last) |
| 1174 | { |
| 1175 | static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/ |
| 1176 | |
| 1177 | return ratecheck(last, &errinterval); |
| 1178 | } |
| 1179 | |
| 1180 | /* |
| 1181 | * Search for a vendor/product pair in an array. The item size is |
| 1182 | * given as an argument. |
| 1183 | */ |
| 1184 | const struct usb_devno * |
| 1185 | usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz, |
| 1186 | uint16_t vendor, uint16_t product) |
| 1187 | { |
| 1188 | while (nentries-- > 0) { |
| 1189 | uint16_t tproduct = tbl->ud_product; |
| 1190 | if (tbl->ud_vendor == vendor && |
| 1191 | (tproduct == product || tproduct == USB_PRODUCT_ANY)) |
| 1192 | return tbl; |
| 1193 | tbl = (const struct usb_devno *)((const char *)tbl + sz); |
| 1194 | } |
| 1195 | return NULL; |
| 1196 | } |
| 1197 | |
| 1198 | |
| 1199 | void |
| 1200 | usb_desc_iter_init(struct usbd_device *dev, usbd_desc_iter_t *iter) |
| 1201 | { |
| 1202 | const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); |
| 1203 | |
| 1204 | iter->cur = (const uByte *)cd; |
| 1205 | iter->end = (const uByte *)cd + UGETW(cd->wTotalLength); |
| 1206 | } |
| 1207 | |
| 1208 | const usb_descriptor_t * |
| 1209 | usb_desc_iter_next(usbd_desc_iter_t *iter) |
| 1210 | { |
| 1211 | const usb_descriptor_t *desc; |
| 1212 | |
| 1213 | if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) { |
| 1214 | if (iter->cur != iter->end) |
| 1215 | printf("usb_desc_iter_next: bad descriptor\n" ); |
| 1216 | return NULL; |
| 1217 | } |
| 1218 | desc = (const usb_descriptor_t *)iter->cur; |
| 1219 | if (desc->bLength == 0) { |
| 1220 | printf("usb_desc_iter_next: descriptor length = 0\n" ); |
| 1221 | return NULL; |
| 1222 | } |
| 1223 | iter->cur += desc->bLength; |
| 1224 | if (iter->cur > iter->end) { |
| 1225 | printf("usb_desc_iter_next: descriptor length too large\n" ); |
| 1226 | return NULL; |
| 1227 | } |
| 1228 | return desc; |
| 1229 | } |
| 1230 | |
| 1231 | usbd_status |
| 1232 | usbd_get_string(struct usbd_device *dev, int si, char *buf) |
| 1233 | { |
| 1234 | return usbd_get_string0(dev, si, buf, 1); |
| 1235 | } |
| 1236 | |
| 1237 | usbd_status |
| 1238 | usbd_get_string0(struct usbd_device *dev, int si, char *buf, int unicode) |
| 1239 | { |
| 1240 | int swap = dev->ud_quirks->uq_flags & UQ_SWAP_UNICODE; |
| 1241 | usb_string_descriptor_t us; |
| 1242 | char *s; |
| 1243 | int i, n; |
| 1244 | uint16_t c; |
| 1245 | usbd_status err; |
| 1246 | int size; |
| 1247 | |
| 1248 | USBHIST_FUNC(); USBHIST_CALLED(usbdebug); |
| 1249 | |
| 1250 | buf[0] = '\0'; |
| 1251 | if (si == 0) |
| 1252 | return USBD_INVAL; |
| 1253 | if (dev->ud_quirks->uq_flags & UQ_NO_STRINGS) |
| 1254 | return USBD_STALLED; |
| 1255 | if (dev->ud_langid == USBD_NOLANG) { |
| 1256 | /* Set up default language */ |
| 1257 | err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us, |
| 1258 | &size); |
| 1259 | if (err || size < 4) { |
| 1260 | USBHIST_LOG(usbdebug, "getting lang failed, using 0" , |
| 1261 | 0, 0, 0, 0); |
| 1262 | dev->ud_langid = 0; /* Well, just pick something then */ |
| 1263 | } else { |
| 1264 | /* Pick the first language as the default. */ |
| 1265 | dev->ud_langid = UGETW(us.bString[0]); |
| 1266 | } |
| 1267 | } |
| 1268 | err = usbd_get_string_desc(dev, si, dev->ud_langid, &us, &size); |
| 1269 | if (err) |
| 1270 | return err; |
| 1271 | s = buf; |
| 1272 | n = size / 2 - 1; |
| 1273 | if (unicode) { |
| 1274 | for (i = 0; i < n; i++) { |
| 1275 | c = UGETW(us.bString[i]); |
| 1276 | if (swap) |
| 1277 | c = (c >> 8) | (c << 8); |
| 1278 | s += wput_utf8(s, 3, c); |
| 1279 | } |
| 1280 | *s++ = 0; |
| 1281 | } |
| 1282 | #ifdef COMPAT_30 |
| 1283 | else { |
| 1284 | for (i = 0; i < n; i++) { |
| 1285 | c = UGETW(us.bString[i]); |
| 1286 | if (swap) |
| 1287 | c = (c >> 8) | (c << 8); |
| 1288 | *s++ = (c < 0x80) ? c : '?'; |
| 1289 | } |
| 1290 | *s++ = 0; |
| 1291 | } |
| 1292 | #endif |
| 1293 | return USBD_NORMAL_COMPLETION; |
| 1294 | } |
| 1295 | |