[BACK]Return to umidi.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / usb

Annotation of src/sys/dev/usb/umidi.c, Revision 1.25.2.7

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

CVSweb <webmaster@jp.NetBSD.org>