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

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

CVSweb <webmaster@jp.NetBSD.org>