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

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

CVSweb <webmaster@jp.NetBSD.org>