LCOV - code coverage report
Current view: top level - dev/usb - umidi.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 705 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13