Annotation of sys/dev/usb/ugen.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ugen.c,v 1.50 2007/06/29 13:31:42 henning Exp $ */
! 2: /* $NetBSD: ugen.c,v 1.63 2002/11/26 18:49:48 christos Exp $ */
! 3: /* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */
! 4:
! 5: /*
! 6: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 7: * All rights reserved.
! 8: *
! 9: * This code is derived from software contributed to The NetBSD Foundation
! 10: * by Lennart Augustsson (lennart@augustsson.net) at
! 11: * Carlstedt Research & Technology.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. All advertising materials mentioning features or use of this software
! 22: * must display the following acknowledgement:
! 23: * This product includes software developed by the NetBSD
! 24: * Foundation, Inc. and its contributors.
! 25: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 39: * POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42:
! 43: #include <sys/param.h>
! 44: #include <sys/systm.h>
! 45: #include <sys/kernel.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/device.h>
! 48: #include <sys/ioctl.h>
! 49: #include <sys/conf.h>
! 50: #include <sys/tty.h>
! 51: #include <sys/file.h>
! 52: #include <sys/selinfo.h>
! 53: #include <sys/proc.h>
! 54: #include <sys/vnode.h>
! 55: #include <sys/poll.h>
! 56:
! 57: #include <dev/usb/usb.h>
! 58: #include <dev/usb/usbdi.h>
! 59: #include <dev/usb/usbdi_util.h>
! 60: #include <dev/usb/usbdevs.h>
! 61:
! 62: #ifdef UGEN_DEBUG
! 63: #define DPRINTF(x) do { if (ugendebug) printf x; } while (0)
! 64: #define DPRINTFN(n,x) do { if (ugendebug>(n)) printf x; } while (0)
! 65: int ugendebug = 0;
! 66: #else
! 67: #define DPRINTF(x)
! 68: #define DPRINTFN(n,x)
! 69: #endif
! 70:
! 71: #define UGEN_CHUNK 128 /* chunk size for read */
! 72: #define UGEN_IBSIZE 1020 /* buffer size */
! 73: #define UGEN_BBSIZE 1024
! 74:
! 75: #define UGEN_NISOFRAMES 500 /* 0.5 seconds worth */
! 76: #define UGEN_NISOREQS 6 /* number of outstanding xfer requests */
! 77: #define UGEN_NISORFRMS 4 /* number of frames (miliseconds) per req */
! 78:
! 79: struct ugen_endpoint {
! 80: struct ugen_softc *sc;
! 81: usb_endpoint_descriptor_t *edesc;
! 82: usbd_interface_handle iface;
! 83: int state;
! 84: #define UGEN_ASLP 0x02 /* waiting for data */
! 85: #define UGEN_SHORT_OK 0x04 /* short xfers are OK */
! 86: usbd_pipe_handle pipeh;
! 87: struct clist q;
! 88: struct selinfo rsel;
! 89: u_char *ibuf; /* start of buffer (circular for isoc) */
! 90: u_char *fill; /* location for input (isoc) */
! 91: u_char *limit; /* end of circular buffer (isoc) */
! 92: u_char *cur; /* current read location (isoc) */
! 93: u_int32_t timeout;
! 94: struct isoreq {
! 95: struct ugen_endpoint *sce;
! 96: usbd_xfer_handle xfer;
! 97: void *dmabuf;
! 98: u_int16_t sizes[UGEN_NISORFRMS];
! 99: } isoreqs[UGEN_NISOREQS];
! 100: };
! 101:
! 102: struct ugen_softc {
! 103: struct device sc_dev; /* base device */
! 104: usbd_device_handle sc_udev;
! 105:
! 106: char sc_is_open[USB_MAX_ENDPOINTS];
! 107: struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
! 108: #define OUT 0
! 109: #define IN 1
! 110:
! 111: int sc_refcnt;
! 112: u_char sc_dying;
! 113: };
! 114:
! 115: void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
! 116: usbd_status status);
! 117: void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
! 118: usbd_status status);
! 119: int ugen_do_read(struct ugen_softc *, int, struct uio *, int);
! 120: int ugen_do_write(struct ugen_softc *, int, struct uio *, int);
! 121: int ugen_do_ioctl(struct ugen_softc *, int, u_long,
! 122: caddr_t, int, struct proc *);
! 123: int ugen_set_config(struct ugen_softc *sc, int configno);
! 124: usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,
! 125: int index, int *lenp);
! 126: usbd_status ugen_set_interface(struct ugen_softc *, int, int);
! 127: int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);
! 128:
! 129: #define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
! 130: #define UGENENDPOINT(n) (minor(n) & 0xf)
! 131: #define UGENDEV(u, e) (makedev(0, ((u) << 4) | (e)))
! 132:
! 133: int ugen_match(struct device *, void *, void *);
! 134: void ugen_attach(struct device *, struct device *, void *);
! 135: int ugen_detach(struct device *, int);
! 136: int ugen_activate(struct device *, enum devact);
! 137:
! 138: struct cfdriver ugen_cd = {
! 139: NULL, "ugen", DV_DULL
! 140: };
! 141:
! 142: const struct cfattach ugen_ca = {
! 143: sizeof(struct ugen_softc),
! 144: ugen_match,
! 145: ugen_attach,
! 146: ugen_detach,
! 147: ugen_activate,
! 148: };
! 149:
! 150: int
! 151: ugen_match(struct device *parent, void *match, void *aux)
! 152: {
! 153: struct usb_attach_arg *uaa = aux;
! 154:
! 155: #if 0
! 156: if (uaa->matchlvl)
! 157: return (uaa->matchlvl);
! 158: #endif
! 159: if (uaa->usegeneric) {
! 160: #ifdef __macppc__
! 161: /*
! 162: * Some Apple laptops have USB phantom devices which match
! 163: * the ADB devices. We want to ignore them to avoid
! 164: * confusing users, as the real hardware underneath is adb
! 165: * and has already attached.
! 166: */
! 167: if (uaa->vendor == USB_VENDOR_APPLE &&
! 168: uaa->product == USB_PRODUCT_APPLE_ADB)
! 169: return (UMATCH_NONE);
! 170: #endif
! 171: return (UMATCH_GENERIC);
! 172: } else
! 173: return (UMATCH_NONE);
! 174: }
! 175:
! 176: void
! 177: ugen_attach(struct device *parent, struct device *self, void *aux)
! 178: {
! 179: struct ugen_softc *sc = (struct ugen_softc *)self;
! 180: struct usb_attach_arg *uaa = aux;
! 181: usbd_device_handle udev;
! 182: char *devinfop;
! 183: usbd_status err;
! 184: int conf;
! 185:
! 186: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 187: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 188: usbd_devinfo_free(devinfop);
! 189:
! 190: sc->sc_udev = udev = uaa->device;
! 191:
! 192: /* First set configuration index 0, the default one for ugen. */
! 193: err = usbd_set_config_index(udev, 0, 0);
! 194: if (err) {
! 195: printf("%s: setting configuration index 0 failed\n",
! 196: sc->sc_dev.dv_xname);
! 197: sc->sc_dying = 1;
! 198: return;
! 199: }
! 200: conf = usbd_get_config_descriptor(udev)->bConfigurationValue;
! 201:
! 202: /* Set up all the local state for this configuration. */
! 203: err = ugen_set_config(sc, conf);
! 204: if (err) {
! 205: printf("%s: setting configuration %d failed\n",
! 206: sc->sc_dev.dv_xname, conf);
! 207: sc->sc_dying = 1;
! 208: return;
! 209: }
! 210:
! 211: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
! 212: &sc->sc_dev);
! 213: }
! 214:
! 215: int
! 216: ugen_set_config(struct ugen_softc *sc, int configno)
! 217: {
! 218: usbd_device_handle dev = sc->sc_udev;
! 219: usbd_interface_handle iface;
! 220: usb_endpoint_descriptor_t *ed;
! 221: struct ugen_endpoint *sce;
! 222: u_int8_t niface, nendpt;
! 223: int ifaceno, endptno, endpt;
! 224: usbd_status err;
! 225: int dir;
! 226:
! 227: DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
! 228: sc->sc_dev.dv_xname, configno, sc));
! 229:
! 230: /*
! 231: * We start at 1, not 0, because we don't care whether the
! 232: * control endpoint is open or not. It is always present.
! 233: */
! 234: for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++)
! 235: if (sc->sc_is_open[endptno]) {
! 236: DPRINTFN(1,
! 237: ("ugen_set_config: %s - endpoint %d is open\n",
! 238: sc->sc_dev.dv_xname, endptno));
! 239: return (USBD_IN_USE);
! 240: }
! 241:
! 242: /* Avoid setting the current value. */
! 243: if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
! 244: err = usbd_set_config_no(dev, configno, 1);
! 245: if (err)
! 246: return (err);
! 247: }
! 248:
! 249: err = usbd_interface_count(dev, &niface);
! 250: if (err)
! 251: return (err);
! 252: memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
! 253: for (ifaceno = 0; ifaceno < niface; ifaceno++) {
! 254: DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
! 255: err = usbd_device2interface_handle(dev, ifaceno, &iface);
! 256: if (err)
! 257: return (err);
! 258: err = usbd_endpoint_count(iface, &nendpt);
! 259: if (err)
! 260: return (err);
! 261: for (endptno = 0; endptno < nendpt; endptno++) {
! 262: ed = usbd_interface2endpoint_descriptor(iface,endptno);
! 263: endpt = ed->bEndpointAddress;
! 264: dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
! 265: sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
! 266: DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
! 267: "(%d,%d), sce=%p\n",
! 268: endptno, endpt, UE_GET_ADDR(endpt),
! 269: UE_GET_DIR(endpt), sce));
! 270: sce->sc = sc;
! 271: sce->edesc = ed;
! 272: sce->iface = iface;
! 273: }
! 274: }
! 275: return (USBD_NORMAL_COMPLETION);
! 276: }
! 277:
! 278: int
! 279: ugenopen(dev_t dev, int flag, int mode, struct proc *p)
! 280: {
! 281: struct ugen_softc *sc;
! 282: int unit = UGENUNIT(dev);
! 283: int endpt = UGENENDPOINT(dev);
! 284: usb_endpoint_descriptor_t *edesc;
! 285: struct ugen_endpoint *sce;
! 286: int dir, isize;
! 287: usbd_status err;
! 288: usbd_xfer_handle xfer;
! 289: void *buf;
! 290: int i, j;
! 291:
! 292: if (unit >= ugen_cd.cd_ndevs)
! 293: return (ENXIO);
! 294: sc = ugen_cd.cd_devs[unit];
! 295: if (sc == NULL)
! 296: return (ENXIO);
! 297:
! 298: DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n",
! 299: flag, mode, unit, endpt));
! 300:
! 301: if (sc == NULL || sc->sc_dying)
! 302: return (ENXIO);
! 303:
! 304: if (sc->sc_is_open[endpt])
! 305: return (EBUSY);
! 306:
! 307: if (endpt == USB_CONTROL_ENDPOINT) {
! 308: sc->sc_is_open[USB_CONTROL_ENDPOINT] = 1;
! 309: return (0);
! 310: }
! 311:
! 312: /* Make sure there are pipes for all directions. */
! 313: for (dir = OUT; dir <= IN; dir++) {
! 314: if (flag & (dir == OUT ? FWRITE : FREAD)) {
! 315: sce = &sc->sc_endpoints[endpt][dir];
! 316: if (sce == 0 || sce->edesc == 0)
! 317: return (ENXIO);
! 318: }
! 319: }
! 320:
! 321: /* Actually open the pipes. */
! 322: /* XXX Should back out properly if it fails. */
! 323: for (dir = OUT; dir <= IN; dir++) {
! 324: if (!(flag & (dir == OUT ? FWRITE : FREAD)))
! 325: continue;
! 326: sce = &sc->sc_endpoints[endpt][dir];
! 327: sce->state = 0;
! 328: sce->timeout = USBD_NO_TIMEOUT;
! 329: DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
! 330: sc, endpt, dir, sce));
! 331: edesc = sce->edesc;
! 332: switch (edesc->bmAttributes & UE_XFERTYPE) {
! 333: case UE_INTERRUPT:
! 334: if (dir == OUT) {
! 335: err = usbd_open_pipe(sce->iface,
! 336: edesc->bEndpointAddress, 0, &sce->pipeh);
! 337: if (err)
! 338: return (EIO);
! 339: break;
! 340: }
! 341: isize = UGETW(edesc->wMaxPacketSize);
! 342: if (isize == 0) /* shouldn't happen */
! 343: return (EINVAL);
! 344: sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
! 345: DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
! 346: endpt, isize));
! 347: if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
! 348: return (ENOMEM);
! 349: err = usbd_open_pipe_intr(sce->iface,
! 350: edesc->bEndpointAddress,
! 351: USBD_SHORT_XFER_OK, &sce->pipeh, sce,
! 352: sce->ibuf, isize, ugenintr,
! 353: USBD_DEFAULT_INTERVAL);
! 354: if (err) {
! 355: free(sce->ibuf, M_USBDEV);
! 356: clfree(&sce->q);
! 357: return (EIO);
! 358: }
! 359: DPRINTFN(5, ("ugenopen: interrupt open done\n"));
! 360: break;
! 361: case UE_BULK:
! 362: err = usbd_open_pipe(sce->iface,
! 363: edesc->bEndpointAddress, 0, &sce->pipeh);
! 364: if (err)
! 365: return (EIO);
! 366: break;
! 367: case UE_ISOCHRONOUS:
! 368: if (dir == OUT)
! 369: return (EINVAL);
! 370: isize = UGETW(edesc->wMaxPacketSize);
! 371: if (isize == 0) /* shouldn't happen */
! 372: return (EINVAL);
! 373: sce->ibuf = malloc(isize * UGEN_NISOFRAMES,
! 374: M_USBDEV, M_WAITOK);
! 375: sce->cur = sce->fill = sce->ibuf;
! 376: sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES;
! 377: DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n",
! 378: endpt, isize));
! 379: err = usbd_open_pipe(sce->iface,
! 380: edesc->bEndpointAddress, 0, &sce->pipeh);
! 381: if (err) {
! 382: free(sce->ibuf, M_USBDEV);
! 383: return (EIO);
! 384: }
! 385: for(i = 0; i < UGEN_NISOREQS; ++i) {
! 386: sce->isoreqs[i].sce = sce;
! 387: xfer = usbd_alloc_xfer(sc->sc_udev);
! 388: if (xfer == 0)
! 389: goto bad;
! 390: sce->isoreqs[i].xfer = xfer;
! 391: buf = usbd_alloc_buffer
! 392: (xfer, isize * UGEN_NISORFRMS);
! 393: if (buf == 0) {
! 394: i++;
! 395: goto bad;
! 396: }
! 397: sce->isoreqs[i].dmabuf = buf;
! 398: for(j = 0; j < UGEN_NISORFRMS; ++j)
! 399: sce->isoreqs[i].sizes[j] = isize;
! 400: usbd_setup_isoc_xfer
! 401: (xfer, sce->pipeh, &sce->isoreqs[i],
! 402: sce->isoreqs[i].sizes,
! 403: UGEN_NISORFRMS, USBD_NO_COPY,
! 404: ugen_isoc_rintr);
! 405: (void)usbd_transfer(xfer);
! 406: }
! 407: DPRINTFN(5, ("ugenopen: isoc open done\n"));
! 408: break;
! 409: bad:
! 410: while (--i >= 0) /* implicit buffer free */
! 411: usbd_free_xfer(sce->isoreqs[i].xfer);
! 412: return (ENOMEM);
! 413: case UE_CONTROL:
! 414: sce->timeout = USBD_DEFAULT_TIMEOUT;
! 415: return (EINVAL);
! 416: }
! 417: }
! 418: sc->sc_is_open[endpt] = 1;
! 419: return (0);
! 420: }
! 421:
! 422: int
! 423: ugenclose(dev_t dev, int flag, int mode, struct proc *p)
! 424: {
! 425: int endpt = UGENENDPOINT(dev);
! 426: struct ugen_softc *sc;
! 427: struct ugen_endpoint *sce;
! 428: int dir;
! 429: int i;
! 430:
! 431: sc = ugen_cd.cd_devs[UGENUNIT(dev)];
! 432:
! 433: DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
! 434: flag, mode, UGENUNIT(dev), endpt));
! 435:
! 436: #ifdef DIAGNOSTIC
! 437: if (!sc->sc_is_open[endpt]) {
! 438: printf("ugenclose: not open\n");
! 439: return (EINVAL);
! 440: }
! 441: #endif
! 442:
! 443: if (endpt == USB_CONTROL_ENDPOINT) {
! 444: DPRINTFN(5, ("ugenclose: close control\n"));
! 445: sc->sc_is_open[endpt] = 0;
! 446: return (0);
! 447: }
! 448:
! 449: for (dir = OUT; dir <= IN; dir++) {
! 450: if (!(flag & (dir == OUT ? FWRITE : FREAD)))
! 451: continue;
! 452: sce = &sc->sc_endpoints[endpt][dir];
! 453: if (sce == NULL || sce->pipeh == NULL)
! 454: continue;
! 455: DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n",
! 456: endpt, dir, sce));
! 457:
! 458: usbd_abort_pipe(sce->pipeh);
! 459: usbd_close_pipe(sce->pipeh);
! 460: sce->pipeh = NULL;
! 461:
! 462: switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
! 463: case UE_INTERRUPT:
! 464: ndflush(&sce->q, sce->q.c_cc);
! 465: clfree(&sce->q);
! 466: break;
! 467: case UE_ISOCHRONOUS:
! 468: for (i = 0; i < UGEN_NISOREQS; ++i)
! 469: usbd_free_xfer(sce->isoreqs[i].xfer);
! 470:
! 471: default:
! 472: break;
! 473: }
! 474:
! 475: if (sce->ibuf != NULL) {
! 476: free(sce->ibuf, M_USBDEV);
! 477: sce->ibuf = NULL;
! 478: clfree(&sce->q);
! 479: }
! 480: }
! 481: sc->sc_is_open[endpt] = 0;
! 482:
! 483: return (0);
! 484: }
! 485:
! 486: int
! 487: ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
! 488: {
! 489: struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
! 490: u_int32_t n, tn;
! 491: char buf[UGEN_BBSIZE];
! 492: usbd_xfer_handle xfer;
! 493: usbd_status err;
! 494: int s;
! 495: int error = 0;
! 496: u_char buffer[UGEN_CHUNK];
! 497:
! 498: DPRINTFN(5, ("%s: ugenread: %d\n", sc->sc_dev.dv_xname, endpt));
! 499:
! 500: if (sc->sc_dying)
! 501: return (EIO);
! 502:
! 503: if (endpt == USB_CONTROL_ENDPOINT)
! 504: return (ENODEV);
! 505:
! 506: #ifdef DIAGNOSTIC
! 507: if (sce->edesc == NULL) {
! 508: printf("ugenread: no edesc\n");
! 509: return (EIO);
! 510: }
! 511: if (sce->pipeh == NULL) {
! 512: printf("ugenread: no pipe\n");
! 513: return (EIO);
! 514: }
! 515: #endif
! 516:
! 517: switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
! 518: case UE_INTERRUPT:
! 519: /* Block until activity occurred. */
! 520: s = splusb();
! 521: while (sce->q.c_cc == 0) {
! 522: if (flag & IO_NDELAY) {
! 523: splx(s);
! 524: return (EWOULDBLOCK);
! 525: }
! 526: sce->state |= UGEN_ASLP;
! 527: DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
! 528: error = tsleep(sce, PZERO | PCATCH, "ugenri",
! 529: (sce->timeout * hz) / 1000);
! 530: DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
! 531: if (sc->sc_dying)
! 532: error = EIO;
! 533: if (error == EWOULDBLOCK) { /* timeout, return 0 */
! 534: error = 0;
! 535: break;
! 536: }
! 537: if (error) {
! 538: sce->state &= ~UGEN_ASLP;
! 539: break;
! 540: }
! 541: }
! 542: splx(s);
! 543:
! 544: /* Transfer as many chunks as possible. */
! 545: while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
! 546: n = min(sce->q.c_cc, uio->uio_resid);
! 547: if (n > sizeof(buffer))
! 548: n = sizeof(buffer);
! 549:
! 550: /* Remove a small chunk from the input queue. */
! 551: q_to_b(&sce->q, buffer, n);
! 552: DPRINTFN(5, ("ugenread: got %d chars\n", n));
! 553:
! 554: /* Copy the data to the user process. */
! 555: error = uiomove(buffer, n, uio);
! 556: if (error)
! 557: break;
! 558: }
! 559: break;
! 560: case UE_BULK:
! 561: xfer = usbd_alloc_xfer(sc->sc_udev);
! 562: if (xfer == 0)
! 563: return (ENOMEM);
! 564: while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
! 565: DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
! 566: tn = n;
! 567: err = usbd_bulk_transfer(
! 568: xfer, sce->pipeh,
! 569: sce->state & UGEN_SHORT_OK ?
! 570: USBD_SHORT_XFER_OK : 0,
! 571: sce->timeout, buf, &tn, "ugenrb");
! 572: if (err) {
! 573: if (err == USBD_INTERRUPTED)
! 574: error = EINTR;
! 575: else if (err == USBD_TIMEOUT)
! 576: error = ETIMEDOUT;
! 577: else
! 578: error = EIO;
! 579: break;
! 580: }
! 581: DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
! 582: error = uiomove(buf, tn, uio);
! 583: if (error || tn < n)
! 584: break;
! 585: }
! 586: usbd_free_xfer(xfer);
! 587: break;
! 588: case UE_ISOCHRONOUS:
! 589: s = splusb();
! 590: while (sce->cur == sce->fill) {
! 591: if (flag & IO_NDELAY) {
! 592: splx(s);
! 593: return (EWOULDBLOCK);
! 594: }
! 595: sce->state |= UGEN_ASLP;
! 596: DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
! 597: error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
! 598: DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
! 599: if (sc->sc_dying)
! 600: error = EIO;
! 601: if (error) {
! 602: sce->state &= ~UGEN_ASLP;
! 603: break;
! 604: }
! 605: }
! 606:
! 607: while (sce->cur != sce->fill && uio->uio_resid > 0 && !error) {
! 608: if(sce->fill > sce->cur)
! 609: n = min(sce->fill - sce->cur, uio->uio_resid);
! 610: else
! 611: n = min(sce->limit - sce->cur, uio->uio_resid);
! 612:
! 613: DPRINTFN(5, ("ugenread: isoc got %d chars\n", n));
! 614:
! 615: /* Copy the data to the user process. */
! 616: error = uiomove(sce->cur, n, uio);
! 617: if (error)
! 618: break;
! 619: sce->cur += n;
! 620: if(sce->cur >= sce->limit)
! 621: sce->cur = sce->ibuf;
! 622: }
! 623: splx(s);
! 624: break;
! 625:
! 626:
! 627: default:
! 628: return (ENXIO);
! 629: }
! 630: return (error);
! 631: }
! 632:
! 633: int
! 634: ugenread(dev_t dev, struct uio *uio, int flag)
! 635: {
! 636: int endpt = UGENENDPOINT(dev);
! 637: struct ugen_softc *sc;
! 638: int error;
! 639:
! 640: sc = ugen_cd.cd_devs[UGENUNIT(dev)];
! 641:
! 642: sc->sc_refcnt++;
! 643: error = ugen_do_read(sc, endpt, uio, flag);
! 644: if (--sc->sc_refcnt < 0)
! 645: usb_detach_wakeup(&sc->sc_dev);
! 646: return (error);
! 647: }
! 648:
! 649: int
! 650: ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
! 651: {
! 652: struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
! 653: u_int32_t n;
! 654: int error = 0;
! 655: char buf[UGEN_BBSIZE];
! 656: usbd_xfer_handle xfer;
! 657: usbd_status err;
! 658:
! 659: DPRINTFN(5, ("%s: ugenwrite: %d\n", sc->sc_dev.dv_xname, endpt));
! 660:
! 661: if (sc->sc_dying)
! 662: return (EIO);
! 663:
! 664: if (endpt == USB_CONTROL_ENDPOINT)
! 665: return (ENODEV);
! 666:
! 667: #ifdef DIAGNOSTIC
! 668: if (sce->edesc == NULL) {
! 669: printf("ugenwrite: no edesc\n");
! 670: return (EIO);
! 671: }
! 672: if (sce->pipeh == NULL) {
! 673: printf("ugenwrite: no pipe\n");
! 674: return (EIO);
! 675: }
! 676: #endif
! 677:
! 678: switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
! 679: case UE_BULK:
! 680: xfer = usbd_alloc_xfer(sc->sc_udev);
! 681: if (xfer == 0)
! 682: return (EIO);
! 683: while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
! 684: error = uiomove(buf, n, uio);
! 685: if (error)
! 686: break;
! 687: DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
! 688: err = usbd_bulk_transfer(xfer, sce->pipeh, 0,
! 689: sce->timeout, buf, &n,"ugenwb");
! 690: if (err) {
! 691: if (err == USBD_INTERRUPTED)
! 692: error = EINTR;
! 693: else if (err == USBD_TIMEOUT)
! 694: error = ETIMEDOUT;
! 695: else
! 696: error = EIO;
! 697: break;
! 698: }
! 699: }
! 700: usbd_free_xfer(xfer);
! 701: break;
! 702: case UE_INTERRUPT:
! 703: xfer = usbd_alloc_xfer(sc->sc_udev);
! 704: if (xfer == 0)
! 705: return (EIO);
! 706: while ((n = min(UGETW(sce->edesc->wMaxPacketSize),
! 707: uio->uio_resid)) != 0) {
! 708: error = uiomove(buf, n, uio);
! 709: if (error)
! 710: break;
! 711: DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
! 712: err = usbd_intr_transfer(xfer, sce->pipeh, 0,
! 713: sce->timeout, buf, &n, "ugenwi");
! 714: if (err) {
! 715: if (err == USBD_INTERRUPTED)
! 716: error = EINTR;
! 717: else if (err == USBD_TIMEOUT)
! 718: error = ETIMEDOUT;
! 719: else
! 720: error = EIO;
! 721: break;
! 722: }
! 723: }
! 724: usbd_free_xfer(xfer);
! 725: break;
! 726: default:
! 727: return (ENXIO);
! 728: }
! 729: return (error);
! 730: }
! 731:
! 732: int
! 733: ugenwrite(dev_t dev, struct uio *uio, int flag)
! 734: {
! 735: int endpt = UGENENDPOINT(dev);
! 736: struct ugen_softc *sc;
! 737: int error;
! 738:
! 739: sc = ugen_cd.cd_devs[UGENUNIT(dev)];
! 740:
! 741: sc->sc_refcnt++;
! 742: error = ugen_do_write(sc, endpt, uio, flag);
! 743: if (--sc->sc_refcnt < 0)
! 744: usb_detach_wakeup(&sc->sc_dev);
! 745: return (error);
! 746: }
! 747:
! 748: int
! 749: ugen_activate(struct device *self, enum devact act)
! 750: {
! 751: struct ugen_softc *sc = (struct ugen_softc *)self;
! 752:
! 753: switch (act) {
! 754: case DVACT_ACTIVATE:
! 755: break;
! 756:
! 757: case DVACT_DEACTIVATE:
! 758: sc->sc_dying = 1;
! 759: break;
! 760: }
! 761: return (0);
! 762: }
! 763:
! 764: int
! 765: ugen_detach(struct device *self, int flags)
! 766: {
! 767: struct ugen_softc *sc = (struct ugen_softc *)self;
! 768: struct ugen_endpoint *sce;
! 769: int i, dir;
! 770: int s;
! 771: int maj, mn;
! 772:
! 773: DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
! 774:
! 775: sc->sc_dying = 1;
! 776: /* Abort all pipes. Causes processes waiting for transfer to wake. */
! 777: for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
! 778: for (dir = OUT; dir <= IN; dir++) {
! 779: sce = &sc->sc_endpoints[i][dir];
! 780: if (sce && sce->pipeh)
! 781: usbd_abort_pipe(sce->pipeh);
! 782: }
! 783: }
! 784:
! 785: s = splusb();
! 786: if (--sc->sc_refcnt >= 0) {
! 787: /* Wake everyone */
! 788: for (i = 0; i < USB_MAX_ENDPOINTS; i++)
! 789: wakeup(&sc->sc_endpoints[i][IN]);
! 790: /* Wait for processes to go away. */
! 791: usb_detach_wait(&sc->sc_dev);
! 792: }
! 793: splx(s);
! 794:
! 795: /* locate the major number */
! 796: for (maj = 0; maj < nchrdev; maj++)
! 797: if (cdevsw[maj].d_open == ugenopen)
! 798: break;
! 799:
! 800: /* Nuke the vnodes for any open instances (calls close). */
! 801: mn = self->dv_unit * USB_MAX_ENDPOINTS;
! 802: vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
! 803:
! 804: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 805: &sc->sc_dev);
! 806:
! 807: return (0);
! 808: }
! 809:
! 810: void
! 811: ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
! 812: {
! 813: struct ugen_endpoint *sce = addr;
! 814: /*struct ugen_softc *sc = sce->sc;*/
! 815: u_int32_t count;
! 816: u_char *ibuf;
! 817:
! 818: if (status == USBD_CANCELLED)
! 819: return;
! 820:
! 821: if (status != USBD_NORMAL_COMPLETION) {
! 822: DPRINTF(("ugenintr: status=%d\n", status));
! 823: if (status == USBD_STALLED)
! 824: usbd_clear_endpoint_stall_async(sce->pipeh);
! 825: return;
! 826: }
! 827:
! 828: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
! 829: ibuf = sce->ibuf;
! 830:
! 831: DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n",
! 832: xfer, status, count));
! 833: DPRINTFN(5, (" data = %02x %02x %02x\n",
! 834: ibuf[0], ibuf[1], ibuf[2]));
! 835:
! 836: (void)b_to_q(ibuf, count, &sce->q);
! 837:
! 838: if (sce->state & UGEN_ASLP) {
! 839: sce->state &= ~UGEN_ASLP;
! 840: DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
! 841: wakeup(sce);
! 842: }
! 843: selwakeup(&sce->rsel);
! 844: }
! 845:
! 846: void
! 847: ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
! 848: usbd_status status)
! 849: {
! 850: struct isoreq *req = addr;
! 851: struct ugen_endpoint *sce = req->sce;
! 852: u_int32_t count, n;
! 853: int i, isize;
! 854:
! 855: /* Return if we are aborting. */
! 856: if (status == USBD_CANCELLED)
! 857: return;
! 858:
! 859: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
! 860: DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n", req - sce->isoreqs,
! 861: count));
! 862:
! 863: /* throw away oldest input if the buffer is full */
! 864: if(sce->fill < sce->cur && sce->cur <= sce->fill + count) {
! 865: sce->cur += count;
! 866: if(sce->cur >= sce->limit)
! 867: sce->cur = sce->ibuf + (sce->limit - sce->cur);
! 868: DPRINTFN(5, ("ugen_isoc_rintr: throwing away %d bytes\n",
! 869: count));
! 870: }
! 871:
! 872: isize = UGETW(sce->edesc->wMaxPacketSize);
! 873: for (i = 0; i < UGEN_NISORFRMS; i++) {
! 874: u_int32_t actlen = req->sizes[i];
! 875: char const *buf = (char const *)req->dmabuf + isize * i;
! 876:
! 877: /* copy data to buffer */
! 878: while (actlen > 0) {
! 879: n = min(actlen, sce->limit - sce->fill);
! 880: memcpy(sce->fill, buf, n);
! 881:
! 882: buf += n;
! 883: actlen -= n;
! 884: sce->fill += n;
! 885: if(sce->fill == sce->limit)
! 886: sce->fill = sce->ibuf;
! 887: }
! 888:
! 889: /* setup size for next transfer */
! 890: req->sizes[i] = isize;
! 891: }
! 892:
! 893: usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,
! 894: USBD_NO_COPY, ugen_isoc_rintr);
! 895: (void)usbd_transfer(xfer);
! 896:
! 897: if (sce->state & UGEN_ASLP) {
! 898: sce->state &= ~UGEN_ASLP;
! 899: DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));
! 900: wakeup(sce);
! 901: }
! 902: selwakeup(&sce->rsel);
! 903: }
! 904:
! 905: usbd_status
! 906: ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
! 907: {
! 908: usbd_interface_handle iface;
! 909: usb_endpoint_descriptor_t *ed;
! 910: usbd_status err;
! 911: struct ugen_endpoint *sce;
! 912: u_int8_t niface, nendpt, endptno, endpt;
! 913: int dir;
! 914:
! 915: DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
! 916:
! 917: err = usbd_interface_count(sc->sc_udev, &niface);
! 918: if (err)
! 919: return (err);
! 920: if (ifaceidx < 0 || ifaceidx >= niface)
! 921: return (USBD_INVAL);
! 922:
! 923: err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
! 924: if (err)
! 925: return (err);
! 926: err = usbd_endpoint_count(iface, &nendpt);
! 927: if (err)
! 928: return (err);
! 929: /* XXX should only do this after setting new altno has succeeded */
! 930: for (endptno = 0; endptno < nendpt; endptno++) {
! 931: ed = usbd_interface2endpoint_descriptor(iface,endptno);
! 932: endpt = ed->bEndpointAddress;
! 933: dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
! 934: sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
! 935: sce->sc = 0;
! 936: sce->edesc = 0;
! 937: sce->iface = 0;
! 938: }
! 939:
! 940: /* change setting */
! 941: err = usbd_set_interface(iface, altno);
! 942: if (err)
! 943: return (err);
! 944:
! 945: err = usbd_endpoint_count(iface, &nendpt);
! 946: if (err)
! 947: return (err);
! 948: for (endptno = 0; endptno < nendpt; endptno++) {
! 949: ed = usbd_interface2endpoint_descriptor(iface,endptno);
! 950: endpt = ed->bEndpointAddress;
! 951: dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
! 952: sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
! 953: sce->sc = sc;
! 954: sce->edesc = ed;
! 955: sce->iface = iface;
! 956: }
! 957: return (0);
! 958: }
! 959:
! 960: /* Retrieve a complete descriptor for a certain device and index. */
! 961: usb_config_descriptor_t *
! 962: ugen_get_cdesc(struct ugen_softc *sc, int index, int *lenp)
! 963: {
! 964: usb_config_descriptor_t *cdesc, *tdesc, cdescr;
! 965: int len;
! 966: usbd_status err;
! 967:
! 968: if (index == USB_CURRENT_CONFIG_INDEX) {
! 969: tdesc = usbd_get_config_descriptor(sc->sc_udev);
! 970: len = UGETW(tdesc->wTotalLength);
! 971: if (lenp)
! 972: *lenp = len;
! 973: cdesc = malloc(len, M_TEMP, M_WAITOK);
! 974: memcpy(cdesc, tdesc, len);
! 975: DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
! 976: } else {
! 977: err = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
! 978: if (err)
! 979: return (0);
! 980: len = UGETW(cdescr.wTotalLength);
! 981: DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
! 982: if (lenp)
! 983: *lenp = len;
! 984: cdesc = malloc(len, M_TEMP, M_WAITOK);
! 985: err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc,
! 986: len);
! 987: if (err) {
! 988: free(cdesc, M_TEMP);
! 989: return (0);
! 990: }
! 991: }
! 992: return (cdesc);
! 993: }
! 994:
! 995: int
! 996: ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx)
! 997: {
! 998: usbd_interface_handle iface;
! 999: usbd_status err;
! 1000:
! 1001: err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
! 1002: if (err)
! 1003: return (-1);
! 1004: return (usbd_get_interface_altindex(iface));
! 1005: }
! 1006:
! 1007: int
! 1008: ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
! 1009: caddr_t addr, int flag, struct proc *p)
! 1010: {
! 1011: struct ugen_endpoint *sce;
! 1012: usbd_status err;
! 1013: usbd_interface_handle iface;
! 1014: struct usb_config_desc *cd;
! 1015: usb_config_descriptor_t *cdesc;
! 1016: struct usb_interface_desc *id;
! 1017: usb_interface_descriptor_t *idesc;
! 1018: struct usb_endpoint_desc *ed;
! 1019: usb_endpoint_descriptor_t *edesc;
! 1020: struct usb_alt_interface *ai;
! 1021: struct usb_string_desc *si;
! 1022: u_int8_t conf, alt;
! 1023:
! 1024: DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
! 1025: if (sc->sc_dying)
! 1026: return (EIO);
! 1027:
! 1028: switch (cmd) {
! 1029: case FIONBIO:
! 1030: /* All handled in the upper FS layer. */
! 1031: return (0);
! 1032: case USB_SET_SHORT_XFER:
! 1033: if (endpt == USB_CONTROL_ENDPOINT)
! 1034: return (EINVAL);
! 1035: /* This flag only affects read */
! 1036: sce = &sc->sc_endpoints[endpt][IN];
! 1037: if (sce == NULL || sce->pipeh == NULL)
! 1038: return (EINVAL);
! 1039: if (*(int *)addr)
! 1040: sce->state |= UGEN_SHORT_OK;
! 1041: else
! 1042: sce->state &= ~UGEN_SHORT_OK;
! 1043: return (0);
! 1044: case USB_SET_TIMEOUT:
! 1045: sce = &sc->sc_endpoints[endpt][IN];
! 1046: if (sce == NULL
! 1047: /* XXX this shouldn't happen, but the distinction between
! 1048: input and output pipes isn't clear enough.
! 1049: || sce->pipeh == NULL */
! 1050: )
! 1051: return (EINVAL);
! 1052: sce->timeout = *(int *)addr;
! 1053: return (0);
! 1054: default:
! 1055: break;
! 1056: }
! 1057:
! 1058: if (endpt != USB_CONTROL_ENDPOINT)
! 1059: return (EINVAL);
! 1060:
! 1061: switch (cmd) {
! 1062: #ifdef UGEN_DEBUG
! 1063: case USB_SETDEBUG:
! 1064: ugendebug = *(int *)addr;
! 1065: break;
! 1066: #endif
! 1067: case USB_GET_CONFIG:
! 1068: err = usbd_get_config(sc->sc_udev, &conf);
! 1069: if (err)
! 1070: return (EIO);
! 1071: *(int *)addr = conf;
! 1072: break;
! 1073: case USB_SET_CONFIG:
! 1074: if (!(flag & FWRITE))
! 1075: return (EPERM);
! 1076: err = ugen_set_config(sc, *(int *)addr);
! 1077: switch (err) {
! 1078: case USBD_NORMAL_COMPLETION:
! 1079: break;
! 1080: case USBD_IN_USE:
! 1081: return (EBUSY);
! 1082: default:
! 1083: return (EIO);
! 1084: }
! 1085: break;
! 1086: case USB_GET_ALTINTERFACE:
! 1087: ai = (struct usb_alt_interface *)addr;
! 1088: err = usbd_device2interface_handle(sc->sc_udev,
! 1089: ai->uai_interface_index, &iface);
! 1090: if (err)
! 1091: return (EINVAL);
! 1092: idesc = usbd_get_interface_descriptor(iface);
! 1093: if (idesc == NULL)
! 1094: return (EIO);
! 1095: ai->uai_alt_no = idesc->bAlternateSetting;
! 1096: break;
! 1097: case USB_SET_ALTINTERFACE:
! 1098: if (!(flag & FWRITE))
! 1099: return (EPERM);
! 1100: ai = (struct usb_alt_interface *)addr;
! 1101: err = usbd_device2interface_handle(sc->sc_udev,
! 1102: ai->uai_interface_index, &iface);
! 1103: if (err)
! 1104: return (EINVAL);
! 1105: err = ugen_set_interface(sc, ai->uai_interface_index,
! 1106: ai->uai_alt_no);
! 1107: if (err)
! 1108: return (EINVAL);
! 1109: break;
! 1110: case USB_GET_NO_ALT:
! 1111: ai = (struct usb_alt_interface *)addr;
! 1112: cdesc = ugen_get_cdesc(sc, ai->uai_config_index, 0);
! 1113: if (cdesc == NULL)
! 1114: return (EINVAL);
! 1115: idesc = usbd_find_idesc(cdesc, ai->uai_interface_index, 0);
! 1116: if (idesc == NULL) {
! 1117: free(cdesc, M_TEMP);
! 1118: return (EINVAL);
! 1119: }
! 1120: ai->uai_alt_no = usbd_get_no_alts(cdesc,
! 1121: idesc->bInterfaceNumber);
! 1122: free(cdesc, M_TEMP);
! 1123: break;
! 1124: case USB_GET_DEVICE_DESC:
! 1125: *(usb_device_descriptor_t *)addr =
! 1126: *usbd_get_device_descriptor(sc->sc_udev);
! 1127: break;
! 1128: case USB_GET_CONFIG_DESC:
! 1129: cd = (struct usb_config_desc *)addr;
! 1130: cdesc = ugen_get_cdesc(sc, cd->ucd_config_index, 0);
! 1131: if (cdesc == NULL)
! 1132: return (EINVAL);
! 1133: cd->ucd_desc = *cdesc;
! 1134: free(cdesc, M_TEMP);
! 1135: break;
! 1136: case USB_GET_INTERFACE_DESC:
! 1137: id = (struct usb_interface_desc *)addr;
! 1138: cdesc = ugen_get_cdesc(sc, id->uid_config_index, 0);
! 1139: if (cdesc == NULL)
! 1140: return (EINVAL);
! 1141: if (id->uid_config_index == USB_CURRENT_CONFIG_INDEX &&
! 1142: id->uid_alt_index == USB_CURRENT_ALT_INDEX)
! 1143: alt = ugen_get_alt_index(sc, id->uid_interface_index);
! 1144: else
! 1145: alt = id->uid_alt_index;
! 1146: idesc = usbd_find_idesc(cdesc, id->uid_interface_index, alt);
! 1147: if (idesc == NULL) {
! 1148: free(cdesc, M_TEMP);
! 1149: return (EINVAL);
! 1150: }
! 1151: id->uid_desc = *idesc;
! 1152: free(cdesc, M_TEMP);
! 1153: break;
! 1154: case USB_GET_ENDPOINT_DESC:
! 1155: ed = (struct usb_endpoint_desc *)addr;
! 1156: cdesc = ugen_get_cdesc(sc, ed->ued_config_index, 0);
! 1157: if (cdesc == NULL)
! 1158: return (EINVAL);
! 1159: if (ed->ued_config_index == USB_CURRENT_CONFIG_INDEX &&
! 1160: ed->ued_alt_index == USB_CURRENT_ALT_INDEX)
! 1161: alt = ugen_get_alt_index(sc, ed->ued_interface_index);
! 1162: else
! 1163: alt = ed->ued_alt_index;
! 1164: edesc = usbd_find_edesc(cdesc, ed->ued_interface_index,
! 1165: alt, ed->ued_endpoint_index);
! 1166: if (edesc == NULL) {
! 1167: free(cdesc, M_TEMP);
! 1168: return (EINVAL);
! 1169: }
! 1170: ed->ued_desc = *edesc;
! 1171: free(cdesc, M_TEMP);
! 1172: break;
! 1173: case USB_GET_FULL_DESC:
! 1174: {
! 1175: int len;
! 1176: struct iovec iov;
! 1177: struct uio uio;
! 1178: struct usb_full_desc *fd = (struct usb_full_desc *)addr;
! 1179: int error;
! 1180:
! 1181: cdesc = ugen_get_cdesc(sc, fd->ufd_config_index, &len);
! 1182: if (len > fd->ufd_size)
! 1183: len = fd->ufd_size;
! 1184: iov.iov_base = (caddr_t)fd->ufd_data;
! 1185: iov.iov_len = len;
! 1186: uio.uio_iov = &iov;
! 1187: uio.uio_iovcnt = 1;
! 1188: uio.uio_resid = len;
! 1189: uio.uio_offset = 0;
! 1190: uio.uio_segflg = UIO_USERSPACE;
! 1191: uio.uio_rw = UIO_READ;
! 1192: uio.uio_procp = p;
! 1193: error = uiomove((void *)cdesc, len, &uio);
! 1194: free(cdesc, M_TEMP);
! 1195: return (error);
! 1196: }
! 1197: case USB_GET_STRING_DESC:
! 1198: {
! 1199: int len;
! 1200: si = (struct usb_string_desc *)addr;
! 1201: err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index,
! 1202: si->usd_language_id, &si->usd_desc, &len);
! 1203: if (err)
! 1204: return (EINVAL);
! 1205: break;
! 1206: }
! 1207: case USB_DO_REQUEST:
! 1208: {
! 1209: struct usb_ctl_request *ur = (void *)addr;
! 1210: int len = UGETW(ur->ucr_request.wLength);
! 1211: struct iovec iov;
! 1212: struct uio uio;
! 1213: void *ptr = 0;
! 1214: usbd_status err;
! 1215: int error = 0;
! 1216:
! 1217: if (!(flag & FWRITE))
! 1218: return (EPERM);
! 1219: /* Avoid requests that would damage the bus integrity. */
! 1220: if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
! 1221: ur->ucr_request.bRequest == UR_SET_ADDRESS) ||
! 1222: (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
! 1223: ur->ucr_request.bRequest == UR_SET_CONFIG) ||
! 1224: (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE &&
! 1225: ur->ucr_request.bRequest == UR_SET_INTERFACE))
! 1226: return (EINVAL);
! 1227:
! 1228: if (len < 0 || len > 32767)
! 1229: return (EINVAL);
! 1230: if (len != 0) {
! 1231: iov.iov_base = (caddr_t)ur->ucr_data;
! 1232: iov.iov_len = len;
! 1233: uio.uio_iov = &iov;
! 1234: uio.uio_iovcnt = 1;
! 1235: uio.uio_resid = len;
! 1236: uio.uio_offset = 0;
! 1237: uio.uio_segflg = UIO_USERSPACE;
! 1238: uio.uio_rw =
! 1239: ur->ucr_request.bmRequestType & UT_READ ?
! 1240: UIO_READ : UIO_WRITE;
! 1241: uio.uio_procp = p;
! 1242: ptr = malloc(len, M_TEMP, M_WAITOK);
! 1243: if (uio.uio_rw == UIO_WRITE) {
! 1244: error = uiomove(ptr, len, &uio);
! 1245: if (error)
! 1246: goto ret;
! 1247: }
! 1248: }
! 1249: sce = &sc->sc_endpoints[endpt][IN];
! 1250: err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request,
! 1251: ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout);
! 1252: if (err) {
! 1253: error = EIO;
! 1254: goto ret;
! 1255: }
! 1256: if (len != 0) {
! 1257: if (uio.uio_rw == UIO_READ) {
! 1258: error = uiomove(ptr, len, &uio);
! 1259: if (error)
! 1260: goto ret;
! 1261: }
! 1262: }
! 1263: ret:
! 1264: if (ptr)
! 1265: free(ptr, M_TEMP);
! 1266: return (error);
! 1267: }
! 1268: case USB_GET_DEVICEINFO:
! 1269: usbd_fill_deviceinfo(sc->sc_udev,
! 1270: (struct usb_device_info *)addr, 1);
! 1271: break;
! 1272: default:
! 1273: return (EINVAL);
! 1274: }
! 1275: return (0);
! 1276: }
! 1277:
! 1278: int
! 1279: ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 1280: {
! 1281: int endpt = UGENENDPOINT(dev);
! 1282: struct ugen_softc *sc;
! 1283: int error;
! 1284:
! 1285: sc = ugen_cd.cd_devs[UGENUNIT(dev)];
! 1286:
! 1287: sc->sc_refcnt++;
! 1288: error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
! 1289: if (--sc->sc_refcnt < 0)
! 1290: usb_detach_wakeup(&sc->sc_dev);
! 1291: return (error);
! 1292: }
! 1293:
! 1294: int
! 1295: ugenpoll(dev_t dev, int events, struct proc *p)
! 1296: {
! 1297: struct ugen_softc *sc;
! 1298: struct ugen_endpoint *sce;
! 1299: int revents = 0;
! 1300: int s;
! 1301:
! 1302: sc = ugen_cd.cd_devs[UGENUNIT(dev)];
! 1303:
! 1304: if (sc->sc_dying)
! 1305: return (POLLERR);
! 1306:
! 1307: /* XXX always IN */
! 1308: sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
! 1309: if (sce == NULL)
! 1310: return (POLLERR);
! 1311: #ifdef DIAGNOSTIC
! 1312: if (!sce->edesc) {
! 1313: printf("ugenpoll: no edesc\n");
! 1314: return (POLLERR);
! 1315: }
! 1316: if (!sce->pipeh) {
! 1317: printf("ugenpoll: no pipe\n");
! 1318: return (POLLERR);
! 1319: }
! 1320: #endif
! 1321: s = splusb();
! 1322: switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
! 1323: case UE_INTERRUPT:
! 1324: if (events & (POLLIN | POLLRDNORM)) {
! 1325: if (sce->q.c_cc > 0)
! 1326: revents |= events & (POLLIN | POLLRDNORM);
! 1327: else
! 1328: selrecord(p, &sce->rsel);
! 1329: }
! 1330: break;
! 1331: case UE_ISOCHRONOUS:
! 1332: if (events & (POLLIN | POLLRDNORM)) {
! 1333: if (sce->cur != sce->fill)
! 1334: revents |= events & (POLLIN | POLLRDNORM);
! 1335: else
! 1336: selrecord(p, &sce->rsel);
! 1337: }
! 1338: break;
! 1339: case UE_BULK:
! 1340: /*
! 1341: * We have no easy way of determining if a read will
! 1342: * yield any data or a write will happen.
! 1343: * Pretend they will.
! 1344: */
! 1345: revents |= events &
! 1346: (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
! 1347: break;
! 1348: default:
! 1349: break;
! 1350: }
! 1351: splx(s);
! 1352: return (revents);
! 1353: }
! 1354:
! 1355: void filt_ugenrdetach(struct knote *);
! 1356: int filt_ugenread_intr(struct knote *, long);
! 1357: int filt_ugenread_isoc(struct knote *, long);
! 1358: int ugenkqfilter(dev_t, struct knote *);
! 1359:
! 1360: void
! 1361: filt_ugenrdetach(struct knote *kn)
! 1362: {
! 1363: struct ugen_endpoint *sce = (void *)kn->kn_hook;
! 1364: int s;
! 1365:
! 1366: s = splusb();
! 1367: SLIST_REMOVE(&sce->rsel.si_note, kn, knote, kn_selnext);
! 1368: splx(s);
! 1369: }
! 1370:
! 1371: int
! 1372: filt_ugenread_intr(struct knote *kn, long hint)
! 1373: {
! 1374: struct ugen_endpoint *sce = (void *)kn->kn_hook;
! 1375:
! 1376: kn->kn_data = sce->q.c_cc;
! 1377: return (kn->kn_data > 0);
! 1378: }
! 1379:
! 1380: int
! 1381: filt_ugenread_isoc(struct knote *kn, long hint)
! 1382: {
! 1383: struct ugen_endpoint *sce = (void *)kn->kn_hook;
! 1384:
! 1385: if (sce->cur == sce->fill)
! 1386: return (0);
! 1387:
! 1388: if (sce->cur < sce->fill)
! 1389: kn->kn_data = sce->fill - sce->cur;
! 1390: else
! 1391: kn->kn_data = (sce->limit - sce->cur) +
! 1392: (sce->fill - sce->ibuf);
! 1393:
! 1394: return (1);
! 1395: }
! 1396:
! 1397: struct filterops ugenread_intr_filtops =
! 1398: { 1, NULL, filt_ugenrdetach, filt_ugenread_intr };
! 1399:
! 1400: struct filterops ugenread_isoc_filtops =
! 1401: { 1, NULL, filt_ugenrdetach, filt_ugenread_isoc };
! 1402:
! 1403: struct filterops ugen_seltrue_filtops =
! 1404: { 1, NULL, filt_ugenrdetach, filt_seltrue };
! 1405:
! 1406: int
! 1407: ugenkqfilter(dev_t dev, struct knote *kn)
! 1408: {
! 1409: struct ugen_softc *sc;
! 1410: struct ugen_endpoint *sce;
! 1411: struct klist *klist;
! 1412: int s;
! 1413:
! 1414: sc = ugen_cd.cd_devs[UGENUNIT(dev)];
! 1415:
! 1416: if (sc->sc_dying)
! 1417: return (1);
! 1418:
! 1419: /* XXX always IN */
! 1420: sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
! 1421: if (sce == NULL)
! 1422: return (1);
! 1423:
! 1424: switch (kn->kn_filter) {
! 1425: case EVFILT_READ:
! 1426: klist = &sce->rsel.si_note;
! 1427: switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
! 1428: case UE_INTERRUPT:
! 1429: kn->kn_fop = &ugenread_intr_filtops;
! 1430: break;
! 1431: case UE_ISOCHRONOUS:
! 1432: kn->kn_fop = &ugenread_isoc_filtops;
! 1433: break;
! 1434: case UE_BULK:
! 1435: /*
! 1436: * We have no easy way of determining if a read will
! 1437: * yield any data or a write will happen.
! 1438: * So, emulate "seltrue".
! 1439: */
! 1440: kn->kn_fop = &ugen_seltrue_filtops;
! 1441: break;
! 1442: default:
! 1443: return (1);
! 1444: }
! 1445: break;
! 1446:
! 1447: case EVFILT_WRITE:
! 1448: klist = &sce->rsel.si_note;
! 1449: switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
! 1450: case UE_INTERRUPT:
! 1451: case UE_ISOCHRONOUS:
! 1452: /* XXX poll doesn't support this */
! 1453: return (1);
! 1454:
! 1455: case UE_BULK:
! 1456: /*
! 1457: * We have no easy way of determining if a read will
! 1458: * yield any data or a write will happen.
! 1459: * So, emulate "seltrue".
! 1460: */
! 1461: kn->kn_fop = &ugen_seltrue_filtops;
! 1462: break;
! 1463: default:
! 1464: return (1);
! 1465: }
! 1466: break;
! 1467:
! 1468: default:
! 1469: return (1);
! 1470: }
! 1471:
! 1472: kn->kn_hook = (void *)sce;
! 1473:
! 1474: s = splusb();
! 1475: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
! 1476: splx(s);
! 1477:
! 1478: return (0);
! 1479: }
CVSweb