Annotation of sys/dev/usb/umidi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: umidi.c,v 1.22 2007/06/14 10:11:16 mbalmer Exp $ */
! 2: /* $NetBSD: umidi.c,v 1.16 2002/07/11 21:14:32 augustss Exp $ */
! 3: /*
! 4: * Copyright (c) 2001 The NetBSD Foundation, Inc.
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to The NetBSD Foundation
! 8: * by Takuya SHIOZAKI (tshiozak@netbsd.org).
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the NetBSD
! 21: * Foundation, Inc. and its contributors.
! 22: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 23: * contributors may be used to endorse or promote products derived
! 24: * from this software without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 36: * POSSIBILITY OF SUCH DAMAGE.
! 37: */
! 38:
! 39: #include <sys/param.h>
! 40: #include <sys/systm.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/malloc.h>
! 43: #include <sys/device.h>
! 44: #include <sys/ioctl.h>
! 45: #include <sys/conf.h>
! 46: #include <sys/file.h>
! 47: #include <sys/selinfo.h>
! 48: #include <sys/proc.h>
! 49: #include <sys/vnode.h>
! 50: #include <sys/poll.h>
! 51:
! 52: #include <dev/usb/usb.h>
! 53: #include <dev/usb/usbdi.h>
! 54: #include <dev/usb/usbdi_util.h>
! 55:
! 56: #include <dev/usb/usbdevs.h>
! 57: #include <dev/usb/uaudioreg.h>
! 58: #include <dev/usb/umidireg.h>
! 59: #include <dev/usb/umidivar.h>
! 60: #include <dev/usb/umidi_quirks.h>
! 61:
! 62: #include <dev/midi_if.h>
! 63:
! 64: #ifdef UMIDI_DEBUG
! 65: #define DPRINTF(x) if (umididebug) printf x
! 66: #define DPRINTFN(n,x) if (umididebug >= (n)) printf x
! 67: int umididebug = 0;
! 68: #else
! 69: #define DPRINTF(x)
! 70: #define DPRINTFN(n,x)
! 71: #endif
! 72:
! 73:
! 74: static int umidi_open(void *, int,
! 75: void (*)(void *, int), void (*)(void *), void *);
! 76: static void umidi_close(void *);
! 77: static int umidi_output(void *, int);
! 78: static void umidi_flush(void *);
! 79: static void umidi_getinfo(void *, struct midi_info *);
! 80:
! 81: static usbd_status alloc_pipe(struct umidi_endpoint *);
! 82: static void free_pipe(struct umidi_endpoint *);
! 83:
! 84: static usbd_status alloc_all_endpoints(struct umidi_softc *);
! 85: static void free_all_endpoints(struct umidi_softc *);
! 86:
! 87: static usbd_status alloc_all_jacks(struct umidi_softc *);
! 88: static void free_all_jacks(struct umidi_softc *);
! 89: static usbd_status bind_jacks_to_mididev(struct umidi_softc *,
! 90: struct umidi_jack *,
! 91: struct umidi_jack *,
! 92: struct umidi_mididev *);
! 93: static void unbind_jacks_from_mididev(struct umidi_mididev *);
! 94: static void unbind_all_jacks(struct umidi_softc *);
! 95: static usbd_status assign_all_jacks_automatically(struct umidi_softc *);
! 96: static usbd_status open_out_jack(struct umidi_jack *, void *,
! 97: void (*)(void *));
! 98: static usbd_status open_in_jack(struct umidi_jack *, void *,
! 99: void (*)(void *, int));
! 100: static void close_out_jack(struct umidi_jack *);
! 101: static void close_in_jack(struct umidi_jack *);
! 102:
! 103: static usbd_status attach_mididev(struct umidi_softc *,
! 104: struct umidi_mididev *);
! 105: static usbd_status detach_mididev(struct umidi_mididev *, int);
! 106: static usbd_status deactivate_mididev(struct umidi_mididev *);
! 107: static usbd_status alloc_all_mididevs(struct umidi_softc *, int);
! 108: static void free_all_mididevs(struct umidi_softc *);
! 109: static usbd_status attach_all_mididevs(struct umidi_softc *);
! 110: static usbd_status detach_all_mididevs(struct umidi_softc *, int);
! 111: static usbd_status deactivate_all_mididevs(struct umidi_softc *);
! 112:
! 113: #ifdef UMIDI_DEBUG
! 114: static void dump_sc(struct umidi_softc *);
! 115: static void dump_ep(struct umidi_endpoint *);
! 116: static void dump_jack(struct umidi_jack *);
! 117: #endif
! 118:
! 119: static void init_packet(struct umidi_packet *);
! 120:
! 121: static usbd_status start_input_transfer(struct umidi_endpoint *);
! 122: static usbd_status start_output_transfer(struct umidi_endpoint *);
! 123: static int out_jack_output(struct umidi_jack *, int);
! 124: static void out_jack_flush(struct umidi_jack *);
! 125: static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 126: static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
! 127: static int out_build_packet(int, struct umidi_packet *, uByte, u_char *);
! 128:
! 129:
! 130: struct midi_hw_if umidi_hw_if = {
! 131: umidi_open,
! 132: umidi_close,
! 133: umidi_output,
! 134: umidi_flush, /* flush */
! 135: umidi_getinfo,
! 136: 0, /* ioctl */
! 137: };
! 138:
! 139: int umidi_match(struct device *, void *, void *);
! 140: void umidi_attach(struct device *, struct device *, void *);
! 141: int umidi_detach(struct device *, int);
! 142: int umidi_activate(struct device *, enum devact);
! 143:
! 144: struct cfdriver umidi_cd = {
! 145: NULL, "umidi", DV_DULL
! 146: };
! 147:
! 148: const struct cfattach umidi_ca = {
! 149: sizeof(struct umidi_softc),
! 150: umidi_match,
! 151: umidi_attach,
! 152: umidi_detach,
! 153: umidi_activate,
! 154: };
! 155:
! 156: int
! 157: umidi_match(struct device *parent, void *match, void *aux)
! 158: {
! 159: struct usb_attach_arg *uaa = aux;
! 160: usb_interface_descriptor_t *id;
! 161:
! 162: DPRINTFN(1,("umidi_match\n"));
! 163:
! 164: if (uaa->iface == NULL)
! 165: return UMATCH_NONE;
! 166:
! 167: if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno))
! 168: return UMATCH_IFACECLASS_IFACESUBCLASS;
! 169:
! 170: id = usbd_get_interface_descriptor(uaa->iface);
! 171: if (id!=NULL &&
! 172: id->bInterfaceClass==UICLASS_AUDIO &&
! 173: id->bInterfaceSubClass==UISUBCLASS_MIDISTREAM)
! 174: return UMATCH_IFACECLASS_IFACESUBCLASS;
! 175:
! 176: return UMATCH_NONE;
! 177: }
! 178:
! 179: void
! 180: umidi_attach(struct device *parent, struct device *self, void *aux)
! 181: {
! 182: usbd_status err;
! 183: struct umidi_softc *sc = (struct umidi_softc *)self;
! 184: struct usb_attach_arg *uaa = aux;
! 185: char *devinfop;
! 186: int i;
! 187:
! 188: DPRINTFN(1,("umidi_attach\n"));
! 189:
! 190: devinfop = usbd_devinfo_alloc(uaa->device, 0);
! 191: printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
! 192: usbd_devinfo_free(devinfop);
! 193:
! 194: sc->sc_iface = uaa->iface;
! 195: sc->sc_udev = uaa->device;
! 196:
! 197: sc->sc_quirk =
! 198: umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno);
! 199: printf("%s: ", sc->sc_dev.dv_xname);
! 200: umidi_print_quirk(sc->sc_quirk);
! 201:
! 202:
! 203: err = alloc_all_endpoints(sc);
! 204: if (err!=USBD_NORMAL_COMPLETION) {
! 205: goto error;
! 206: }
! 207: err = alloc_all_jacks(sc);
! 208: if (err!=USBD_NORMAL_COMPLETION) {
! 209: free_all_endpoints(sc);
! 210: goto error;
! 211: }
! 212: printf("%s: out=%d, in=%d\n",
! 213: sc->sc_dev.dv_xname,
! 214: sc->sc_out_num_jacks, sc->sc_in_num_jacks);
! 215:
! 216: err = assign_all_jacks_automatically(sc);
! 217: if (err!=USBD_NORMAL_COMPLETION) {
! 218: unbind_all_jacks(sc);
! 219: free_all_jacks(sc);
! 220: free_all_endpoints(sc);
! 221: goto error;
! 222: }
! 223: err = attach_all_mididevs(sc);
! 224: if (err!=USBD_NORMAL_COMPLETION) {
! 225: free_all_jacks(sc);
! 226: free_all_endpoints(sc);
! 227: }
! 228:
! 229: #ifdef UMIDI_DEBUG
! 230: dump_sc(sc);
! 231: #endif
! 232:
! 233: for (i = 0; i < sc->sc_in_num_endpoints; i++) {
! 234: (void)start_input_transfer(&sc->sc_in_ep[i]);
! 235: }
! 236:
! 237: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH,
! 238: sc->sc_udev, &sc->sc_dev);
! 239:
! 240: return;
! 241: error:
! 242: printf("%s: disabled.\n", sc->sc_dev.dv_xname);
! 243: sc->sc_dying = 1;
! 244: }
! 245:
! 246: int
! 247: umidi_activate(struct device *self, enum devact act)
! 248: {
! 249: struct umidi_softc *sc = (struct umidi_softc *)self;
! 250:
! 251: switch (act) {
! 252: case DVACT_ACTIVATE:
! 253: DPRINTFN(1,("umidi_activate (activate)\n"));
! 254: break;
! 255: case DVACT_DEACTIVATE:
! 256: DPRINTFN(1,("umidi_activate (deactivate)\n"));
! 257: sc->sc_dying = 1;
! 258: deactivate_all_mididevs(sc);
! 259: break;
! 260: }
! 261: return 0;
! 262: }
! 263:
! 264: int
! 265: umidi_detach(struct device *self, int flags)
! 266: {
! 267: struct umidi_softc *sc = (struct umidi_softc *)self;
! 268:
! 269: DPRINTFN(1,("umidi_detach\n"));
! 270:
! 271: sc->sc_dying = 1;
! 272: detach_all_mididevs(sc, flags);
! 273: free_all_mididevs(sc);
! 274: free_all_jacks(sc);
! 275: free_all_endpoints(sc);
! 276:
! 277: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
! 278: &sc->sc_dev);
! 279:
! 280: return 0;
! 281: }
! 282:
! 283:
! 284: /*
! 285: * midi_if stuffs
! 286: */
! 287: int
! 288: umidi_open(void *addr,
! 289: int flags,
! 290: void (*iintr)(void *, int),
! 291: void (*ointr)(void *),
! 292: void *arg)
! 293: {
! 294: struct umidi_mididev *mididev = addr;
! 295: struct umidi_softc *sc = mididev->sc;
! 296:
! 297: DPRINTF(("umidi_open: sc=%p\n", sc));
! 298:
! 299: if (!sc)
! 300: return ENXIO;
! 301: if (mididev->opened)
! 302: return EBUSY;
! 303: if (sc->sc_dying)
! 304: return EIO;
! 305:
! 306: mididev->opened = 1;
! 307: mididev->flags = flags;
! 308: if ((mididev->flags & FWRITE) && mididev->out_jack)
! 309: open_out_jack(mididev->out_jack, arg, ointr);
! 310: if ((mididev->flags & FREAD) && mididev->in_jack) {
! 311: open_in_jack(mididev->in_jack, arg, iintr);
! 312: }
! 313:
! 314: return 0;
! 315: }
! 316:
! 317: void
! 318: umidi_close(void *addr)
! 319: {
! 320: int s;
! 321: struct umidi_mididev *mididev = addr;
! 322:
! 323: s = splusb();
! 324: if ((mididev->flags & FWRITE) && mididev->out_jack)
! 325: close_out_jack(mididev->out_jack);
! 326: if ((mididev->flags & FREAD) && mididev->in_jack)
! 327: close_in_jack(mididev->in_jack);
! 328: mididev->opened = 0;
! 329: splx(s);
! 330: }
! 331:
! 332: int
! 333: umidi_output(void *addr, int d)
! 334: {
! 335: struct umidi_mididev *mididev = addr;
! 336:
! 337: if (!mididev->out_jack || !mididev->opened)
! 338: return EIO;
! 339:
! 340: return out_jack_output(mididev->out_jack, d);
! 341: }
! 342:
! 343: void
! 344: umidi_flush(void *addr)
! 345: {
! 346: struct umidi_mididev *mididev = addr;
! 347:
! 348: if (!mididev->out_jack || !mididev->opened)
! 349: return;
! 350:
! 351: return out_jack_flush(mididev->out_jack);
! 352: }
! 353:
! 354: void
! 355: umidi_getinfo(void *addr, struct midi_info *mi)
! 356: {
! 357: struct umidi_mididev *mididev = addr;
! 358:
! 359: mi->name = "USB MIDI I/F"; /* XXX: model name */
! 360: mi->props = MIDI_PROP_OUT_INTR;
! 361: if (mididev->in_jack)
! 362: mi->props |= MIDI_PROP_CAN_INPUT;
! 363: }
! 364:
! 365:
! 366: /*
! 367: * each endpoint stuffs
! 368: */
! 369:
! 370: /* alloc/free pipe */
! 371: static usbd_status
! 372: alloc_pipe(struct umidi_endpoint *ep)
! 373: {
! 374: struct umidi_softc *sc = ep->sc;
! 375: usbd_status err;
! 376:
! 377: DPRINTF(("%s: alloc_pipe %p\n", sc->sc_dev.dv_xname, ep));
! 378: SIMPLEQ_INIT(&ep->intrq);
! 379: ep->pending = 0;
! 380: ep->busy = 0;
! 381: ep->used = 0;
! 382: ep->xfer = usbd_alloc_xfer(sc->sc_udev);
! 383: if (ep->xfer == NULL) {
! 384: return USBD_NOMEM;
! 385: }
! 386: ep->buffer = usbd_alloc_buffer(ep->xfer, ep->packetsize);
! 387: if (ep->buffer == NULL) {
! 388: usbd_free_xfer(ep->xfer);
! 389: return USBD_NOMEM;
! 390: }
! 391: err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe);
! 392: if (err != USBD_NORMAL_COMPLETION) {
! 393: usbd_free_xfer(ep->xfer);
! 394: return err;
! 395: }
! 396: return USBD_NORMAL_COMPLETION;
! 397: }
! 398:
! 399: static void
! 400: free_pipe(struct umidi_endpoint *ep)
! 401: {
! 402: DPRINTF(("%s: free_pipe %p\n", ep->sc->sc_dev.dv_xname, ep));
! 403: usbd_abort_pipe(ep->pipe);
! 404: usbd_close_pipe(ep->pipe);
! 405: usbd_free_xfer(ep->xfer);
! 406: }
! 407:
! 408:
! 409: /* alloc/free the array of endpoint structures */
! 410:
! 411: static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *);
! 412: static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *);
! 413: static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *);
! 414:
! 415: static usbd_status
! 416: alloc_all_endpoints(struct umidi_softc *sc)
! 417: {
! 418: usbd_status err;
! 419: struct umidi_endpoint *ep;
! 420: int i;
! 421:
! 422: if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)) {
! 423: err = alloc_all_endpoints_fixed_ep(sc);
! 424: } else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)) {
! 425: err = alloc_all_endpoints_yamaha(sc);
! 426: } else {
! 427: err = alloc_all_endpoints_genuine(sc);
! 428: }
! 429: if (err!=USBD_NORMAL_COMPLETION)
! 430: return err;
! 431:
! 432: ep = sc->sc_endpoints;
! 433: for (i=sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i>0; i--) {
! 434: err = alloc_pipe(ep);
! 435: if (err!=USBD_NORMAL_COMPLETION) {
! 436: while(ep != sc->sc_endpoints) {
! 437: ep--;
! 438: free_pipe(ep);
! 439: }
! 440: free(sc->sc_endpoints, M_USBDEV);
! 441: sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
! 442: break;
! 443: }
! 444: ep++;
! 445: }
! 446: return err;
! 447: }
! 448:
! 449: static void
! 450: free_all_endpoints(struct umidi_softc *sc)
! 451: {
! 452: int i;
! 453: for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++)
! 454: free_pipe(&sc->sc_endpoints[i]);
! 455: if (sc->sc_endpoints != NULL)
! 456: free(sc->sc_endpoints, M_USBDEV);
! 457: sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
! 458: }
! 459:
! 460: static usbd_status
! 461: alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
! 462: {
! 463: usbd_status err;
! 464: struct umq_fixed_ep_desc *fp;
! 465: struct umidi_endpoint *ep;
! 466: usb_endpoint_descriptor_t *epd;
! 467: int i;
! 468:
! 469: fp = umidi_get_quirk_data_from_type(sc->sc_quirk,
! 470: UMQ_TYPE_FIXED_EP);
! 471: sc->sc_out_num_jacks = 0;
! 472: sc->sc_in_num_jacks = 0;
! 473: sc->sc_out_num_endpoints = fp->num_out_ep;
! 474: sc->sc_in_num_endpoints = fp->num_in_ep;
! 475: sc->sc_endpoints = malloc(sizeof(*sc->sc_out_ep)*
! 476: (sc->sc_out_num_endpoints+
! 477: sc->sc_in_num_endpoints),
! 478: M_USBDEV, M_WAITOK);
! 479: if (!sc->sc_endpoints) {
! 480: return USBD_NOMEM;
! 481: }
! 482: sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
! 483: sc->sc_in_ep =
! 484: sc->sc_in_num_endpoints ?
! 485: sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
! 486:
! 487: ep = &sc->sc_out_ep[0];
! 488: for (i=0; i<sc->sc_out_num_endpoints; i++) {
! 489: epd = usbd_interface2endpoint_descriptor(
! 490: sc->sc_iface,
! 491: fp->out_ep[i].ep);
! 492: if (!epd) {
! 493: DPRINTF(("%s: cannot get endpoint descriptor(out:%d)\n",
! 494: sc->sc_dev.dv_xname, fp->out_ep[i].ep));
! 495: err = USBD_INVAL;
! 496: goto error;
! 497: }
! 498: if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK ||
! 499: UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_OUT) {
! 500: printf("%s: illegal endpoint(out:%d)\n",
! 501: sc->sc_dev.dv_xname, fp->out_ep[i].ep);
! 502: err = USBD_INVAL;
! 503: goto error;
! 504: }
! 505: ep->sc = sc;
! 506: ep->packetsize = UGETW(epd->wMaxPacketSize);
! 507: ep->addr = epd->bEndpointAddress;
! 508: ep->num_jacks = fp->out_ep[i].num_jacks;
! 509: sc->sc_out_num_jacks += fp->out_ep[i].num_jacks;
! 510: ep->num_open = 0;
! 511: memset(ep->jacks, 0, sizeof(ep->jacks));
! 512: ep++;
! 513: }
! 514: ep = &sc->sc_in_ep[0];
! 515: for (i=0; i<sc->sc_in_num_endpoints; i++) {
! 516: epd = usbd_interface2endpoint_descriptor(
! 517: sc->sc_iface,
! 518: fp->in_ep[i].ep);
! 519: if (!epd) {
! 520: DPRINTF(("%s: cannot get endpoint descriptor(in:%d)\n",
! 521: sc->sc_dev.dv_xname, fp->in_ep[i].ep));
! 522: err = USBD_INVAL;
! 523: goto error;
! 524: }
! 525: if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK ||
! 526: UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_IN) {
! 527: printf("%s: illegal endpoint(in:%d)\n",
! 528: sc->sc_dev.dv_xname, fp->in_ep[i].ep);
! 529: err = USBD_INVAL;
! 530: goto error;
! 531: }
! 532: ep->sc = sc;
! 533: ep->addr = epd->bEndpointAddress;
! 534: ep->packetsize = UGETW(epd->wMaxPacketSize);
! 535: ep->num_jacks = fp->in_ep[i].num_jacks;
! 536: sc->sc_in_num_jacks += fp->in_ep[i].num_jacks;
! 537: ep->num_open = 0;
! 538: memset(ep->jacks, 0, sizeof(ep->jacks));
! 539: ep++;
! 540: }
! 541:
! 542: return USBD_NORMAL_COMPLETION;
! 543: error:
! 544: free(sc->sc_endpoints, M_USBDEV);
! 545: sc->sc_endpoints = NULL;
! 546: return err;
! 547: }
! 548:
! 549: static usbd_status
! 550: alloc_all_endpoints_yamaha(struct umidi_softc *sc)
! 551: {
! 552: /* This driver currently supports max 1in/1out bulk endpoints */
! 553: usb_descriptor_t *desc;
! 554: usb_endpoint_descriptor_t *epd;
! 555: int out_addr, in_addr, in_packetsize, i;
! 556: int dir;
! 557: size_t remain, descsize;
! 558:
! 559: sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
! 560: out_addr = in_addr = 0;
! 561:
! 562: /* detect endpoints */
! 563: desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
! 564: for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) {
! 565: epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
! 566: if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) {
! 567: dir = UE_GET_DIR(epd->bEndpointAddress);
! 568: if (dir==UE_DIR_OUT && !out_addr)
! 569: out_addr = epd->bEndpointAddress;
! 570: else if (dir==UE_DIR_IN && !in_addr) {
! 571: in_addr = epd->bEndpointAddress;
! 572: in_packetsize = UGETW(epd->wMaxPacketSize);
! 573: }
! 574: }
! 575: }
! 576: desc = NEXT_D(desc);
! 577:
! 578: /* count jacks */
! 579: if (!(desc->bDescriptorType==UDESC_CS_INTERFACE &&
! 580: desc->bDescriptorSubtype==UMIDI_MS_HEADER))
! 581: return USBD_INVAL;
! 582: remain = (size_t)UGETW(TO_CSIFD(desc)->wTotalLength) -
! 583: (size_t)desc->bLength;
! 584: desc = NEXT_D(desc);
! 585:
! 586: while (remain>=sizeof(usb_descriptor_t)) {
! 587: descsize = desc->bLength;
! 588: if (descsize>remain || descsize==0)
! 589: break;
! 590: if (desc->bDescriptorType==UDESC_CS_INTERFACE &&
! 591: remain>=UMIDI_JACK_DESCRIPTOR_SIZE) {
! 592: if (desc->bDescriptorSubtype==UMIDI_OUT_JACK)
! 593: sc->sc_out_num_jacks++;
! 594: else if (desc->bDescriptorSubtype==UMIDI_IN_JACK)
! 595: sc->sc_in_num_jacks++;
! 596: }
! 597: desc = NEXT_D(desc);
! 598: remain-=descsize;
! 599: }
! 600:
! 601: /* validate some parameters */
! 602: if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS)
! 603: sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS;
! 604: if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS)
! 605: sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS;
! 606: if (sc->sc_out_num_jacks && out_addr) {
! 607: sc->sc_out_num_endpoints = 1;
! 608: } else {
! 609: sc->sc_out_num_endpoints = 0;
! 610: sc->sc_out_num_jacks = 0;
! 611: }
! 612: if (sc->sc_in_num_jacks && in_addr) {
! 613: sc->sc_in_num_endpoints = 1;
! 614: } else {
! 615: sc->sc_in_num_endpoints = 0;
! 616: sc->sc_in_num_jacks = 0;
! 617: }
! 618: sc->sc_endpoints = malloc(sizeof(struct umidi_endpoint)*
! 619: (sc->sc_out_num_endpoints+
! 620: sc->sc_in_num_endpoints),
! 621: M_USBDEV, M_WAITOK);
! 622: if (!sc->sc_endpoints)
! 623: return USBD_NOMEM;
! 624: if (sc->sc_out_num_endpoints) {
! 625: sc->sc_out_ep = sc->sc_endpoints;
! 626: sc->sc_out_ep->sc = sc;
! 627: sc->sc_out_ep->addr = out_addr;
! 628: sc->sc_out_ep->packetsize = UGETW(epd->wMaxPacketSize);
! 629: sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks;
! 630: sc->sc_out_ep->num_open = 0;
! 631: memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks));
! 632: } else
! 633: sc->sc_out_ep = NULL;
! 634:
! 635: if (sc->sc_in_num_endpoints) {
! 636: sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints;
! 637: sc->sc_in_ep->sc = sc;
! 638: sc->sc_in_ep->addr = in_addr;
! 639: sc->sc_in_ep->packetsize = in_packetsize;
! 640: sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks;
! 641: sc->sc_in_ep->num_open = 0;
! 642: memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks));
! 643: } else
! 644: sc->sc_in_ep = NULL;
! 645:
! 646: return USBD_NORMAL_COMPLETION;
! 647: }
! 648:
! 649: static usbd_status
! 650: alloc_all_endpoints_genuine(struct umidi_softc *sc)
! 651: {
! 652: usb_interface_descriptor_t *interface_desc;
! 653: usb_config_descriptor_t *config_desc;
! 654: usb_descriptor_t *desc;
! 655: int num_ep;
! 656: size_t remain, descsize;
! 657: struct umidi_endpoint *p, *q, *lowest, *endep, tmpep;
! 658: int epaddr, eppacketsize;
! 659:
! 660: interface_desc = usbd_get_interface_descriptor(sc->sc_iface);
! 661: num_ep = interface_desc->bNumEndpoints;
! 662: sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint) * num_ep,
! 663: M_USBDEV, M_WAITOK);
! 664: if (!p)
! 665: return USBD_NOMEM;
! 666:
! 667: sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
! 668: sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0;
! 669: epaddr = -1;
! 670:
! 671: /* get the list of endpoints for midi stream */
! 672: config_desc = usbd_get_config_descriptor(sc->sc_udev);
! 673: desc = (usb_descriptor_t *) config_desc;
! 674: remain = (size_t)UGETW(config_desc->wTotalLength);
! 675: while (remain>=sizeof(usb_descriptor_t)) {
! 676: descsize = desc->bLength;
! 677: if (descsize>remain || descsize==0)
! 678: break;
! 679: if (desc->bDescriptorType==UDESC_ENDPOINT &&
! 680: remain>=USB_ENDPOINT_DESCRIPTOR_SIZE &&
! 681: UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) {
! 682: epaddr = TO_EPD(desc)->bEndpointAddress;
! 683: eppacketsize = UGETW(TO_EPD(desc)->wMaxPacketSize);
! 684: } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT &&
! 685: remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE &&
! 686: epaddr!=-1) {
! 687: if (num_ep>0) {
! 688: num_ep--;
! 689: p->sc = sc;
! 690: p->addr = epaddr;
! 691: p->packetsize = eppacketsize;
! 692: p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack;
! 693: if (UE_GET_DIR(epaddr)==UE_DIR_OUT) {
! 694: sc->sc_out_num_endpoints++;
! 695: sc->sc_out_num_jacks += p->num_jacks;
! 696: } else {
! 697: sc->sc_in_num_endpoints++;
! 698: sc->sc_in_num_jacks += p->num_jacks;
! 699: }
! 700: p++;
! 701: }
! 702: } else
! 703: epaddr = -1;
! 704: desc = NEXT_D(desc);
! 705: remain-=descsize;
! 706: }
! 707:
! 708: /* sort endpoints */
! 709: num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints;
! 710: p = sc->sc_endpoints;
! 711: endep = p + num_ep;
! 712: while (p<endep) {
! 713: lowest = p;
! 714: for (q=p+1; q<endep; q++) {
! 715: if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN &&
! 716: UE_GET_DIR(q->addr)==UE_DIR_OUT) ||
! 717: ((UE_GET_DIR(lowest->addr)==
! 718: UE_GET_DIR(q->addr)) &&
! 719: (UE_GET_ADDR(lowest->addr)>
! 720: UE_GET_ADDR(q->addr))))
! 721: lowest = q;
! 722: }
! 723: if (lowest != p) {
! 724: memcpy((void *)&tmpep, (void *)p, sizeof(tmpep));
! 725: memcpy((void *)p, (void *)lowest, sizeof(tmpep));
! 726: memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep));
! 727: }
! 728: p->num_open = 0;
! 729: p++;
! 730: }
! 731:
! 732: sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
! 733: sc->sc_in_ep =
! 734: sc->sc_in_num_endpoints ?
! 735: sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
! 736:
! 737: return USBD_NORMAL_COMPLETION;
! 738: }
! 739:
! 740:
! 741: /*
! 742: * jack stuffs
! 743: */
! 744:
! 745: static usbd_status
! 746: alloc_all_jacks(struct umidi_softc *sc)
! 747: {
! 748: int i, j;
! 749: struct umidi_endpoint *ep;
! 750: struct umidi_jack *jack, **rjack;
! 751:
! 752: /* allocate/initialize structures */
! 753: sc->sc_jacks =
! 754: malloc(sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+
! 755: sc->sc_out_num_jacks),
! 756: M_USBDEV, M_WAITOK);
! 757: if (!sc->sc_jacks)
! 758: return USBD_NOMEM;
! 759: sc->sc_out_jacks =
! 760: sc->sc_out_num_jacks ? sc->sc_jacks : NULL;
! 761: sc->sc_in_jacks =
! 762: sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL;
! 763:
! 764: jack = &sc->sc_out_jacks[0];
! 765: for (i=0; i<sc->sc_out_num_jacks; i++) {
! 766: jack->opened = 0;
! 767: jack->binded = 0;
! 768: jack->arg = NULL;
! 769: jack->u.out.intr = NULL;
! 770: #ifdef DIAGNOSTIC
! 771: jack->wait = 0;
! 772: #endif
! 773: jack->cable_number = i;
! 774: jack++;
! 775: }
! 776: jack = &sc->sc_in_jacks[0];
! 777: for (i=0; i<sc->sc_in_num_jacks; i++) {
! 778: jack->opened = 0;
! 779: jack->binded = 0;
! 780: jack->arg = NULL;
! 781: jack->u.in.intr = NULL;
! 782: jack->cable_number = i;
! 783: jack++;
! 784: }
! 785:
! 786: /* assign each jacks to each endpoints */
! 787: jack = &sc->sc_out_jacks[0];
! 788: ep = &sc->sc_out_ep[0];
! 789: for (i=0; i<sc->sc_out_num_endpoints; i++) {
! 790: rjack = &ep->jacks[0];
! 791: for (j=0; j<ep->num_jacks; j++) {
! 792: *rjack = jack;
! 793: jack->endpoint = ep;
! 794: jack++;
! 795: rjack++;
! 796: }
! 797: ep++;
! 798: }
! 799: jack = &sc->sc_in_jacks[0];
! 800: ep = &sc->sc_in_ep[0];
! 801: for (i=0; i<sc->sc_in_num_endpoints; i++) {
! 802: rjack = &ep->jacks[0];
! 803: for (j=0; j<ep->num_jacks; j++) {
! 804: *rjack = jack;
! 805: jack->endpoint = ep;
! 806: jack++;
! 807: rjack++;
! 808: }
! 809: ep++;
! 810: }
! 811:
! 812: return USBD_NORMAL_COMPLETION;
! 813: }
! 814:
! 815: static void
! 816: free_all_jacks(struct umidi_softc *sc)
! 817: {
! 818: int s;
! 819:
! 820: s = splaudio();
! 821: if (sc->sc_out_jacks) {
! 822: free(sc->sc_jacks, M_USBDEV);
! 823: sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL;
! 824: }
! 825: splx(s);
! 826: }
! 827:
! 828: static usbd_status
! 829: bind_jacks_to_mididev(struct umidi_softc *sc,
! 830: struct umidi_jack *out_jack,
! 831: struct umidi_jack *in_jack,
! 832: struct umidi_mididev *mididev)
! 833: {
! 834: if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded))
! 835: return USBD_IN_USE;
! 836: if (mididev->out_jack || mididev->in_jack)
! 837: return USBD_IN_USE;
! 838:
! 839: if (out_jack)
! 840: out_jack->binded = 1;
! 841: if (in_jack)
! 842: in_jack->binded = 1;
! 843: mididev->in_jack = in_jack;
! 844: mididev->out_jack = out_jack;
! 845:
! 846: return USBD_NORMAL_COMPLETION;
! 847: }
! 848:
! 849: static void
! 850: unbind_jacks_from_mididev(struct umidi_mididev *mididev)
! 851: {
! 852: if ((mididev->flags & FWRITE) && mididev->out_jack)
! 853: close_out_jack(mididev->out_jack);
! 854: if ((mididev->flags & FREAD) && mididev->in_jack)
! 855: close_in_jack(mididev->in_jack);
! 856:
! 857: if (mididev->out_jack)
! 858: mididev->out_jack->binded = 0;
! 859: if (mididev->in_jack)
! 860: mididev->in_jack->binded = 0;
! 861: mididev->out_jack = mididev->in_jack = NULL;
! 862: }
! 863:
! 864: static void
! 865: unbind_all_jacks(struct umidi_softc *sc)
! 866: {
! 867: int i;
! 868:
! 869: if (sc->sc_mididevs)
! 870: for (i=0; i<sc->sc_num_mididevs; i++) {
! 871: unbind_jacks_from_mididev(&sc->sc_mididevs[i]);
! 872: }
! 873: }
! 874:
! 875: static usbd_status
! 876: assign_all_jacks_automatically(struct umidi_softc *sc)
! 877: {
! 878: usbd_status err;
! 879: int i;
! 880: struct umidi_jack *out, *in;
! 881:
! 882: err =
! 883: alloc_all_mididevs(sc,
! 884: max(sc->sc_out_num_jacks, sc->sc_in_num_jacks));
! 885: if (err!=USBD_NORMAL_COMPLETION)
! 886: return err;
! 887:
! 888: for (i=0; i<sc->sc_num_mididevs; i++) {
! 889: out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i]:NULL;
! 890: in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i]:NULL;
! 891: err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]);
! 892: if (err!=USBD_NORMAL_COMPLETION) {
! 893: free_all_mididevs(sc);
! 894: return err;
! 895: }
! 896: }
! 897:
! 898: return USBD_NORMAL_COMPLETION;
! 899: }
! 900:
! 901: static usbd_status
! 902: open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *))
! 903: {
! 904: if (jack->opened)
! 905: return USBD_IN_USE;
! 906:
! 907: jack->arg = arg;
! 908: jack->u.out.intr = intr;
! 909: init_packet(&jack->packet);
! 910: jack->opened = 1;
! 911: jack->endpoint->num_open++;
! 912:
! 913: return USBD_NORMAL_COMPLETION;
! 914: }
! 915:
! 916: static usbd_status
! 917: open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int))
! 918: {
! 919: if (jack->opened)
! 920: return USBD_IN_USE;
! 921:
! 922: jack->arg = arg;
! 923: jack->u.in.intr = intr;
! 924: jack->opened = 1;
! 925: jack->endpoint->num_open++;
! 926:
! 927: return USBD_NORMAL_COMPLETION;
! 928: }
! 929:
! 930: static void
! 931: close_out_jack(struct umidi_jack *jack)
! 932: {
! 933: if (jack->opened) {
! 934: jack->opened = 0;
! 935: jack->endpoint->num_open--;
! 936: }
! 937: }
! 938:
! 939: static void
! 940: close_in_jack(struct umidi_jack *jack)
! 941: {
! 942: if (jack->opened) {
! 943: jack->opened = 0;
! 944: jack->endpoint->num_open--;
! 945: }
! 946: }
! 947:
! 948: static usbd_status
! 949: attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev)
! 950: {
! 951: if (mididev->sc)
! 952: return USBD_IN_USE;
! 953:
! 954: mididev->sc = sc;
! 955:
! 956: mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, &sc->sc_dev);
! 957:
! 958: return USBD_NORMAL_COMPLETION;
! 959: }
! 960:
! 961: static usbd_status
! 962: detach_mididev(struct umidi_mididev *mididev, int flags)
! 963: {
! 964: if (!mididev->sc)
! 965: return USBD_NO_ADDR;
! 966:
! 967: if (mididev->opened) {
! 968: umidi_close(mididev);
! 969: }
! 970: unbind_jacks_from_mididev(mididev);
! 971:
! 972: if (mididev->mdev)
! 973: config_detach(mididev->mdev, flags);
! 974:
! 975: mididev->sc = NULL;
! 976:
! 977: return USBD_NORMAL_COMPLETION;
! 978: }
! 979:
! 980: static usbd_status
! 981: deactivate_mididev(struct umidi_mididev *mididev)
! 982: {
! 983: if (mididev->out_jack)
! 984: mididev->out_jack->binded = 0;
! 985: if (mididev->in_jack)
! 986: mididev->in_jack->binded = 0;
! 987: config_deactivate(mididev->mdev);
! 988:
! 989: return USBD_NORMAL_COMPLETION;
! 990: }
! 991:
! 992: static usbd_status
! 993: alloc_all_mididevs(struct umidi_softc *sc, int nmidi)
! 994: {
! 995: sc->sc_num_mididevs = nmidi;
! 996: sc->sc_mididevs = malloc(sizeof(*sc->sc_mididevs)*nmidi,
! 997: M_USBDEV, M_WAITOK);
! 998: if (!sc->sc_mididevs)
! 999: return USBD_NOMEM;
! 1000: memset(sc->sc_mididevs, 0, sizeof(*sc->sc_mididevs)*nmidi);
! 1001:
! 1002: return USBD_NORMAL_COMPLETION;
! 1003: }
! 1004:
! 1005: static void
! 1006: free_all_mididevs(struct umidi_softc *sc)
! 1007: {
! 1008: sc->sc_num_mididevs = 0;
! 1009: if (sc->sc_mididevs)
! 1010: free(sc->sc_mididevs, M_USBDEV);
! 1011: }
! 1012:
! 1013: static usbd_status
! 1014: attach_all_mididevs(struct umidi_softc *sc)
! 1015: {
! 1016: usbd_status err;
! 1017: int i;
! 1018:
! 1019: if (sc->sc_mididevs)
! 1020: for (i=0; i<sc->sc_num_mididevs; i++) {
! 1021: err = attach_mididev(sc, &sc->sc_mididevs[i]);
! 1022: if (err!=USBD_NORMAL_COMPLETION)
! 1023: return err;
! 1024: }
! 1025:
! 1026: return USBD_NORMAL_COMPLETION;
! 1027: }
! 1028:
! 1029: static usbd_status
! 1030: detach_all_mididevs(struct umidi_softc *sc, int flags)
! 1031: {
! 1032: usbd_status err;
! 1033: int i;
! 1034:
! 1035: if (sc->sc_mididevs)
! 1036: for (i=0; i<sc->sc_num_mididevs; i++) {
! 1037: err = detach_mididev(&sc->sc_mididevs[i], flags);
! 1038: if (err!=USBD_NORMAL_COMPLETION)
! 1039: return err;
! 1040: }
! 1041:
! 1042: return USBD_NORMAL_COMPLETION;
! 1043: }
! 1044:
! 1045: static usbd_status
! 1046: deactivate_all_mididevs(struct umidi_softc *sc)
! 1047: {
! 1048: usbd_status err;
! 1049: int i;
! 1050:
! 1051: if (sc->sc_mididevs)
! 1052: for (i=0; i<sc->sc_num_mididevs; i++) {
! 1053: err = deactivate_mididev(&sc->sc_mididevs[i]);
! 1054: if (err!=USBD_NORMAL_COMPLETION)
! 1055: return err;
! 1056: }
! 1057:
! 1058: return USBD_NORMAL_COMPLETION;
! 1059: }
! 1060:
! 1061: #ifdef UMIDI_DEBUG
! 1062: static void
! 1063: dump_sc(struct umidi_softc *sc)
! 1064: {
! 1065: int i;
! 1066:
! 1067: DPRINTFN(10, ("%s: dump_sc\n", sc->sc_dev.dv_xname));
! 1068: for (i=0; i<sc->sc_out_num_endpoints; i++) {
! 1069: DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i]));
! 1070: dump_ep(&sc->sc_out_ep[i]);
! 1071: }
! 1072: for (i=0; i<sc->sc_in_num_endpoints; i++) {
! 1073: DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i]));
! 1074: dump_ep(&sc->sc_in_ep[i]);
! 1075: }
! 1076: }
! 1077:
! 1078: static void
! 1079: dump_ep(struct umidi_endpoint *ep)
! 1080: {
! 1081: int i;
! 1082: for (i=0; i<ep->num_jacks; i++) {
! 1083: DPRINTFN(10, ("\t\tjack(%p):\n", ep->jacks[i]));
! 1084: dump_jack(ep->jacks[i]);
! 1085: }
! 1086: }
! 1087: static void
! 1088: dump_jack(struct umidi_jack *jack)
! 1089: {
! 1090: DPRINTFN(10, ("\t\t\tep=%p\n",
! 1091: jack->endpoint));
! 1092: }
! 1093:
! 1094: #endif /* UMIDI_DEBUG */
! 1095:
! 1096:
! 1097:
! 1098: /*
! 1099: * MUX MIDI PACKET
! 1100: */
! 1101:
! 1102: static const int packet_length[16] = {
! 1103: /*0*/ -1,
! 1104: /*1*/ -1,
! 1105: /*2*/ 2,
! 1106: /*3*/ 3,
! 1107: /*4*/ 3,
! 1108: /*5*/ 1,
! 1109: /*6*/ 2,
! 1110: /*7*/ 3,
! 1111: /*8*/ 3,
! 1112: /*9*/ 3,
! 1113: /*A*/ 3,
! 1114: /*B*/ 3,
! 1115: /*C*/ 2,
! 1116: /*D*/ 2,
! 1117: /*E*/ 3,
! 1118: /*F*/ 1,
! 1119: };
! 1120:
! 1121: #define GET_CN(p) (((unsigned char)(p)>>4)&0x0F)
! 1122: #define GET_CIN(p) ((unsigned char)(p)&0x0F)
! 1123: #define MIX_CN_CIN(cn, cin) \
! 1124: ((unsigned char)((((unsigned char)(cn)&0x0F)<<4)| \
! 1125: ((unsigned char)(cin)&0x0F)))
! 1126:
! 1127: static void
! 1128: init_packet(struct umidi_packet *packet)
! 1129: {
! 1130: packet->status = 0;
! 1131: packet->index = 0;
! 1132: }
! 1133:
! 1134: static usbd_status
! 1135: start_input_transfer(struct umidi_endpoint *ep)
! 1136: {
! 1137: usbd_status err;
! 1138: usbd_setup_xfer(ep->xfer, ep->pipe,
! 1139: (usbd_private_handle)ep,
! 1140: ep->buffer, ep->packetsize,
! 1141: USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, in_intr);
! 1142: err = usbd_transfer(ep->xfer);
! 1143: if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) {
! 1144: DPRINTF(("%s: start_input_transfer: usbd_transfer() failed err=%s\n",
! 1145: ep->sc->sc_dev.dv_xname, usbd_errstr(err)));
! 1146: return err;
! 1147: }
! 1148: return USBD_NORMAL_COMPLETION;
! 1149: }
! 1150:
! 1151: static usbd_status
! 1152: start_output_transfer(struct umidi_endpoint *ep)
! 1153: {
! 1154: usbd_status err;
! 1155: usbd_setup_xfer(ep->xfer, ep->pipe,
! 1156: (usbd_private_handle)ep,
! 1157: ep->buffer, ep->used,
! 1158: USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr);
! 1159: err = usbd_transfer(ep->xfer);
! 1160: if (err != USBD_NORMAL_COMPLETION && err != USBD_IN_PROGRESS) {
! 1161: DPRINTF(("%s: start_output_transfer: usbd_transfer() failed err=%s\n",
! 1162: ep->sc->sc_dev.dv_xname, usbd_errstr(err)));
! 1163: return err;
! 1164: }
! 1165: ep->used = ep->packetsize;
! 1166: return USBD_NORMAL_COMPLETION;
! 1167: }
! 1168:
! 1169:
! 1170: #ifdef UMIDI_DEBUG
! 1171: #define DPR_PACKET(dir, sc, p) \
! 1172: DPRINTFN(500, \
! 1173: ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \
! 1174: sc->sc_dev.dv_xname, \
! 1175: (unsigned char)(p)->buffer[0], \
! 1176: (unsigned char)(p)->buffer[1], \
! 1177: (unsigned char)(p)->buffer[2], \
! 1178: (unsigned char)(p)->buffer[3]));
! 1179: #else
! 1180: #define DPR_PACKET(dir, sc, p)
! 1181: #endif
! 1182:
! 1183: static int
! 1184: out_jack_output(struct umidi_jack *j, int d)
! 1185: {
! 1186: struct umidi_endpoint *ep = j->endpoint;
! 1187: struct umidi_softc *sc = ep->sc;
! 1188: int s;
! 1189:
! 1190: if (sc->sc_dying)
! 1191: return EIO;
! 1192: if (!j->opened)
! 1193: return ENODEV;
! 1194:
! 1195: s = splusb();
! 1196: if (ep->used == ep->packetsize) {
! 1197: #ifdef DIAGNOSTIC
! 1198: if (j->wait == 0) {
! 1199: j->wait = 1;
! 1200: #endif
! 1201: SIMPLEQ_INSERT_TAIL(&ep->intrq, j, intrq_entry);
! 1202: ep->pending++;
! 1203: #ifdef DIAGNOSTIC
! 1204: } else {
! 1205: printf("umidi: (again) %d: already on intrq\n",
! 1206: j->cable_number);
! 1207: }
! 1208: #endif
! 1209: splx(s);
! 1210: return EAGAIN;
! 1211: }
! 1212:
! 1213: if (!out_build_packet(j->cable_number, &j->packet, d,
! 1214: ep->buffer + ep->used)) {
! 1215: splx(s);
! 1216: return EINPROGRESS;
! 1217: }
! 1218: ep->used += UMIDI_PACKET_SIZE;
! 1219: if (ep->used < ep->packetsize) {
! 1220: splx(s);
! 1221: return EINPROGRESS;
! 1222: }
! 1223: #ifdef DIAGNOSTIC
! 1224: if (j->wait == 0) {
! 1225: j->wait = 1;
! 1226: #endif
! 1227: SIMPLEQ_INSERT_TAIL(&ep->intrq, j, intrq_entry);
! 1228: ep->pending++;
! 1229: #ifdef DIAGNOSTIC
! 1230: } else {
! 1231: printf("umidi: (ok) %d: already on intrq\n",
! 1232: j->cable_number);
! 1233: }
! 1234: #endif
! 1235: if (!ep->busy) {
! 1236: ep->busy = 1;
! 1237: start_output_transfer(ep);
! 1238: }
! 1239: splx(s);
! 1240: return 0;
! 1241: }
! 1242:
! 1243: static void
! 1244: out_jack_flush(struct umidi_jack *j)
! 1245: {
! 1246: struct umidi_endpoint *ep = j->endpoint;
! 1247: int s;
! 1248:
! 1249: if (ep->sc->sc_dying || !j->opened)
! 1250: return;
! 1251:
! 1252: s = splusb();
! 1253: if (ep->used != 0 && !ep->busy) {
! 1254: ep->busy = 1;
! 1255: start_output_transfer(ep);
! 1256: }
! 1257: splx(s);
! 1258: }
! 1259:
! 1260:
! 1261: static void
! 1262: in_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1263: {
! 1264: int cn, evlen, remain, i;
! 1265: unsigned char *buf;
! 1266: struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
! 1267: struct umidi_jack *jack;
! 1268:
! 1269: if (ep->sc->sc_dying)
! 1270: return;
! 1271:
! 1272: usbd_get_xfer_status(xfer, NULL, NULL, &remain, NULL);
! 1273: if (status != USBD_NORMAL_COMPLETION) {
! 1274: DPRINTF(("in_intr: abnormal status: %s\n", usbd_errstr(status)));
! 1275: return;
! 1276: }
! 1277: buf = ep->buffer;
! 1278: while (remain >= UMIDI_PACKET_SIZE) {
! 1279: cn = GET_CN(buf[0]);
! 1280: if (cn < ep->num_jacks && (jack = ep->jacks[cn]) &&
! 1281: jack->binded && jack->opened && jack->u.in.intr) {
! 1282: evlen = packet_length[GET_CIN(buf[0])];
! 1283: for (i=0; i<evlen; i++)
! 1284: (*jack->u.in.intr)(jack->arg, buf[i+1]);
! 1285: }
! 1286: buf += UMIDI_PACKET_SIZE;
! 1287: remain -= UMIDI_PACKET_SIZE;
! 1288: }
! 1289: (void)start_input_transfer(ep);
! 1290: }
! 1291:
! 1292: static void
! 1293: out_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
! 1294: {
! 1295: struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
! 1296: struct umidi_softc *sc = ep->sc;
! 1297: struct umidi_jack *j;
! 1298: unsigned pending;
! 1299:
! 1300: if (sc->sc_dying)
! 1301: return;
! 1302:
! 1303: ep->used = 0;
! 1304: for (pending = ep->pending; pending > 0; pending--) {
! 1305: j = SIMPLEQ_FIRST(&ep->intrq);
! 1306: #ifdef DIAGNOSTIC
! 1307: if (j == NULL) {
! 1308: printf("umidi: missing intr entry\n");
! 1309: break;
! 1310: }
! 1311: #endif
! 1312: SIMPLEQ_REMOVE_HEAD(&ep->intrq, intrq_entry);
! 1313: ep->pending--;
! 1314: #ifdef DIAGNOSTIC
! 1315: j->wait = 0;
! 1316: #endif
! 1317: if (j->opened && j->u.out.intr)
! 1318: (*j->u.out.intr)(j->arg);
! 1319: }
! 1320:
! 1321: if (ep->used == 0) {
! 1322: ep->busy = 0;
! 1323: } else {
! 1324: start_output_transfer(ep);
! 1325: }
! 1326: }
! 1327:
! 1328: #define UMIDI_VOICELEN(status) (umidi_evlen[((status) >> 4) & 7])
! 1329: unsigned umidi_evlen[] = { 4, 4, 4, 4, 3, 3, 4 };
! 1330:
! 1331: #define EV_SYSEX 0xf0
! 1332: #define EV_MTC 0xf1
! 1333: #define EV_SPP 0xf2
! 1334: #define EV_SONGSEL 0xf3
! 1335: #define EV_TUNE_REQ 0xf6
! 1336: #define EV_SYSEX_STOP 0xf7
! 1337:
! 1338: static int
! 1339: out_build_packet(int cable_number, struct umidi_packet *packet,
! 1340: uByte data, u_char *obuf)
! 1341: {
! 1342: if (data >= 0xf8) { /* is it a realtime message ? */
! 1343: obuf[0] = data >> 4 | cable_number << 4;
! 1344: obuf[1] = data;
! 1345: obuf[2] = 0;
! 1346: obuf[3] = 0;
! 1347: return 1;
! 1348: }
! 1349: if (data >= 0xf0) { /* is it a common message ? */
! 1350: switch(data) {
! 1351: case EV_SYSEX:
! 1352: packet->buf[1] = packet->status = data;
! 1353: packet->index = 2;
! 1354: break;
! 1355: case EV_SYSEX_STOP:
! 1356: if (packet->status != EV_SYSEX) break;
! 1357: if (packet->index == 0)
! 1358: packet->index = 1;
! 1359: packet->status = data;
! 1360: packet->buf[packet->index++] = data;
! 1361: packet->buf[0] = (0x4 - 1 + packet->index) | cable_number << 4;
! 1362: goto packetready;
! 1363: case EV_TUNE_REQ:
! 1364: packet->status = data;
! 1365: packet->buf[0] = 0x5 | cable_number << 4;
! 1366: packet->index = 1;
! 1367: goto packetready;
! 1368: default:
! 1369: packet->status = data;
! 1370: break;
! 1371: }
! 1372: return 0;
! 1373: }
! 1374: if (data >= 0x80) { /* is it a voice message ? */
! 1375: packet->status = data;
! 1376: packet->index = 0;
! 1377: return 0;
! 1378: }
! 1379:
! 1380: /* else it is a data byte */
! 1381: if (packet->status >= 0xf0) {
! 1382: switch(packet->status) {
! 1383: case EV_SYSEX: /* sysex starts or continues */
! 1384: if (packet->index == 0)
! 1385: packet->index = 1;
! 1386:
! 1387: packet->buf[packet->index++] = data;
! 1388: if (packet->index >= UMIDI_PACKET_SIZE) {
! 1389: packet->buf[0] = 0x4 | cable_number << 4;
! 1390: goto packetready;
! 1391: }
! 1392: break;
! 1393: case EV_MTC: /* messages with 1 data byte */
! 1394: case EV_SONGSEL:
! 1395: packet->buf[0] = 0x2 | cable_number << 4;
! 1396: packet->buf[1] = packet->status;
! 1397: packet->buf[2] = data;
! 1398: packet->index = 3;
! 1399: goto packetready;
! 1400: case EV_SPP: /* messages with 2 data bytes */
! 1401: if (packet->index == 0) {
! 1402: packet->buf[0] = 0x3 | cable_number << 4;
! 1403: packet->index = 1;
! 1404: }
! 1405: packet->buf[packet->index++] = data;
! 1406: if (packet->index >= UMIDI_PACKET_SIZE) {
! 1407: packet->buf[1] = packet->status;
! 1408: goto packetready;
! 1409: }
! 1410: break;
! 1411: default: /* ignore data with unknown status */
! 1412: break;
! 1413: }
! 1414: return 0;
! 1415: }
! 1416: if (packet->status >= 0x80) { /* is it a voice message ? */
! 1417: if (packet->index == 0) {
! 1418: packet->buf[0] = packet->status >> 4 | cable_number << 4;
! 1419: packet->buf[1] = packet->status;
! 1420: packet->index = 2;
! 1421: }
! 1422: packet->buf[packet->index++] = data;
! 1423: if (packet->index >= UMIDI_VOICELEN(packet->status))
! 1424: goto packetready;
! 1425: }
! 1426: /* ignore data with unknown status */
! 1427: return 0;
! 1428:
! 1429: packetready:
! 1430: while (packet->index < UMIDI_PACKET_SIZE)
! 1431: packet->buf[packet->index++] = 0;
! 1432: packet->index = 0;
! 1433: memcpy(obuf, packet->buf, UMIDI_PACKET_SIZE);
! 1434: return 1;
! 1435: }
CVSweb