[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.23.2.4

1.23.2.4! yamt        1: /*     $NetBSD: umidi.c,v 1.23.2.3 2007/09/03 14:39:18 yamt 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.23.2.2  yamt        7:  * by Takuya SHIOZAKI (tshiozak@NetBSD.org) and (full-size transfers, extended
                      8:  * hw_if) Chapman Flack (chap@NetBSD.org).
1.1       tshiozak    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:  */
1.10      lukem      38:
                     39: #include <sys/cdefs.h>
1.23.2.4! yamt       40: __KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.23.2.3 2007/09/03 14:39:18 yamt Exp $");
1.1       tshiozak   41:
1.23.2.2  yamt       42: #include <sys/types.h>
1.1       tshiozak   43: #include <sys/param.h>
                     44: #include <sys/systm.h>
                     45: #include <sys/kernel.h>
                     46: #include <sys/malloc.h>
                     47: #include <sys/device.h>
                     48: #include <sys/ioctl.h>
                     49: #include <sys/conf.h>
                     50: #include <sys/file.h>
                     51: #include <sys/select.h>
                     52: #include <sys/proc.h>
                     53: #include <sys/vnode.h>
                     54: #include <sys/poll.h>
                     55: #include <sys/lock.h>
1.23.2.4! yamt       56: #include <sys/intr.h>
1.23.2.2  yamt       57:
1.1       tshiozak   58: #include <dev/usb/usb.h>
                     59: #include <dev/usb/usbdi.h>
                     60: #include <dev/usb/usbdi_util.h>
                     61:
                     62: #include <dev/usb/usbdevs.h>
                     63: #include <dev/usb/uaudioreg.h>
                     64: #include <dev/usb/umidireg.h>
                     65: #include <dev/usb/umidivar.h>
                     66: #include <dev/usb/umidi_quirks.h>
                     67:
                     68: #include <dev/midi_if.h>
                     69:
                     70: #ifdef UMIDI_DEBUG
                     71: #define DPRINTF(x)     if (umididebug) printf x
                     72: #define DPRINTFN(n,x)  if (umididebug >= (n)) printf x
1.23.2.2  yamt       73: #include <sys/time.h>
                     74: static struct timeval umidi_tv;
1.1       tshiozak   75: int    umididebug = 0;
                     76: #else
                     77: #define DPRINTF(x)
                     78: #define DPRINTFN(n,x)
                     79: #endif
                     80:
                     81:
                     82: static int umidi_open(void *, int,
                     83:                      void (*)(void *, int), void (*)(void *), void *);
                     84: static void umidi_close(void *);
1.23.2.2  yamt       85: static int umidi_channelmsg(void *, int, int, u_char *, int);
                     86: static int umidi_commonmsg(void *, int, u_char *, int);
                     87: static int umidi_sysex(void *, u_char *, int);
                     88: static int umidi_rtmsg(void *, int);
1.1       tshiozak   89: static void umidi_getinfo(void *, struct midi_info *);
                     90:
1.3       tshiozak   91: static usbd_status alloc_pipe(struct umidi_endpoint *);
                     92: static void free_pipe(struct umidi_endpoint *);
1.1       tshiozak   93:
                     94: static usbd_status alloc_all_endpoints(struct umidi_softc *);
                     95: static void free_all_endpoints(struct umidi_softc *);
                     96:
                     97: static usbd_status alloc_all_jacks(struct umidi_softc *);
                     98: static void free_all_jacks(struct umidi_softc *);
                     99: static usbd_status bind_jacks_to_mididev(struct umidi_softc *,
                    100:                                         struct umidi_jack *,
                    101:                                         struct umidi_jack *,
                    102:                                         struct umidi_mididev *);
1.4       tshiozak  103: static void unbind_jacks_from_mididev(struct umidi_mididev *);
                    104: static void unbind_all_jacks(struct umidi_softc *);
1.1       tshiozak  105: static usbd_status assign_all_jacks_automatically(struct umidi_softc *);
1.4       tshiozak  106: static usbd_status open_out_jack(struct umidi_jack *, void *,
                    107:                                 void (*)(void *));
                    108: static usbd_status open_in_jack(struct umidi_jack *, void *,
                    109:                                void (*)(void *, int));
                    110: static void close_out_jack(struct umidi_jack *);
                    111: static void close_in_jack(struct umidi_jack *);
1.1       tshiozak  112:
1.23.2.2  yamt      113: static usbd_status attach_mididev(struct umidi_softc *, struct umidi_mididev *);
1.1       tshiozak  114: static usbd_status detach_mididev(struct umidi_mididev *, int);
                    115: static usbd_status deactivate_mididev(struct umidi_mididev *);
                    116: static usbd_status alloc_all_mididevs(struct umidi_softc *, int);
                    117: static void free_all_mididevs(struct umidi_softc *);
                    118: static usbd_status attach_all_mididevs(struct umidi_softc *);
                    119: static usbd_status detach_all_mididevs(struct umidi_softc *, int);
                    120: static usbd_status deactivate_all_mididevs(struct umidi_softc *);
1.23.2.2  yamt      121: static char *describe_mididev(struct umidi_mididev *);
1.1       tshiozak  122:
                    123: #ifdef UMIDI_DEBUG
                    124: static void dump_sc(struct umidi_softc *);
                    125: static void dump_ep(struct umidi_endpoint *);
                    126: static void dump_jack(struct umidi_jack *);
                    127: #endif
                    128:
                    129: static usbd_status start_input_transfer(struct umidi_endpoint *);
                    130: static usbd_status start_output_transfer(struct umidi_endpoint *);
1.23.2.2  yamt      131: static int out_jack_output(struct umidi_jack *, u_char *, int, int);
1.1       tshiozak  132: static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
                    133: static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
1.23.2.2  yamt      134: static void out_solicit(void *); /* struct umidi_endpoint* for softintr */
1.1       tshiozak  135:
                    136:
1.22      yamt      137: const struct midi_hw_if umidi_hw_if = {
1.1       tshiozak  138:        umidi_open,
                    139:        umidi_close,
1.23.2.2  yamt      140:        umidi_rtmsg,
1.1       tshiozak  141:        umidi_getinfo,
                    142:        0,              /* ioctl */
                    143: };
                    144:
1.23.2.2  yamt      145: struct midi_hw_if_ext umidi_hw_if_ext = {
                    146:        .channel = umidi_channelmsg,
                    147:        .common  = umidi_commonmsg,
                    148:        .sysex   = umidi_sysex,
                    149: };
                    150:
                    151: struct midi_hw_if_ext umidi_hw_if_mm = {
                    152:        .channel = umidi_channelmsg,
                    153:        .common  = umidi_commonmsg,
                    154:        .sysex   = umidi_sysex,
                    155:        .compress = 1,
                    156: };
                    157:
1.1       tshiozak  158: USB_DECLARE_DRIVER(umidi);
                    159:
                    160: USB_MATCH(umidi)
                    161: {
1.23.2.3  yamt      162:        USB_IFMATCH_START(umidi, uaa);
1.1       tshiozak  163:
                    164:        DPRINTFN(1,("umidi_match\n"));
                    165:
1.3       tshiozak  166:        if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno))
                    167:                return UMATCH_IFACECLASS_IFACESUBCLASS;
1.1       tshiozak  168:
1.23.2.3  yamt      169:        if (uaa->class == UICLASS_AUDIO &&
                    170:            uaa->subclass == UISUBCLASS_MIDISTREAM)
1.3       tshiozak  171:                return UMATCH_IFACECLASS_IFACESUBCLASS;
1.1       tshiozak  172:
1.3       tshiozak  173:        return UMATCH_NONE;
1.1       tshiozak  174: }
                    175:
                    176: USB_ATTACH(umidi)
                    177: {
                    178:        usbd_status err;
1.23.2.3  yamt      179:        USB_IFATTACH_START(umidi, sc, uaa);
1.23      augustss  180:        char *devinfop;
1.1       tshiozak  181:
                    182:        DPRINTFN(1,("umidi_attach\n"));
                    183:
1.23      augustss  184:        devinfop = usbd_devinfo_alloc(uaa->device, 0);
                    185:        printf("\n%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop);
                    186:        usbd_devinfo_free(devinfop);
1.1       tshiozak  187:
                    188:        sc->sc_iface = uaa->iface;
                    189:        sc->sc_udev = uaa->device;
                    190:
                    191:        sc->sc_quirk =
                    192:            umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno);
                    193:        printf("%s: ", USBDEVNAME(sc->sc_dev));
                    194:        umidi_print_quirk(sc->sc_quirk);
                    195:
                    196:
                    197:        err = alloc_all_endpoints(sc);
                    198:        if (err!=USBD_NORMAL_COMPLETION) {
                    199:                printf("%s: alloc_all_endpoints failed. (err=%d)\n",
                    200:                       USBDEVNAME(sc->sc_dev), err);
                    201:                goto error;
                    202:        }
                    203:        err = alloc_all_jacks(sc);
                    204:        if (err!=USBD_NORMAL_COMPLETION) {
                    205:                free_all_endpoints(sc);
                    206:                printf("%s: alloc_all_jacks failed. (err=%d)\n",
                    207:                       USBDEVNAME(sc->sc_dev), err);
                    208:                goto error;
                    209:        }
                    210:        printf("%s: out=%d, in=%d\n",
                    211:               USBDEVNAME(sc->sc_dev),
                    212:               sc->sc_out_num_jacks, sc->sc_in_num_jacks);
                    213:
                    214:        err = assign_all_jacks_automatically(sc);
                    215:        if (err!=USBD_NORMAL_COMPLETION) {
                    216:                unbind_all_jacks(sc);
                    217:                free_all_jacks(sc);
                    218:                free_all_endpoints(sc);
                    219:                printf("%s: assign_all_jacks_automatically failed. (err=%d)\n",
                    220:                       USBDEVNAME(sc->sc_dev), err);
                    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:                printf("%s: attach_all_mididevs failed. (err=%d)\n",
                    228:                       USBDEVNAME(sc->sc_dev), err);
                    229:        }
                    230:
                    231: #ifdef UMIDI_DEBUG
                    232:        dump_sc(sc);
                    233: #endif
                    234:
                    235:        usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH,
                    236:                           sc->sc_udev, USBDEV(sc->sc_dev));
1.16      augustss  237:
1.1       tshiozak  238:        USB_ATTACH_SUCCESS_RETURN;
                    239: error:
                    240:        printf("%s: disabled.\n", USBDEVNAME(sc->sc_dev));
                    241:        sc->sc_dying = 1;
                    242:        USB_ATTACH_ERROR_RETURN;
                    243: }
                    244:
                    245: int
                    246: umidi_activate(device_ptr_t self, enum devact act)
                    247: {
1.3       tshiozak  248:        struct umidi_softc *sc = (struct umidi_softc *)self;
1.1       tshiozak  249:
                    250:        switch (act) {
                    251:        case DVACT_ACTIVATE:
                    252:                DPRINTFN(1,("umidi_activate (activate)\n"));
                    253:
                    254:                return EOPNOTSUPP;
                    255:                break;
                    256:        case DVACT_DEACTIVATE:
                    257:                DPRINTFN(1,("umidi_activate (deactivate)\n"));
                    258:                sc->sc_dying = 1;
                    259:                deactivate_all_mididevs(sc);
                    260:                break;
                    261:        }
                    262:        return 0;
                    263: }
                    264:
                    265: USB_DETACH(umidi)
                    266: {
1.3       tshiozak  267:        USB_DETACH_START(umidi, sc);
1.1       tshiozak  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:
1.3       tshiozak  277:        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
                    278:                           USBDEV(sc->sc_dev));
1.1       tshiozak  279:
                    280:        return 0;
                    281: }
                    282:
                    283:
1.4       tshiozak  284: /*
                    285:  * midi_if stuffs
                    286:  */
1.1       tshiozak  287: int
                    288: umidi_open(void *addr,
                    289:           int flags,
1.12      augustss  290:           void (*iintr)(void *, int),
                    291:           void (*ointr)(void *),
1.1       tshiozak  292:           void *arg)
                    293: {
1.3       tshiozak  294:        struct umidi_mididev *mididev = addr;
                    295:        struct umidi_softc *sc = mididev->sc;
1.23.2.2  yamt      296:        usbd_status err;
1.1       tshiozak  297:
                    298:        DPRINTF(("umidi_open: sc=%p\n", sc));
                    299:
                    300:        if (!sc)
                    301:                return ENXIO;
                    302:        if (mididev->opened)
                    303:                return EBUSY;
1.4       tshiozak  304:        if (sc->sc_dying)
1.1       tshiozak  305:                return EIO;
                    306:
1.4       tshiozak  307:        mididev->opened = 1;
1.1       tshiozak  308:        mididev->flags = flags;
1.23.2.2  yamt      309:        if ((mididev->flags & FWRITE) && mididev->out_jack) {
                    310:                err = open_out_jack(mididev->out_jack, arg, ointr);
                    311:                if ( err != USBD_NORMAL_COMPLETION )
                    312:                        goto bad;
                    313:        }
1.3       tshiozak  314:        if ((mididev->flags & FREAD) && mididev->in_jack) {
1.23.2.2  yamt      315:                err = open_in_jack(mididev->in_jack, arg, iintr);
                    316:                if ( err != USBD_NORMAL_COMPLETION
                    317:                &&   err != USBD_IN_PROGRESS )
                    318:                        goto bad;
1.3       tshiozak  319:        }
1.1       tshiozak  320:
                    321:        return 0;
1.23.2.2  yamt      322: bad:
                    323:        mididev->opened = 0;
                    324:        DPRINTF(("umidi_open: usbd_status %d\n", err));
                    325:        return USBD_IN_USE == err ? EBUSY : EIO;
1.1       tshiozak  326: }
                    327:
                    328: void
                    329: umidi_close(void *addr)
                    330: {
                    331:        int s;
1.3       tshiozak  332:        struct umidi_mididev *mididev = addr;
1.1       tshiozak  333:
                    334:        s = splusb();
                    335:        if ((mididev->flags & FWRITE) && mididev->out_jack)
1.4       tshiozak  336:                close_out_jack(mididev->out_jack);
1.1       tshiozak  337:        if ((mididev->flags & FREAD) && mididev->in_jack)
1.4       tshiozak  338:                close_in_jack(mididev->in_jack);
1.1       tshiozak  339:        mididev->opened = 0;
                    340:        splx(s);
                    341: }
                    342:
                    343: int
1.23.2.2  yamt      344: umidi_channelmsg(void *addr, int status, int channel, u_char *msg,
                    345:     int len)
                    346: {
                    347:        struct umidi_mididev *mididev = addr;
                    348:
                    349:        if (!mididev->out_jack || !mididev->opened)
                    350:                return EIO;
                    351:
                    352:        return out_jack_output(mididev->out_jack, msg, len, (status>>4)&0xf);
                    353: }
                    354:
                    355: int
                    356: umidi_commonmsg(void *addr, int status, u_char *msg, int len)
1.1       tshiozak  357: {
1.3       tshiozak  358:        struct umidi_mididev *mididev = addr;
1.23.2.2  yamt      359:        int cin;
1.1       tshiozak  360:
1.4       tshiozak  361:        if (!mididev->out_jack || !mididev->opened)
1.1       tshiozak  362:                return EIO;
                    363:
1.23.2.2  yamt      364:        switch ( len ) {
                    365:        case 1: cin = 5; break;
                    366:        case 2: cin = 2; break;
                    367:        case 3: cin = 3; break;
                    368:        default: return EIO; /* or gcc warns of cin uninitialized */
                    369:        }
                    370:
                    371:        return out_jack_output(mididev->out_jack, msg, len, cin);
                    372: }
                    373:
                    374: int
                    375: umidi_sysex(void *addr, u_char *msg, int len)
                    376: {
                    377:        struct umidi_mididev *mididev = addr;
                    378:        int cin;
                    379:
                    380:        if (!mididev->out_jack || !mididev->opened)
                    381:                return EIO;
                    382:
                    383:        switch ( len ) {
                    384:        case 1: cin = 5; break;
                    385:        case 2: cin = 6; break;
                    386:        case 3: cin = (msg[2] == 0xf7) ? 7 : 4; break;
                    387:        default: return EIO; /* or gcc warns of cin uninitialized */
                    388:        }
                    389:
                    390:        return out_jack_output(mididev->out_jack, msg, len, cin);
                    391: }
                    392:
                    393: int
                    394: umidi_rtmsg(void *addr, int d)
                    395: {
                    396:        struct umidi_mididev *mididev = addr;
                    397:        u_char msg = d;
                    398:
                    399:        if (!mididev->out_jack || !mididev->opened)
                    400:                return EIO;
                    401:
                    402:        return out_jack_output(mididev->out_jack, &msg, 1, 0xf);
1.1       tshiozak  403: }
                    404:
                    405: void
                    406: umidi_getinfo(void *addr, struct midi_info *mi)
                    407: {
1.3       tshiozak  408:        struct umidi_mididev *mididev = addr;
1.23.2.2  yamt      409:        struct umidi_softc *sc = mididev->sc;
                    410:        int mm = UMQ_ISTYPE(sc, UMQ_TYPE_MIDIMAN_GARBLE);
1.1       tshiozak  411:
1.23.2.2  yamt      412:        mi->name = mididev->label;
1.3       tshiozak  413:        mi->props = MIDI_PROP_OUT_INTR;
1.1       tshiozak  414:        if (mididev->in_jack)
                    415:                mi->props |= MIDI_PROP_CAN_INPUT;
1.23.2.2  yamt      416:        midi_register_hw_if_ext(mm? &umidi_hw_if_mm : &umidi_hw_if_ext);
1.1       tshiozak  417: }
                    418:
                    419:
1.4       tshiozak  420: /*
                    421:  * each endpoint stuffs
                    422:  */
1.1       tshiozak  423:
1.3       tshiozak  424: /* alloc/free pipe */
1.1       tshiozak  425: static usbd_status
1.3       tshiozak  426: alloc_pipe(struct umidi_endpoint *ep)
1.1       tshiozak  427: {
                    428:        struct umidi_softc *sc = ep->sc;
                    429:        usbd_status err;
1.23.2.2  yamt      430:        usb_endpoint_descriptor_t *epd;
                    431:
                    432:        epd = usbd_get_endpoint_descriptor(sc->sc_iface, ep->addr);
                    433:        /*
                    434:         * For output, an improvement would be to have a buffer bigger than
                    435:         * wMaxPacketSize by num_jacks-1 additional packet slots; that would
                    436:         * allow out_solicit to fill the buffer to the full packet size in
                    437:         * all cases. But to use usbd_alloc_buffer to get a slightly larger
                    438:         * buffer would not be a good way to do that, because if the addition
                    439:         * would make the buffer exceed USB_MEM_SMALL then a substantially
                    440:         * larger block may be wastefully allocated. Some flavor of double
                    441:         * buffering could serve the same purpose, but would increase the
                    442:         * code complexity, so for now I will live with the current slight
                    443:         * penalty of reducing max transfer size by (num_open-num_scheduled)
                    444:         * packet slots.
                    445:         */
                    446:        ep->buffer_size = UGETW(epd->wMaxPacketSize);
                    447:        ep->buffer_size -= ep->buffer_size % UMIDI_PACKET_SIZE;
                    448:
                    449:        DPRINTF(("%s: alloc_pipe %p, buffer size %u\n",
                    450:                USBDEVNAME(sc->sc_dev), ep, ep->buffer_size));
                    451:        ep->num_scheduled = 0;
                    452:        ep->this_schedule = 0;
                    453:        ep->next_schedule = 0;
                    454:        ep->soliciting = 0;
                    455:        ep->armed = 0;
1.3       tshiozak  456:        ep->xfer = usbd_alloc_xfer(sc->sc_udev);
1.11      augustss  457:        if (ep->xfer == NULL) {
1.3       tshiozak  458:            err = USBD_NOMEM;
                    459:            goto quit;
                    460:        }
1.23.2.2  yamt      461:        ep->buffer = usbd_alloc_buffer(ep->xfer, ep->buffer_size);
1.11      augustss  462:        if (ep->buffer == NULL) {
1.3       tshiozak  463:            usbd_free_xfer(ep->xfer);
                    464:            err = USBD_NOMEM;
                    465:            goto quit;
                    466:        }
1.23.2.2  yamt      467:        ep->next_slot = ep->buffer;
1.3       tshiozak  468:        err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe);
                    469:        if (err)
                    470:            usbd_free_xfer(ep->xfer);
1.23.2.4! yamt      471:        ep->solicit_cookie = softint_establish(SOFTINT_CLOCK, out_solicit, ep);
1.1       tshiozak  472: quit:
                    473:        return err;
                    474: }
                    475:
                    476: static void
1.3       tshiozak  477: free_pipe(struct umidi_endpoint *ep)
1.1       tshiozak  478: {
1.3       tshiozak  479:        DPRINTF(("%s: free_pipe %p\n", USBDEVNAME(ep->sc->sc_dev), ep));
                    480:        usbd_abort_pipe(ep->pipe);
                    481:        usbd_close_pipe(ep->pipe);
                    482:        usbd_free_xfer(ep->xfer);
1.23.2.4! yamt      483:        softint_disestablish(ep->solicit_cookie);
1.1       tshiozak  484: }
                    485:
                    486:
                    487: /* alloc/free the array of endpoint structures */
                    488:
                    489: static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *);
                    490: static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *);
                    491: static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *);
                    492:
                    493: static usbd_status
                    494: alloc_all_endpoints(struct umidi_softc *sc)
                    495: {
1.3       tshiozak  496:        usbd_status err;
                    497:        struct umidi_endpoint *ep;
                    498:        int i;
1.9       tshiozak  499:
1.3       tshiozak  500:        if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)) {
                    501:                err = alloc_all_endpoints_fixed_ep(sc);
                    502:        } else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)) {
                    503:                err = alloc_all_endpoints_yamaha(sc);
1.1       tshiozak  504:        } else {
1.3       tshiozak  505:                err = alloc_all_endpoints_genuine(sc);
1.1       tshiozak  506:        }
1.3       tshiozak  507:        if (err!=USBD_NORMAL_COMPLETION)
                    508:                return err;
                    509:
                    510:        ep = sc->sc_endpoints;
1.8       tshiozak  511:        for (i=sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i>0; i--) {
1.3       tshiozak  512:                err = alloc_pipe(ep++);
                    513:                if (err!=USBD_NORMAL_COMPLETION) {
                    514:                        for (; ep!=sc->sc_endpoints; ep--)
                    515:                                free_pipe(ep-1);
                    516:                        free(sc->sc_endpoints, M_USBDEV);
                    517:                        sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
                    518:                        break;
                    519:                }
                    520:        }
                    521:        return err;
1.1       tshiozak  522: }
                    523:
                    524: static void
                    525: free_all_endpoints(struct umidi_softc *sc)
                    526: {
1.3       tshiozak  527:        int i;
1.8       tshiozak  528:        for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++)
1.3       tshiozak  529:            free_pipe(&sc->sc_endpoints[i]);
1.14      kent      530:        if (sc->sc_endpoints != NULL)
                    531:                free(sc->sc_endpoints, M_USBDEV);
1.1       tshiozak  532:        sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
                    533: }
                    534:
                    535: static usbd_status
                    536: alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
                    537: {
1.3       tshiozak  538:        usbd_status err;
1.1       tshiozak  539:        struct umq_fixed_ep_desc *fp;
1.3       tshiozak  540:        struct umidi_endpoint *ep;
1.1       tshiozak  541:        usb_endpoint_descriptor_t *epd;
                    542:        int i;
                    543:
                    544:        fp = umidi_get_quirk_data_from_type(sc->sc_quirk,
                    545:                                            UMQ_TYPE_FIXED_EP);
                    546:        sc->sc_out_num_jacks = 0;
                    547:        sc->sc_in_num_jacks = 0;
                    548:        sc->sc_out_num_endpoints = fp->num_out_ep;
                    549:        sc->sc_in_num_endpoints = fp->num_in_ep;
                    550:        sc->sc_endpoints = malloc(sizeof(*sc->sc_out_ep)*
                    551:                                  (sc->sc_out_num_endpoints+
                    552:                                   sc->sc_in_num_endpoints),
                    553:                                  M_USBDEV, M_WAITOK);
                    554:        if (!sc->sc_endpoints) {
                    555:                return USBD_NOMEM;
                    556:        }
                    557:        sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
                    558:        sc->sc_in_ep =
                    559:            sc->sc_in_num_endpoints ?
                    560:                sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
1.3       tshiozak  561:
                    562:        ep = &sc->sc_out_ep[0];
1.1       tshiozak  563:        for (i=0; i<sc->sc_out_num_endpoints; i++) {
                    564:                epd = usbd_interface2endpoint_descriptor(
                    565:                        sc->sc_iface,
                    566:                        fp->out_ep[i].ep);
                    567:                if (!epd) {
                    568:                        printf("%s: cannot get endpoint descriptor(out:%d)\n",
                    569:                               USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
1.3       tshiozak  570:                        err = USBD_INVAL;
1.1       tshiozak  571:                        goto error;
                    572:                }
                    573:                if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK ||
                    574:                    UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_OUT) {
                    575:                        printf("%s: illegal endpoint(out:%d)\n",
                    576:                               USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
1.3       tshiozak  577:                        err = USBD_INVAL;
1.1       tshiozak  578:                        goto error;
                    579:                }
1.3       tshiozak  580:                ep->sc = sc;
                    581:                ep->addr = epd->bEndpointAddress;
                    582:                ep->num_jacks = fp->out_ep[i].num_jacks;
1.1       tshiozak  583:                sc->sc_out_num_jacks += fp->out_ep[i].num_jacks;
1.3       tshiozak  584:                ep->num_open = 0;
                    585:                memset(ep->jacks, 0, sizeof(ep->jacks));
                    586:                ep++;
1.1       tshiozak  587:        }
1.3       tshiozak  588:        ep = &sc->sc_in_ep[0];
1.1       tshiozak  589:        for (i=0; i<sc->sc_in_num_endpoints; i++) {
                    590:                epd = usbd_interface2endpoint_descriptor(
                    591:                        sc->sc_iface,
                    592:                        fp->in_ep[i].ep);
                    593:                if (!epd) {
                    594:                        printf("%s: cannot get endpoint descriptor(in:%d)\n",
                    595:                               USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
1.3       tshiozak  596:                        err = USBD_INVAL;
1.1       tshiozak  597:                        goto error;
                    598:                }
1.23.2.2  yamt      599:                /*
                    600:                 * MIDISPORT_2X4 inputs on an interrupt rather than a bulk
                    601:                 * endpoint.  The existing input logic in this driver seems
                    602:                 * to work successfully if we just stop treating an interrupt
                    603:                 * endpoint as illegal (or the in_progress status we get on
                    604:                 * the initial transfer).  It does not seem necessary to
                    605:                 * actually use the interrupt flavor of alloc_pipe or make
                    606:                 * other serious rearrangements of logic.  I like that.
                    607:                 */
                    608:                switch ( UE_GET_XFERTYPE(epd->bmAttributes) ) {
                    609:                case UE_BULK:
                    610:                case UE_INTERRUPT:
                    611:                        if ( UE_DIR_IN == UE_GET_DIR(epd->bEndpointAddress) )
                    612:                                break;
                    613:                        /*FALLTHROUGH*/
                    614:                default:
1.1       tshiozak  615:                        printf("%s: illegal endpoint(in:%d)\n",
                    616:                               USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
1.3       tshiozak  617:                        err = USBD_INVAL;
1.1       tshiozak  618:                        goto error;
                    619:                }
1.23.2.2  yamt      620:
1.3       tshiozak  621:                ep->sc = sc;
                    622:                ep->addr = epd->bEndpointAddress;
                    623:                ep->num_jacks = fp->in_ep[i].num_jacks;
1.1       tshiozak  624:                sc->sc_in_num_jacks += fp->in_ep[i].num_jacks;
1.3       tshiozak  625:                ep->num_open = 0;
                    626:                memset(ep->jacks, 0, sizeof(ep->jacks));
                    627:                ep++;
1.1       tshiozak  628:        }
                    629:
                    630:        return USBD_NORMAL_COMPLETION;
                    631: error:
                    632:        free(sc->sc_endpoints, M_USBDEV);
                    633:        sc->sc_endpoints = NULL;
1.3       tshiozak  634:        return err;
1.1       tshiozak  635: }
                    636:
                    637: static usbd_status
                    638: alloc_all_endpoints_yamaha(struct umidi_softc *sc)
                    639: {
                    640:        /* This driver currently supports max 1in/1out bulk endpoints */
                    641:        usb_descriptor_t *desc;
1.23.2.3  yamt      642:        umidi_cs_descriptor_t *udesc;
1.8       tshiozak  643:        usb_endpoint_descriptor_t *epd;
                    644:        int out_addr, in_addr, i;
                    645:        int dir;
1.1       tshiozak  646:        size_t remain, descsize;
                    647:
1.8       tshiozak  648:        sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
                    649:        out_addr = in_addr = 0;
                    650:
                    651:        /* detect endpoints */
1.1       tshiozak  652:        desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
1.8       tshiozak  653:        for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) {
                    654:                epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
1.23.2.1  yamt      655:                KASSERT(epd != NULL);
1.8       tshiozak  656:                if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) {
                    657:                        dir = UE_GET_DIR(epd->bEndpointAddress);
                    658:                        if (dir==UE_DIR_OUT && !out_addr)
                    659:                                out_addr = epd->bEndpointAddress;
                    660:                        else if (dir==UE_DIR_IN && !in_addr)
                    661:                                in_addr = epd->bEndpointAddress;
                    662:                }
                    663:        }
1.23.2.3  yamt      664:        udesc = (umidi_cs_descriptor_t *)NEXT_D(desc);
1.1       tshiozak  665:
1.8       tshiozak  666:        /* count jacks */
1.23.2.3  yamt      667:        if (!(udesc->bDescriptorType==UDESC_CS_INTERFACE &&
                    668:              udesc->bDescriptorSubtype==UMIDI_MS_HEADER))
1.8       tshiozak  669:                return USBD_INVAL;
1.23.2.3  yamt      670:        remain = (size_t)UGETW(TO_CSIFD(udesc)->wTotalLength) -
                    671:                (size_t)udesc->bLength;
                    672:        udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc);
1.1       tshiozak  673:
                    674:        while (remain>=sizeof(usb_descriptor_t)) {
1.23.2.3  yamt      675:                descsize = udesc->bLength;
1.1       tshiozak  676:                if (descsize>remain || descsize==0)
                    677:                        break;
1.23.2.3  yamt      678:                if (udesc->bDescriptorType==UDESC_CS_INTERFACE &&
1.1       tshiozak  679:                    remain>=UMIDI_JACK_DESCRIPTOR_SIZE) {
1.23.2.3  yamt      680:                        if (udesc->bDescriptorSubtype==UMIDI_OUT_JACK)
1.1       tshiozak  681:                                sc->sc_out_num_jacks++;
1.23.2.3  yamt      682:                        else if (udesc->bDescriptorSubtype==UMIDI_IN_JACK)
1.1       tshiozak  683:                                sc->sc_in_num_jacks++;
                    684:                }
1.23.2.3  yamt      685:                udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc);
1.1       tshiozak  686:                remain-=descsize;
                    687:        }
                    688:
1.8       tshiozak  689:        /* validate some parameters */
1.1       tshiozak  690:        if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS)
                    691:                sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS;
                    692:        if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS)
                    693:                sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS;
1.8       tshiozak  694:        if (sc->sc_out_num_jacks && out_addr) {
1.1       tshiozak  695:                sc->sc_out_num_endpoints = 1;
                    696:        } else {
                    697:                sc->sc_out_num_endpoints = 0;
                    698:                sc->sc_out_num_jacks = 0;
                    699:        }
1.8       tshiozak  700:        if (sc->sc_in_num_jacks && in_addr) {
1.1       tshiozak  701:                sc->sc_in_num_endpoints = 1;
                    702:        } else {
                    703:                sc->sc_in_num_endpoints = 0;
                    704:                sc->sc_in_num_jacks = 0;
                    705:        }
                    706:        sc->sc_endpoints = malloc(sizeof(struct umidi_endpoint)*
                    707:                                  (sc->sc_out_num_endpoints+
                    708:                                   sc->sc_in_num_endpoints),
                    709:                                  M_USBDEV, M_WAITOK);
                    710:        if (!sc->sc_endpoints)
                    711:                return USBD_NOMEM;
                    712:        if (sc->sc_out_num_endpoints) {
                    713:                sc->sc_out_ep = sc->sc_endpoints;
                    714:                sc->sc_out_ep->sc = sc;
                    715:                sc->sc_out_ep->addr = out_addr;
                    716:                sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks;
                    717:                sc->sc_out_ep->num_open = 0;
                    718:                memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks));
                    719:        } else
                    720:                sc->sc_out_ep = NULL;
                    721:
                    722:        if (sc->sc_in_num_endpoints) {
                    723:                sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints;
                    724:                sc->sc_in_ep->sc = sc;
                    725:                sc->sc_in_ep->addr = in_addr;
                    726:                sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks;
                    727:                sc->sc_in_ep->num_open = 0;
                    728:                memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks));
                    729:        } else
                    730:                sc->sc_in_ep = NULL;
                    731:
                    732:        return USBD_NORMAL_COMPLETION;
                    733: }
                    734:
                    735: static usbd_status
                    736: alloc_all_endpoints_genuine(struct umidi_softc *sc)
                    737: {
1.20      gson      738:        usb_interface_descriptor_t *interface_desc;
                    739:        usb_config_descriptor_t *config_desc;
1.1       tshiozak  740:        usb_descriptor_t *desc;
1.7       tshiozak  741:        int num_ep;
1.1       tshiozak  742:        size_t remain, descsize;
                    743:        struct umidi_endpoint *p, *q, *lowest, *endep, tmpep;
                    744:        int epaddr;
                    745:
1.20      gson      746:        interface_desc = usbd_get_interface_descriptor(sc->sc_iface);
                    747:        num_ep = interface_desc->bNumEndpoints;
                    748:        sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint) * num_ep,
1.1       tshiozak  749:                                      M_USBDEV, M_WAITOK);
                    750:        if (!p)
                    751:                return USBD_NOMEM;
                    752:
                    753:        sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
                    754:        sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0;
                    755:        epaddr = -1;
                    756:
                    757:        /* get the list of endpoints for midi stream */
1.20      gson      758:        config_desc = usbd_get_config_descriptor(sc->sc_udev);
                    759:        desc = (usb_descriptor_t *) config_desc;
                    760:        remain = (size_t)UGETW(config_desc->wTotalLength);
1.1       tshiozak  761:        while (remain>=sizeof(usb_descriptor_t)) {
                    762:                descsize = desc->bLength;
                    763:                if (descsize>remain || descsize==0)
                    764:                        break;
                    765:                if (desc->bDescriptorType==UDESC_ENDPOINT &&
                    766:                    remain>=USB_ENDPOINT_DESCRIPTOR_SIZE &&
                    767:                    UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) {
                    768:                        epaddr = TO_EPD(desc)->bEndpointAddress;
                    769:                } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT &&
                    770:                           remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE &&
                    771:                           epaddr!=-1) {
                    772:                        if (num_ep>0) {
1.9       tshiozak  773:                                num_ep--;
1.1       tshiozak  774:                                p->sc = sc;
                    775:                                p->addr = epaddr;
                    776:                                p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack;
                    777:                                if (UE_GET_DIR(epaddr)==UE_DIR_OUT) {
                    778:                                        sc->sc_out_num_endpoints++;
                    779:                                        sc->sc_out_num_jacks += p->num_jacks;
                    780:                                } else {
                    781:                                        sc->sc_in_num_endpoints++;
                    782:                                        sc->sc_in_num_jacks += p->num_jacks;
                    783:                                }
                    784:                                p++;
                    785:                        }
                    786:                } else
                    787:                        epaddr = -1;
                    788:                desc = NEXT_D(desc);
                    789:                remain-=descsize;
                    790:        }
                    791:
                    792:        /* sort endpoints */
                    793:        num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints;
                    794:        p = sc->sc_endpoints;
                    795:        endep = p + num_ep;
                    796:        while (p<endep) {
                    797:                lowest = p;
                    798:                for (q=p+1; q<endep; q++) {
                    799:                        if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN &&
                    800:                             UE_GET_DIR(q->addr)==UE_DIR_OUT) ||
                    801:                            ((UE_GET_DIR(lowest->addr)==
                    802:                              UE_GET_DIR(q->addr)) &&
                    803:                             (UE_GET_ADDR(lowest->addr)>
                    804:                              UE_GET_ADDR(q->addr))))
                    805:                                lowest = q;
                    806:                }
                    807:                if (lowest != p) {
                    808:                        memcpy((void *)&tmpep, (void *)p, sizeof(tmpep));
                    809:                        memcpy((void *)p, (void *)lowest, sizeof(tmpep));
                    810:                        memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep));
                    811:                }
1.7       tshiozak  812:                p->num_open = 0;
                    813:                p++;
1.1       tshiozak  814:        }
1.16      augustss  815:
1.1       tshiozak  816:        sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
                    817:        sc->sc_in_ep =
                    818:            sc->sc_in_num_endpoints ?
                    819:                sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
                    820:
                    821:        return USBD_NORMAL_COMPLETION;
                    822: }
                    823:
                    824:
1.4       tshiozak  825: /*
                    826:  * jack stuffs
                    827:  */
                    828:
1.1       tshiozak  829: static usbd_status
                    830: alloc_all_jacks(struct umidi_softc *sc)
                    831: {
                    832:        int i, j;
                    833:        struct umidi_endpoint *ep;
1.23.2.2  yamt      834:        struct umidi_jack *jack;
                    835:        unsigned char *cn_spec;
                    836:
                    837:        if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_SEQ_PER_EP))
                    838:                sc->cblnums_global = 0;
                    839:        else if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_SEQ_GLOBAL))
                    840:                sc->cblnums_global = 1;
                    841:        else {
                    842:                /*
                    843:                 * I don't think this default is correct, but it preserves
                    844:                 * the prior behavior of the code. That's why I defined two
                    845:                 * complementary quirks. Any device for which the default
                    846:                 * behavior is wrong can be made to work by giving it an
                    847:                 * explicit quirk, and if a pattern ever develops (as I suspect
                    848:                 * it will) that a lot of otherwise standard USB MIDI devices
                    849:                 * need the CN_SEQ_PER_EP "quirk," then this default can be
                    850:                 * changed to 0, and the only devices that will break are those
                    851:                 * listing neither quirk, and they'll easily be fixed by giving
                    852:                 * them the CN_SEQ_GLOBAL quirk.
                    853:                 */
                    854:                sc->cblnums_global = 1;
                    855:        }
                    856:
                    857:        if (UMQ_ISTYPE(sc, UMQ_TYPE_CN_FIXED))
                    858:                cn_spec = umidi_get_quirk_data_from_type(sc->sc_quirk,
                    859:                                                         UMQ_TYPE_CN_FIXED);
                    860:        else
                    861:                cn_spec = NULL;
1.1       tshiozak  862:
                    863:        /* allocate/initialize structures */
                    864:        sc->sc_jacks =
                    865:            malloc(sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+
                    866:                                              sc->sc_out_num_jacks),
                    867:                   M_USBDEV, M_WAITOK);
                    868:        if (!sc->sc_jacks)
                    869:                return USBD_NOMEM;
                    870:        sc->sc_out_jacks =
                    871:            sc->sc_out_num_jacks ? sc->sc_jacks : NULL;
                    872:        sc->sc_in_jacks =
                    873:            sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL;
                    874:
                    875:        jack = &sc->sc_out_jacks[0];
                    876:        for (i=0; i<sc->sc_out_num_jacks; i++) {
1.4       tshiozak  877:                jack->opened = 0;
                    878:                jack->binded = 0;
                    879:                jack->arg = NULL;
                    880:                jack->u.out.intr = NULL;
1.23.2.2  yamt      881:                jack->midiman_ppkt = NULL;
                    882:                if ( sc->cblnums_global )
                    883:                        jack->cable_number = i;
1.1       tshiozak  884:                jack++;
                    885:        }
                    886:        jack = &sc->sc_in_jacks[0];
                    887:        for (i=0; i<sc->sc_in_num_jacks; i++) {
1.4       tshiozak  888:                jack->opened = 0;
                    889:                jack->binded = 0;
                    890:                jack->arg = NULL;
                    891:                jack->u.in.intr = NULL;
1.23.2.2  yamt      892:                if ( sc->cblnums_global )
                    893:                        jack->cable_number = i;
1.1       tshiozak  894:                jack++;
                    895:        }
                    896:
                    897:        /* assign each jacks to each endpoints */
                    898:        jack = &sc->sc_out_jacks[0];
                    899:        ep = &sc->sc_out_ep[0];
                    900:        for (i=0; i<sc->sc_out_num_endpoints; i++) {
                    901:                for (j=0; j<ep->num_jacks; j++) {
                    902:                        jack->endpoint = ep;
1.23.2.2  yamt      903:                        if ( cn_spec != NULL )
                    904:                                jack->cable_number = *cn_spec++;
                    905:                        else if ( !sc->cblnums_global )
                    906:                                jack->cable_number = j;
                    907:                        ep->jacks[jack->cable_number] = jack;
1.1       tshiozak  908:                        jack++;
                    909:                }
                    910:                ep++;
                    911:        }
                    912:        jack = &sc->sc_in_jacks[0];
                    913:        ep = &sc->sc_in_ep[0];
                    914:        for (i=0; i<sc->sc_in_num_endpoints; i++) {
                    915:                for (j=0; j<ep->num_jacks; j++) {
                    916:                        jack->endpoint = ep;
1.23.2.2  yamt      917:                        if ( cn_spec != NULL )
                    918:                                jack->cable_number = *cn_spec++;
                    919:                        else if ( !sc->cblnums_global )
                    920:                                jack->cable_number = j;
                    921:                        ep->jacks[jack->cable_number] = jack;
1.1       tshiozak  922:                        jack++;
                    923:                }
                    924:                ep++;
                    925:        }
                    926:
                    927:        return USBD_NORMAL_COMPLETION;
                    928: }
                    929:
                    930: static void
                    931: free_all_jacks(struct umidi_softc *sc)
                    932: {
                    933:        int s;
                    934:
                    935:        s = splaudio();
                    936:        if (sc->sc_out_jacks) {
                    937:                free(sc->sc_jacks, M_USBDEV);
                    938:                sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL;
                    939:        }
                    940:        splx(s);
                    941: }
                    942:
                    943: static usbd_status
                    944: bind_jacks_to_mididev(struct umidi_softc *sc,
                    945:                      struct umidi_jack *out_jack,
                    946:                      struct umidi_jack *in_jack,
                    947:                      struct umidi_mididev *mididev)
                    948: {
1.8       tshiozak  949:        if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded))
1.4       tshiozak  950:                return USBD_IN_USE;
                    951:        if (mididev->out_jack || mididev->in_jack)
1.1       tshiozak  952:                return USBD_IN_USE;
                    953:
1.4       tshiozak  954:        if (out_jack)
                    955:                out_jack->binded = 1;
                    956:        if (in_jack)
                    957:                in_jack->binded = 1;
1.1       tshiozak  958:        mididev->in_jack = in_jack;
                    959:        mididev->out_jack = out_jack;
                    960:
                    961:        return USBD_NORMAL_COMPLETION;
                    962: }
                    963:
1.4       tshiozak  964: static void
1.1       tshiozak  965: unbind_jacks_from_mididev(struct umidi_mididev *mididev)
                    966: {
1.15      tshiozak  967:        if ((mididev->flags & FWRITE) && mididev->out_jack)
1.4       tshiozak  968:                close_out_jack(mididev->out_jack);
1.15      tshiozak  969:        if ((mididev->flags & FREAD) && mididev->in_jack)
1.4       tshiozak  970:                close_in_jack(mididev->in_jack);
1.1       tshiozak  971:
1.4       tshiozak  972:        if (mididev->out_jack)
                    973:                mididev->out_jack->binded = 0;
                    974:        if (mididev->in_jack)
                    975:                mididev->in_jack->binded = 0;
                    976:        mididev->out_jack = mididev->in_jack = NULL;
1.1       tshiozak  977: }
                    978:
1.4       tshiozak  979: static void
1.1       tshiozak  980: unbind_all_jacks(struct umidi_softc *sc)
                    981: {
                    982:        int i;
                    983:
                    984:        if (sc->sc_mididevs)
                    985:                for (i=0; i<sc->sc_num_mididevs; i++) {
1.4       tshiozak  986:                        unbind_jacks_from_mididev(&sc->sc_mididevs[i]);
1.1       tshiozak  987:                }
                    988: }
                    989:
                    990: static usbd_status
                    991: assign_all_jacks_automatically(struct umidi_softc *sc)
                    992: {
                    993:        usbd_status err;
                    994:        int i;
                    995:        struct umidi_jack *out, *in;
1.23.2.2  yamt      996:        signed char *asg_spec;
1.1       tshiozak  997:
                    998:        err =
                    999:            alloc_all_mididevs(sc,
                   1000:                               max(sc->sc_out_num_jacks, sc->sc_in_num_jacks));
                   1001:        if (err!=USBD_NORMAL_COMPLETION)
                   1002:                return err;
                   1003:
1.23.2.2  yamt     1004:        if ( UMQ_ISTYPE(sc, UMQ_TYPE_MD_FIXED))
                   1005:                asg_spec = umidi_get_quirk_data_from_type(sc->sc_quirk,
                   1006:                                                          UMQ_TYPE_MD_FIXED);
                   1007:        else
                   1008:                asg_spec = NULL;
                   1009:
1.1       tshiozak 1010:        for (i=0; i<sc->sc_num_mididevs; i++) {
1.23.2.2  yamt     1011:                if ( asg_spec != NULL ) {
                   1012:                        if ( *asg_spec == -1 )
                   1013:                                out = NULL;
                   1014:                        else
                   1015:                                out = &sc->sc_out_jacks[*asg_spec];
                   1016:                        ++ asg_spec;
                   1017:                        if ( *asg_spec == -1 )
                   1018:                                in = NULL;
                   1019:                        else
                   1020:                                in = &sc->sc_in_jacks[*asg_spec];
                   1021:                        ++ asg_spec;
                   1022:                } else {
                   1023:                        out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i]
                   1024:                                                       : NULL;
                   1025:                        in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i]
                   1026:                                                     : NULL;
                   1027:                }
1.1       tshiozak 1028:                err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]);
                   1029:                if (err!=USBD_NORMAL_COMPLETION) {
                   1030:                        free_all_mididevs(sc);
                   1031:                        return err;
                   1032:                }
                   1033:        }
                   1034:
                   1035:        return USBD_NORMAL_COMPLETION;
                   1036: }
                   1037:
                   1038: static usbd_status
1.4       tshiozak 1039: open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *))
                   1040: {
                   1041:        struct umidi_endpoint *ep = jack->endpoint;
1.23.2.2  yamt     1042:        umidi_packet_bufp end;
                   1043:        int s;
                   1044:        int err;
1.4       tshiozak 1045:
                   1046:        if (jack->opened)
                   1047:                return USBD_IN_USE;
                   1048:
                   1049:        jack->arg = arg;
                   1050:        jack->u.out.intr = intr;
1.23.2.2  yamt     1051:        jack->midiman_ppkt = NULL;
                   1052:        end = ep->buffer + ep->buffer_size / sizeof *ep->buffer;
                   1053:        s = splusb();
1.4       tshiozak 1054:        jack->opened = 1;
                   1055:        ep->num_open++;
1.23.2.2  yamt     1056:        /*
                   1057:         * out_solicit maintains an invariant that there will always be
                   1058:         * (num_open - num_scheduled) slots free in the buffer. as we have
                   1059:         * just incremented num_open, the buffer may be too full to satisfy
                   1060:         * the invariant until a transfer completes, for which we must wait.
                   1061:         */
                   1062:        while ( end - ep->next_slot < ep->num_open - ep->num_scheduled ) {
                   1063:                err = tsleep(ep, PWAIT|PCATCH, "umi op", mstohz(10));
                   1064:                if ( err ) {
                   1065:                        ep->num_open--;
                   1066:                        jack->opened = 0;
                   1067:                        splx(s);
                   1068:                        return USBD_IOERROR;
                   1069:                }
                   1070:        }
                   1071:        splx(s);
1.4       tshiozak 1072:
                   1073:        return USBD_NORMAL_COMPLETION;
                   1074: }
                   1075:
                   1076: static usbd_status
                   1077: open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int))
1.1       tshiozak 1078: {
1.3       tshiozak 1079:        usbd_status err = USBD_NORMAL_COMPLETION;
                   1080:        struct umidi_endpoint *ep = jack->endpoint;
                   1081:
1.4       tshiozak 1082:        if (jack->opened)
                   1083:                return USBD_IN_USE;
                   1084:
                   1085:        jack->arg = arg;
                   1086:        jack->u.in.intr = intr;
                   1087:        jack->opened = 1;
1.3       tshiozak 1088:        if (ep->num_open++==0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
                   1089:                err = start_input_transfer(ep);
1.18      gson     1090:                if (err != USBD_NORMAL_COMPLETION &&
                   1091:                    err != USBD_IN_PROGRESS) {
1.3       tshiozak 1092:                        ep->num_open--;
                   1093:                }
                   1094:        }
                   1095:
                   1096:        return err;
1.1       tshiozak 1097: }
                   1098:
                   1099: static void
1.4       tshiozak 1100: close_out_jack(struct umidi_jack *jack)
1.1       tshiozak 1101: {
1.23.2.2  yamt     1102:        struct umidi_endpoint *ep;
1.3       tshiozak 1103:        int s;
1.23.2.2  yamt     1104:        u_int16_t mask;
                   1105:        int err;
1.4       tshiozak 1106:
                   1107:        if (jack->opened) {
1.23.2.2  yamt     1108:                ep = jack->endpoint;
                   1109:                mask = 1 << (jack->cable_number);
1.4       tshiozak 1110:                s = splusb();
1.23.2.2  yamt     1111:                while ( mask & (ep->this_schedule | ep->next_schedule) ) {
                   1112:                        err = tsleep(ep, PWAIT|PCATCH, "umi dr", mstohz(10));
                   1113:                        if ( err )
1.15      tshiozak 1114:                                break;
1.3       tshiozak 1115:                }
1.4       tshiozak 1116:                jack->opened = 0;
                   1117:                jack->endpoint->num_open--;
1.23.2.2  yamt     1118:                ep->this_schedule &= ~mask;
                   1119:                ep->next_schedule &= ~mask;
                   1120:                splx(s);
1.3       tshiozak 1121:        }
1.1       tshiozak 1122: }
                   1123:
1.4       tshiozak 1124: static void
                   1125: close_in_jack(struct umidi_jack *jack)
                   1126: {
                   1127:        if (jack->opened) {
                   1128:                jack->opened = 0;
1.19      gson     1129:                if (--jack->endpoint->num_open == 0) {
                   1130:                    usbd_abort_pipe(jack->endpoint->pipe);
                   1131:                }
1.4       tshiozak 1132:        }
                   1133: }
1.1       tshiozak 1134:
                   1135: static usbd_status
                   1136: attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev)
                   1137: {
                   1138:        if (mididev->sc)
                   1139:                return USBD_IN_USE;
                   1140:
                   1141:        mididev->sc = sc;
1.23.2.2  yamt     1142:
                   1143:        mididev->label = describe_mididev(mididev);
1.1       tshiozak 1144:
                   1145:        mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, &sc->sc_dev);
                   1146:
                   1147:        return USBD_NORMAL_COMPLETION;
                   1148: }
                   1149:
                   1150: static usbd_status
                   1151: detach_mididev(struct umidi_mididev *mididev, int flags)
                   1152: {
                   1153:        if (!mididev->sc)
                   1154:                return USBD_NO_ADDR;
                   1155:
                   1156:        if (mididev->opened) {
                   1157:                umidi_close(mididev);
                   1158:        }
1.4       tshiozak 1159:        unbind_jacks_from_mididev(mididev);
1.1       tshiozak 1160:
                   1161:        if (mididev->mdev)
                   1162:                config_detach(mididev->mdev, flags);
1.23.2.2  yamt     1163:
                   1164:        if (NULL != mididev->label) {
                   1165:                free(mididev->label, M_USBDEV);
                   1166:                mididev->label = NULL;
                   1167:        }
1.1       tshiozak 1168:
                   1169:        mididev->sc = NULL;
                   1170:
                   1171:        return USBD_NORMAL_COMPLETION;
                   1172: }
                   1173:
                   1174: static usbd_status
                   1175: deactivate_mididev(struct umidi_mididev *mididev)
                   1176: {
1.4       tshiozak 1177:        if (mididev->out_jack)
                   1178:                mididev->out_jack->binded = 0;
                   1179:        if (mididev->in_jack)
                   1180:                mididev->in_jack->binded = 0;
1.1       tshiozak 1181:        config_deactivate(mididev->mdev);
                   1182:
                   1183:        return USBD_NORMAL_COMPLETION;
                   1184: }
                   1185:
                   1186: static usbd_status
                   1187: alloc_all_mididevs(struct umidi_softc *sc, int nmidi)
                   1188: {
                   1189:        sc->sc_num_mididevs = nmidi;
                   1190:        sc->sc_mididevs = malloc(sizeof(*sc->sc_mididevs)*nmidi,
1.13      tsutsui  1191:                                 M_USBDEV, M_WAITOK|M_ZERO);
1.1       tshiozak 1192:        if (!sc->sc_mididevs)
                   1193:                return USBD_NOMEM;
                   1194:
                   1195:        return USBD_NORMAL_COMPLETION;
                   1196: }
                   1197:
                   1198: static void
                   1199: free_all_mididevs(struct umidi_softc *sc)
                   1200: {
                   1201:        sc->sc_num_mididevs = 0;
                   1202:        if (sc->sc_mididevs)
                   1203:                free(sc->sc_mididevs, M_USBDEV);
                   1204: }
                   1205:
                   1206: static usbd_status
                   1207: attach_all_mididevs(struct umidi_softc *sc)
                   1208: {
                   1209:        usbd_status err;
                   1210:        int i;
                   1211:
                   1212:        if (sc->sc_mididevs)
                   1213:                for (i=0; i<sc->sc_num_mididevs; i++) {
                   1214:                        err = attach_mididev(sc, &sc->sc_mididevs[i]);
                   1215:                        if (err!=USBD_NORMAL_COMPLETION)
                   1216:                                return err;
                   1217:                }
                   1218:
                   1219:        return USBD_NORMAL_COMPLETION;
                   1220: }
                   1221:
                   1222: static usbd_status
                   1223: detach_all_mididevs(struct umidi_softc *sc, int flags)
                   1224: {
                   1225:        usbd_status err;
                   1226:        int i;
                   1227:
                   1228:        if (sc->sc_mididevs)
                   1229:                for (i=0; i<sc->sc_num_mididevs; i++) {
                   1230:                        err = detach_mididev(&sc->sc_mididevs[i], flags);
                   1231:                        if (err!=USBD_NORMAL_COMPLETION)
                   1232:                                return err;
                   1233:                }
                   1234:
                   1235:        return USBD_NORMAL_COMPLETION;
                   1236: }
                   1237:
                   1238: static usbd_status
                   1239: deactivate_all_mididevs(struct umidi_softc *sc)
                   1240: {
                   1241:        usbd_status err;
                   1242:        int i;
                   1243:
                   1244:        if (sc->sc_mididevs)
                   1245:                for (i=0; i<sc->sc_num_mididevs; i++) {
                   1246:                        err = deactivate_mididev(&sc->sc_mididevs[i]);
                   1247:                        if (err!=USBD_NORMAL_COMPLETION)
                   1248:                                return err;
                   1249:                }
                   1250:
                   1251:        return USBD_NORMAL_COMPLETION;
                   1252: }
                   1253:
1.23.2.2  yamt     1254: /*
                   1255:  * TODO: the 0-based cable numbers will often not match the labeling of the
                   1256:  * equipment. Ideally:
                   1257:  *  For class-compliant devices: get the iJack string from the jack descriptor.
                   1258:  *  Otherwise:
                   1259:  *  - support a DISPLAY_BASE_CN quirk (add the value to each internal cable
                   1260:  *    number for display)
                   1261:  *  - support an array quirk explictly giving a char * for each jack.
                   1262:  * For now, you get 0-based cable numbers. If there are multiple endpoints and
                   1263:  * the CNs are not globally unique, each is shown with its associated endpoint
                   1264:  * address in hex also. That should not be necessary when using iJack values
                   1265:  * or a quirk array.
                   1266:  */
                   1267: static char *
                   1268: describe_mididev(struct umidi_mididev *md)
                   1269: {
                   1270:        char in_label[16];
                   1271:        char out_label[16];
                   1272:        char *unit_label;
                   1273:        char *final_label;
                   1274:        struct umidi_softc *sc;
                   1275:        int show_ep_in;
                   1276:        int show_ep_out;
                   1277:        size_t len;
                   1278:
                   1279:        sc = md->sc;
                   1280:        show_ep_in  = sc-> sc_in_num_endpoints > 1 && !sc->cblnums_global;
                   1281:        show_ep_out = sc->sc_out_num_endpoints > 1 && !sc->cblnums_global;
                   1282:
                   1283:        if ( NULL != md->in_jack )
                   1284:                snprintf(in_label, sizeof in_label,
                   1285:                    show_ep_in ? "<%d(%x) " : "<%d ",
                   1286:                    md->in_jack->cable_number,
                   1287:                    md->in_jack->endpoint->addr);
                   1288:        else
                   1289:                in_label[0] = '\0';
                   1290:
                   1291:        if ( NULL != md->out_jack )
                   1292:                snprintf(out_label, sizeof out_label,
                   1293:                    show_ep_out ? ">%d(%x) " : ">%d ",
                   1294:                    md->out_jack->cable_number,
                   1295:                    md->out_jack->endpoint->addr);
                   1296:        else
                   1297:                in_label[0] = '\0';
                   1298:
                   1299:        unit_label = USBDEVNAME(sc->sc_dev);
                   1300:
                   1301:        len = strlen(in_label) + strlen(out_label) + strlen(unit_label) + 4;
                   1302:
                   1303:        final_label = malloc(len, M_USBDEV, M_WAITOK);
                   1304:
                   1305:        snprintf(final_label, len, "%s%son %s",
                   1306:            in_label, out_label, unit_label);
                   1307:
                   1308:        return final_label;
                   1309: }
                   1310:
1.1       tshiozak 1311: #ifdef UMIDI_DEBUG
                   1312: static void
                   1313: dump_sc(struct umidi_softc *sc)
                   1314: {
                   1315:        int i;
                   1316:
                   1317:        DPRINTFN(10, ("%s: dump_sc\n", USBDEVNAME(sc->sc_dev)));
                   1318:        for (i=0; i<sc->sc_out_num_endpoints; i++) {
                   1319:                DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i]));
                   1320:                dump_ep(&sc->sc_out_ep[i]);
                   1321:        }
                   1322:        for (i=0; i<sc->sc_in_num_endpoints; i++) {
                   1323:                DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i]));
                   1324:                dump_ep(&sc->sc_in_ep[i]);
                   1325:        }
                   1326: }
                   1327:
                   1328: static void
                   1329: dump_ep(struct umidi_endpoint *ep)
                   1330: {
                   1331:        int i;
1.23.2.2  yamt     1332:        for (i=0; i<UMIDI_MAX_EPJACKS; i++) {
                   1333:                if (NULL==ep->jacks[i])
                   1334:                        continue;
                   1335:                DPRINTFN(10, ("\t\tjack[%d]:%p:\n", i, ep->jacks[i]));
1.1       tshiozak 1336:                dump_jack(ep->jacks[i]);
                   1337:        }
                   1338: }
                   1339: static void
                   1340: dump_jack(struct umidi_jack *jack)
                   1341: {
1.15      tshiozak 1342:        DPRINTFN(10, ("\t\t\tep=%p\n",
                   1343:                      jack->endpoint));
1.1       tshiozak 1344: }
                   1345:
                   1346: #endif /* UMIDI_DEBUG */
                   1347:
                   1348:
                   1349:
                   1350: /*
                   1351:  * MUX MIDI PACKET
                   1352:  */
                   1353:
1.5       jdolecek 1354: static const int packet_length[16] = {
1.1       tshiozak 1355:        /*0*/   -1,
                   1356:        /*1*/   -1,
                   1357:        /*2*/   2,
                   1358:        /*3*/   3,
                   1359:        /*4*/   3,
                   1360:        /*5*/   1,
                   1361:        /*6*/   2,
                   1362:        /*7*/   3,
                   1363:        /*8*/   3,
                   1364:        /*9*/   3,
                   1365:        /*A*/   3,
                   1366:        /*B*/   3,
                   1367:        /*C*/   2,
                   1368:        /*D*/   2,
                   1369:        /*E*/   3,
                   1370:        /*F*/   1,
                   1371: };
                   1372:
                   1373: #define        GET_CN(p)               (((unsigned char)(p)>>4)&0x0F)
                   1374: #define GET_CIN(p)             ((unsigned char)(p)&0x0F)
                   1375: #define MIX_CN_CIN(cn, cin) \
                   1376:        ((unsigned char)((((unsigned char)(cn)&0x0F)<<4)| \
1.3       tshiozak 1377:                          ((unsigned char)(cin)&0x0F)))
1.1       tshiozak 1378:
                   1379: static usbd_status
                   1380: start_input_transfer(struct umidi_endpoint *ep)
                   1381: {
                   1382:        usbd_setup_xfer(ep->xfer, ep->pipe,
                   1383:                        (usbd_private_handle)ep,
1.23.2.2  yamt     1384:                        ep->buffer, ep->buffer_size,
                   1385:                        USBD_SHORT_XFER_OK | USBD_NO_COPY,
                   1386:                         USBD_NO_TIMEOUT, in_intr);
1.1       tshiozak 1387:        return usbd_transfer(ep->xfer);
                   1388: }
                   1389:
                   1390: static usbd_status
                   1391: start_output_transfer(struct umidi_endpoint *ep)
                   1392: {
1.23.2.2  yamt     1393:        usbd_status rv;
                   1394:        u_int32_t length;
                   1395:        int i;
                   1396:
                   1397:        length = (ep->next_slot - ep->buffer) * sizeof *ep->buffer;
                   1398:        DPRINTFN(200,("umidi out transfer: start %p end %p length %u\n",
                   1399:            ep->buffer, ep->next_slot, length));
1.1       tshiozak 1400:        usbd_setup_xfer(ep->xfer, ep->pipe,
                   1401:                        (usbd_private_handle)ep,
1.23.2.2  yamt     1402:                        ep->buffer, length,
1.11      augustss 1403:                        USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr);
1.23.2.2  yamt     1404:        rv = usbd_transfer(ep->xfer);
                   1405:
                   1406:        /*
                   1407:         * Once the transfer is scheduled, no more adding to partial
                   1408:         * packets within it.
                   1409:         */
                   1410:        if (UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE)) {
                   1411:                for (i=0; i<UMIDI_MAX_EPJACKS; ++i)
                   1412:                        if (NULL != ep->jacks[i])
                   1413:                                ep->jacks[i]->midiman_ppkt = NULL;
                   1414:        }
                   1415:
                   1416:        return rv;
1.1       tshiozak 1417: }
                   1418:
1.4       tshiozak 1419: #ifdef UMIDI_DEBUG
                   1420: #define DPR_PACKET(dir, sc, p)                                         \
1.23.2.2  yamt     1421: if ((unsigned char)(p)[1]!=0xFE)                               \
1.4       tshiozak 1422:        DPRINTFN(500,                                                   \
                   1423:                 ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n",  \
                   1424:                  USBDEVNAME(sc->sc_dev),                               \
1.23.2.2  yamt     1425:                  (unsigned char)(p)[0],                        \
                   1426:                  (unsigned char)(p)[1],                        \
                   1427:                  (unsigned char)(p)[2],                        \
                   1428:                  (unsigned char)(p)[3]));
1.4       tshiozak 1429: #else
                   1430: #define DPR_PACKET(dir, sc, p)
                   1431: #endif
                   1432:
1.23.2.2  yamt     1433: /*
                   1434:  * A 4-byte Midiman packet superficially resembles a 4-byte USB MIDI packet
                   1435:  * with the cable number and length in the last byte instead of the first,
                   1436:  * but there the resemblance ends. Where a USB MIDI packet is a semantic
                   1437:  * unit, a Midiman packet is just a wrapper for 1 to 3 bytes of raw MIDI
                   1438:  * with a cable nybble and a length nybble (which, unlike the CIN of a
                   1439:  * real USB MIDI packet, has no semantics at all besides the length).
                   1440:  * A packet received from a Midiman may contain part of a MIDI message,
                   1441:  * more than one MIDI message, or parts of more than one MIDI message. A
                   1442:  * three-byte MIDI message may arrive in three packets of data length 1, and
                   1443:  * running status may be used. Happily, the midi(4) driver above us will put
                   1444:  * it all back together, so the only cost is in USB bandwidth. The device
                   1445:  * has an easier time with what it receives from us: we'll pack messages in
                   1446:  * and across packets, but filling the packets whenever possible and,
                   1447:  * as midi(4) hands us a complete message at a time, we'll never send one
                   1448:  * in a dribble of short packets.
                   1449:  */
                   1450:
1.4       tshiozak 1451: static int
1.23.2.2  yamt     1452: out_jack_output(struct umidi_jack *out_jack, u_char *src, int len, int cin)
1.4       tshiozak 1453: {
                   1454:        struct umidi_endpoint *ep = out_jack->endpoint;
                   1455:        struct umidi_softc *sc = ep->sc;
1.23.2.2  yamt     1456:        unsigned char *packet;
1.4       tshiozak 1457:        int s;
1.23.2.2  yamt     1458:        int plen;
                   1459:        int poff;
1.4       tshiozak 1460:
                   1461:        if (sc->sc_dying)
                   1462:                return EIO;
                   1463:
1.23.2.2  yamt     1464:        if (!out_jack->opened)
                   1465:                return ENODEV; /* XXX as it was, is this the right errno? */
1.4       tshiozak 1466:
1.23.2.2  yamt     1467: #ifdef UMIDI_DEBUG
                   1468:        if ( umididebug >= 100 )
                   1469:                microtime(&umidi_tv);
                   1470: #endif
                   1471:        DPRINTFN(100, ("umidi out: %lu.%06lus ep=%p cn=%d len=%d cin=%#x\n",
                   1472:            umidi_tv.tv_sec%100, umidi_tv.tv_usec,
                   1473:            ep, out_jack->cable_number, len, cin));
                   1474:
                   1475:        s = splusb();
                   1476:        packet = *ep->next_slot++;
                   1477:        KASSERT(ep->buffer_size >=
                   1478:            (ep->next_slot - ep->buffer) * sizeof *ep->buffer);
                   1479:        memset(packet, 0, UMIDI_PACKET_SIZE);
                   1480:        if (UMQ_ISTYPE(sc, UMQ_TYPE_MIDIMAN_GARBLE)) {
                   1481:                if (NULL != out_jack->midiman_ppkt) { /* fill out a prev pkt */
                   1482:                        poff = 0x0f & (out_jack->midiman_ppkt[3]);
                   1483:                        plen = 3 - poff;
                   1484:                        if (plen > len)
                   1485:                                plen = len;
                   1486:                        memcpy(out_jack->midiman_ppkt+poff, src, plen);
                   1487:                        src += plen;
                   1488:                        len -= plen;
                   1489:                        plen += poff;
                   1490:                        out_jack->midiman_ppkt[3] =
                   1491:                            MIX_CN_CIN(out_jack->cable_number, plen);
                   1492:                        DPR_PACKET(out+, sc, out_jack->midiman_ppkt);
                   1493:                        if (3 == plen)
                   1494:                                out_jack->midiman_ppkt = NULL; /* no more */
                   1495:                }
                   1496:                if (0 == len)
                   1497:                        ep->next_slot--; /* won't be needed, nevermind */
                   1498:                else {
                   1499:                        memcpy(packet, src, len);
                   1500:                        packet[3] = MIX_CN_CIN(out_jack->cable_number, len);
                   1501:                        DPR_PACKET(out, sc, packet);
                   1502:                        if (len < 3)
                   1503:                                out_jack->midiman_ppkt = packet;
                   1504:                }
                   1505:        } else { /* the nice simple USB class-compliant case */
                   1506:                packet[0] = MIX_CN_CIN(out_jack->cable_number, cin);
                   1507:                memcpy(packet+1, src, len);
                   1508:                DPR_PACKET(out, sc, packet);
                   1509:        }
                   1510:        ep->next_schedule |= 1<<(out_jack->cable_number);
                   1511:        ++ ep->num_scheduled;
                   1512:        if ( !ep->armed  &&  !ep->soliciting ) {
                   1513:                /*
                   1514:                 * It would be bad to call out_solicit directly here (the
                   1515:                 * caller need not be reentrant) but a soft interrupt allows
                   1516:                 * solicit to run immediately the caller exits its critical
                   1517:                 * section, and if the caller has more to write we can get it
                   1518:                 * before starting the USB transfer, and send a longer one.
                   1519:                 */
                   1520:                ep->soliciting = 1;
1.23.2.4! yamt     1521:                softint_schedule(ep->solicit_cookie);
1.23.2.2  yamt     1522:        }
                   1523:        splx(s);
                   1524:
                   1525:        return 0;
1.4       tshiozak 1526: }
                   1527:
1.1       tshiozak 1528: static void
1.23.2.2  yamt     1529: in_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
                   1530:     usbd_status status)
1.1       tshiozak 1531: {
1.4       tshiozak 1532:        int cn, len, i;
1.1       tshiozak 1533:        struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
1.4       tshiozak 1534:        struct umidi_jack *jack;
1.23.2.2  yamt     1535:        unsigned char *packet;
                   1536:        umidi_packet_bufp slot;
                   1537:        umidi_packet_bufp end;
                   1538:        unsigned char *data;
                   1539:        u_int32_t count;
1.1       tshiozak 1540:
1.3       tshiozak 1541:        if (ep->sc->sc_dying || !ep->num_open)
1.1       tshiozak 1542:                return;
                   1543:
1.23.2.2  yamt     1544:        usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
                   1545:         if ( 0 == count % UMIDI_PACKET_SIZE ) {
                   1546:                DPRINTFN(200,("%s: input endpoint %p transfer length %u\n",
                   1547:                             USBDEVNAME(ep->sc->sc_dev), ep, count));
                   1548:         } else {
                   1549:                 DPRINTF(("%s: input endpoint %p odd transfer length %u\n",
                   1550:                         USBDEVNAME(ep->sc->sc_dev), ep, count));
                   1551:         }
                   1552:
                   1553:        slot = ep->buffer;
                   1554:        end = slot + count / sizeof *slot;
                   1555:
                   1556:        for ( packet = *slot; slot < end; packet = *++slot ) {
                   1557:
                   1558:                if ( UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE) ) {
                   1559:                        cn = (0xf0&(packet[3]))>>4;
                   1560:                        len = 0x0f&(packet[3]);
                   1561:                        data = packet;
                   1562:                } else {
                   1563:                        cn = GET_CN(packet[0]);
                   1564:                        len = packet_length[GET_CIN(packet[0])];
                   1565:                        data = packet + 1;
                   1566:                }
                   1567:                /* 0 <= cn <= 15 by inspection of above code */
                   1568:                if (!(jack = ep->jacks[cn]) || cn != jack->cable_number) {
                   1569:                        DPRINTF(("%s: stray input endpoint %p cable %d len %d: "
                   1570:                                 "%02X %02X %02X (try CN_SEQ quirk?)\n",
                   1571:                                 USBDEVNAME(ep->sc->sc_dev), ep, cn, len,
                   1572:                                 (unsigned)data[0],
                   1573:                                 (unsigned)data[1],
                   1574:                                 (unsigned)data[2]));
                   1575:                        return;
                   1576:                }
                   1577:
                   1578:                if (!jack->binded || !jack->opened)
                   1579:                        continue;
                   1580:
                   1581:                DPRINTFN(500,("%s: input endpoint %p cable %d len %d: "
                   1582:                             "%02X %02X %02X\n",
                   1583:                             USBDEVNAME(ep->sc->sc_dev), ep, cn, len,
                   1584:                             (unsigned)data[0],
                   1585:                             (unsigned)data[1],
                   1586:                             (unsigned)data[2]));
                   1587:
                   1588:                if (jack->u.in.intr) {
                   1589:                        for (i=0; i<len; i++) {
                   1590:                                (*jack->u.in.intr)(jack->arg, data[i]);
                   1591:                        }
1.4       tshiozak 1592:                }
1.23.2.2  yamt     1593:
1.4       tshiozak 1594:        }
1.1       tshiozak 1595:
                   1596:        (void)start_input_transfer(ep);
                   1597: }
                   1598:
                   1599: static void
1.23.2.2  yamt     1600: out_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
                   1601:     usbd_status status)
1.1       tshiozak 1602: {
                   1603:        struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
                   1604:        struct umidi_softc *sc = ep->sc;
1.23.2.2  yamt     1605:        u_int32_t count;
1.1       tshiozak 1606:
1.23.2.2  yamt     1607:        if (sc->sc_dying)
1.1       tshiozak 1608:                return;
                   1609:
1.23.2.2  yamt     1610: #ifdef UMIDI_DEBUG
                   1611:        if ( umididebug >= 200 )
                   1612:                microtime(&umidi_tv);
                   1613: #endif
                   1614:        usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
                   1615:         if ( 0 == count % UMIDI_PACKET_SIZE ) {
                   1616:                DPRINTFN(200,("%s: %lu.%06lus out ep %p xfer length %u\n",
                   1617:                             USBDEVNAME(ep->sc->sc_dev),
                   1618:                             umidi_tv.tv_sec%100, umidi_tv.tv_usec, ep, count));
                   1619:         } else {
                   1620:                 DPRINTF(("%s: output endpoint %p odd transfer length %u\n",
                   1621:                         USBDEVNAME(ep->sc->sc_dev), ep, count));
                   1622:         }
                   1623:        count /= UMIDI_PACKET_SIZE;
                   1624:
                   1625:        /*
                   1626:         * If while the transfer was pending we buffered any new messages,
                   1627:         * move them to the start of the buffer.
                   1628:         */
                   1629:        ep->next_slot -= count;
                   1630:        if ( ep->buffer < ep->next_slot ) {
                   1631:                memcpy(ep->buffer, ep->buffer + count,
                   1632:                       (char *)ep->next_slot - (char *)ep->buffer);
                   1633:        }
                   1634:        wakeup(ep);
                   1635:        /*
                   1636:         * Do not want anyone else to see armed <- 0 before soliciting <- 1.
                   1637:         * Running at splusb so the following should happen to be safe.
                   1638:         */
                   1639:        ep->armed = 0;
                   1640:        if ( !ep->soliciting ) {
                   1641:                ep->soliciting = 1;
                   1642:                out_solicit(ep);
1.1       tshiozak 1643:        }
                   1644: }
                   1645:
1.23.2.2  yamt     1646: /*
                   1647:  * A jack on which we have received a packet must be called back on its
                   1648:  * out.intr handler before it will send us another; it is considered
                   1649:  * 'scheduled'. It is nice and predictable - as long as it is scheduled,
                   1650:  * we need no extra buffer space for it.
                   1651:  *
                   1652:  * In contrast, a jack that is open but not scheduled may supply us a packet
                   1653:  * at any time, driven by the top half, and we must be able to accept it, no
                   1654:  * excuses. So we must ensure that at any point in time there are at least
                   1655:  * (num_open - num_scheduled) slots free.
                   1656:  *
                   1657:  * As long as there are more slots free than that minimum, we can loop calling
                   1658:  * scheduled jacks back on their "interrupt" handlers, soliciting more
                   1659:  * packets, starting the USB transfer only when the buffer space is down to
                   1660:  * the minimum or no jack has any more to send.
                   1661:  */
1.1       tshiozak 1662: static void
1.23.2.2  yamt     1663: out_solicit(void *arg)
1.1       tshiozak 1664: {
1.23.2.2  yamt     1665:        struct umidi_endpoint *ep = arg;
                   1666:        int s;
                   1667:        umidi_packet_bufp end;
                   1668:        u_int16_t which;
                   1669:        struct umidi_jack *jack;
                   1670:
                   1671:        end = ep->buffer + ep->buffer_size / sizeof *ep->buffer;
                   1672:
                   1673:        for ( ;; ) {
                   1674:                s = splusb();
                   1675:                if ( end - ep->next_slot <= ep->num_open - ep->num_scheduled )
                   1676:                        break; /* at splusb */
                   1677:                if ( ep->this_schedule == 0 ) {
                   1678:                        if ( ep->next_schedule == 0 )
                   1679:                                break; /* at splusb */
                   1680:                        ep->this_schedule = ep->next_schedule;
                   1681:                        ep->next_schedule = 0;
                   1682:                }
                   1683:                /*
                   1684:                 * At least one jack is scheduled. Find and mask off the least
                   1685:                 * set bit in this_schedule and decrement num_scheduled.
                   1686:                 * Convert mask to bit index to find the corresponding jack,
                   1687:                 * and call its intr handler. If it has a message, it will call
                   1688:                 * back one of the output methods, which will set its bit in
                   1689:                 * next_schedule (not copied into this_schedule until the
                   1690:                 * latter is empty). In this way we round-robin the jacks that
                   1691:                 * have messages to send, until the buffer is as full as we
                   1692:                 * dare, and then start a transfer.
                   1693:                 */
                   1694:                which = ep->this_schedule;
                   1695:                which &= (~which)+1; /* now mask of least set bit */
                   1696:                ep->this_schedule &= ~which;
                   1697:                -- ep->num_scheduled;
                   1698:                splx(s);
1.1       tshiozak 1699:
1.23.2.2  yamt     1700:                -- which; /* now 1s below mask - count 1s to get index */
                   1701:                which -= ((which >> 1) & 0x5555);/* SWAR credit aggregate.org */
                   1702:                which = (((which >> 2) & 0x3333) + (which & 0x3333));
                   1703:                which = (((which >> 4) + which) & 0x0f0f);
                   1704:                which +=  (which >> 8);
                   1705:                which &= 0x1f; /* the bit index a/k/a jack number */
                   1706:
                   1707:                jack = ep->jacks[which];
                   1708:                if (jack->u.out.intr)
                   1709:                        (*jack->u.out.intr)(jack->arg);
1.1       tshiozak 1710:        }
1.23.2.2  yamt     1711:        /* splusb at loop exit */
                   1712:        if ( !ep->armed  &&  ep->next_slot > ep->buffer )
                   1713:                ep->armed = (USBD_IN_PROGRESS == start_output_transfer(ep));
                   1714:        ep->soliciting = 0;
                   1715:        splx(s);
1.1       tshiozak 1716: }

CVSweb <webmaster@jp.NetBSD.org>