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>