Annotation of src/sys/dev/usb/umidi.c, Revision 1.25.2.7
1.25.2.5 chap 1: /* $NetBSD: umidi.c,v 1.25.2.4 2006/05/20 03:05:05 chap 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.17 keihan 7: * by Takuya SHIOZAKI (tshiozak@NetBSD.org).
1.1 tshiozak 8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by the NetBSD
20: * Foundation, Inc. and its contributors.
21: * 4. Neither the name of The NetBSD Foundation nor the names of its
22: * contributors may be used to endorse or promote products derived
23: * from this software without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35: * POSSIBILITY OF SUCH DAMAGE.
36: */
1.10 lukem 37:
38: #include <sys/cdefs.h>
1.25.2.5 chap 39: __KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.25.2.4 2006/05/20 03:05:05 chap Exp $");
1.1 tshiozak 40:
41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/kernel.h>
44: #include <sys/malloc.h>
45: #include <sys/device.h>
46: #include <sys/ioctl.h>
47: #include <sys/conf.h>
48: #include <sys/file.h>
49: #include <sys/select.h>
50: #include <sys/proc.h>
51: #include <sys/vnode.h>
52: #include <sys/poll.h>
53: #include <sys/lock.h>
54:
55: #include <dev/usb/usb.h>
56: #include <dev/usb/usbdi.h>
57: #include <dev/usb/usbdi_util.h>
58:
59: #include <dev/usb/usbdevs.h>
60: #include <dev/usb/uaudioreg.h>
61: #include <dev/usb/umidireg.h>
62: #include <dev/usb/umidivar.h>
63: #include <dev/usb/umidi_quirks.h>
64:
65: #include <dev/midi_if.h>
66:
67: #ifdef UMIDI_DEBUG
68: #define DPRINTF(x) if (umididebug) printf x
69: #define DPRINTFN(n,x) if (umididebug >= (n)) printf x
70: int umididebug = 0;
71: #else
72: #define DPRINTF(x)
73: #define DPRINTFN(n,x)
74: #endif
75:
76:
77: static int umidi_open(void *, int,
78: void (*)(void *, int), void (*)(void *), void *);
79: static void umidi_close(void *);
1.25.2.5 chap 80: static int umidi_channelmsg(void *, int, int, u_char *, int);
81: static int umidi_commonmsg(void *, int, u_char *, int);
82: static int umidi_sysex(void *, u_char *, int);
83: static int umidi_rtmsg(void *, int);
1.1 tshiozak 84: static void umidi_getinfo(void *, struct midi_info *);
85:
1.3 tshiozak 86: static usbd_status alloc_pipe(struct umidi_endpoint *);
87: static void free_pipe(struct umidi_endpoint *);
1.1 tshiozak 88:
89: static usbd_status alloc_all_endpoints(struct umidi_softc *);
90: static void free_all_endpoints(struct umidi_softc *);
91:
92: static usbd_status alloc_all_jacks(struct umidi_softc *);
93: static void free_all_jacks(struct umidi_softc *);
94: static usbd_status bind_jacks_to_mididev(struct umidi_softc *,
95: struct umidi_jack *,
96: struct umidi_jack *,
97: struct umidi_mididev *);
1.4 tshiozak 98: static void unbind_jacks_from_mididev(struct umidi_mididev *);
99: static void unbind_all_jacks(struct umidi_softc *);
1.1 tshiozak 100: static usbd_status assign_all_jacks_automatically(struct umidi_softc *);
1.4 tshiozak 101: static usbd_status open_out_jack(struct umidi_jack *, void *,
102: void (*)(void *));
103: static usbd_status open_in_jack(struct umidi_jack *, void *,
104: void (*)(void *, int));
105: static void close_out_jack(struct umidi_jack *);
106: static void close_in_jack(struct umidi_jack *);
1.1 tshiozak 107:
108: static usbd_status attach_mididev(struct umidi_softc *,
109: struct umidi_mididev *);
110: static usbd_status detach_mididev(struct umidi_mididev *, int);
111: static usbd_status deactivate_mididev(struct umidi_mididev *);
112: static usbd_status alloc_all_mididevs(struct umidi_softc *, int);
113: static void free_all_mididevs(struct umidi_softc *);
114: static usbd_status attach_all_mididevs(struct umidi_softc *);
115: static usbd_status detach_all_mididevs(struct umidi_softc *, int);
116: static usbd_status deactivate_all_mididevs(struct umidi_softc *);
117:
118: #ifdef UMIDI_DEBUG
119: static void dump_sc(struct umidi_softc *);
120: static void dump_ep(struct umidi_endpoint *);
121: static void dump_jack(struct umidi_jack *);
122: #endif
123:
124: static usbd_status start_input_transfer(struct umidi_endpoint *);
125: static usbd_status start_output_transfer(struct umidi_endpoint *);
1.25.2.5 chap 126: static int out_jack_output(struct umidi_jack *, u_char *, int, int);
1.1 tshiozak 127: static void in_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
128: static void out_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
129:
130:
1.25.2.1 chap 131: struct midi_hw_if umidi_hw_if = {
1.1 tshiozak 132: umidi_open,
133: umidi_close,
1.25.2.5 chap 134: umidi_rtmsg,
1.1 tshiozak 135: umidi_getinfo,
136: 0, /* ioctl */
137: };
138:
1.25.2.5 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:
1.1 tshiozak 145: USB_DECLARE_DRIVER(umidi);
146:
147: USB_MATCH(umidi)
148: {
149: USB_MATCH_START(umidi, uaa);
150: usb_interface_descriptor_t *id;
151:
152: DPRINTFN(1,("umidi_match\n"));
153:
154: if (uaa->iface == NULL)
155: return UMATCH_NONE;
156:
1.3 tshiozak 157: if (umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno))
158: return UMATCH_IFACECLASS_IFACESUBCLASS;
1.1 tshiozak 159:
160: id = usbd_get_interface_descriptor(uaa->iface);
1.16 augustss 161: if (id!=NULL &&
1.1 tshiozak 162: id->bInterfaceClass==UICLASS_AUDIO &&
1.3 tshiozak 163: id->bInterfaceSubClass==UISUBCLASS_MIDISTREAM)
164: return UMATCH_IFACECLASS_IFACESUBCLASS;
1.1 tshiozak 165:
1.3 tshiozak 166: return UMATCH_NONE;
1.1 tshiozak 167: }
168:
169: USB_ATTACH(umidi)
170: {
171: usbd_status err;
172: USB_ATTACH_START(umidi, sc, uaa);
1.25.2.1 chap 173: char devinfo[1024];
1.1 tshiozak 174:
175: DPRINTFN(1,("umidi_attach\n"));
176:
1.25.2.1 chap 177: usbd_devinfo(uaa->device, 0, devinfo);
178: printf("\n%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
1.1 tshiozak 179:
180: sc->sc_iface = uaa->iface;
181: sc->sc_udev = uaa->device;
182:
183: sc->sc_quirk =
184: umidi_search_quirk(uaa->vendor, uaa->product, uaa->ifaceno);
185: printf("%s: ", USBDEVNAME(sc->sc_dev));
186: umidi_print_quirk(sc->sc_quirk);
187:
188:
189: err = alloc_all_endpoints(sc);
190: if (err!=USBD_NORMAL_COMPLETION) {
191: printf("%s: alloc_all_endpoints failed. (err=%d)\n",
192: USBDEVNAME(sc->sc_dev), err);
193: goto error;
194: }
195: err = alloc_all_jacks(sc);
196: if (err!=USBD_NORMAL_COMPLETION) {
197: free_all_endpoints(sc);
198: printf("%s: alloc_all_jacks failed. (err=%d)\n",
199: USBDEVNAME(sc->sc_dev), err);
200: goto error;
201: }
202: printf("%s: out=%d, in=%d\n",
203: USBDEVNAME(sc->sc_dev),
204: sc->sc_out_num_jacks, sc->sc_in_num_jacks);
205:
206: err = assign_all_jacks_automatically(sc);
207: if (err!=USBD_NORMAL_COMPLETION) {
208: unbind_all_jacks(sc);
209: free_all_jacks(sc);
210: free_all_endpoints(sc);
211: printf("%s: assign_all_jacks_automatically failed. (err=%d)\n",
212: USBDEVNAME(sc->sc_dev), err);
213: goto error;
214: }
215: err = attach_all_mididevs(sc);
216: if (err!=USBD_NORMAL_COMPLETION) {
217: free_all_jacks(sc);
218: free_all_endpoints(sc);
219: printf("%s: attach_all_mididevs failed. (err=%d)\n",
220: USBDEVNAME(sc->sc_dev), err);
221: }
222:
223: #ifdef UMIDI_DEBUG
224: dump_sc(sc);
225: #endif
226:
227: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH,
228: sc->sc_udev, USBDEV(sc->sc_dev));
1.16 augustss 229:
1.1 tshiozak 230: USB_ATTACH_SUCCESS_RETURN;
231: error:
232: printf("%s: disabled.\n", USBDEVNAME(sc->sc_dev));
233: sc->sc_dying = 1;
234: USB_ATTACH_ERROR_RETURN;
235: }
236:
237: int
238: umidi_activate(device_ptr_t self, enum devact act)
239: {
1.3 tshiozak 240: struct umidi_softc *sc = (struct umidi_softc *)self;
1.1 tshiozak 241:
242: switch (act) {
243: case DVACT_ACTIVATE:
244: DPRINTFN(1,("umidi_activate (activate)\n"));
245:
246: return EOPNOTSUPP;
247: break;
248: case DVACT_DEACTIVATE:
249: DPRINTFN(1,("umidi_activate (deactivate)\n"));
250: sc->sc_dying = 1;
251: deactivate_all_mididevs(sc);
252: break;
253: }
254: return 0;
255: }
256:
257: USB_DETACH(umidi)
258: {
1.3 tshiozak 259: USB_DETACH_START(umidi, sc);
1.1 tshiozak 260:
261: DPRINTFN(1,("umidi_detach\n"));
262:
263: sc->sc_dying = 1;
264: detach_all_mididevs(sc, flags);
265: free_all_mididevs(sc);
266: free_all_jacks(sc);
267: free_all_endpoints(sc);
268:
1.3 tshiozak 269: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
270: USBDEV(sc->sc_dev));
1.1 tshiozak 271:
272: return 0;
273: }
274:
275:
1.4 tshiozak 276: /*
277: * midi_if stuffs
278: */
1.1 tshiozak 279: int
280: umidi_open(void *addr,
281: int flags,
1.12 augustss 282: void (*iintr)(void *, int),
283: void (*ointr)(void *),
1.1 tshiozak 284: void *arg)
285: {
1.3 tshiozak 286: struct umidi_mididev *mididev = addr;
287: struct umidi_softc *sc = mididev->sc;
1.25.2.2 chap 288: usbd_status err;
1.1 tshiozak 289:
290: DPRINTF(("umidi_open: sc=%p\n", sc));
291:
292: if (!sc)
293: return ENXIO;
294: if (mididev->opened)
295: return EBUSY;
1.4 tshiozak 296: if (sc->sc_dying)
1.1 tshiozak 297: return EIO;
298:
1.4 tshiozak 299: mididev->opened = 1;
1.1 tshiozak 300: mididev->flags = flags;
1.25.2.2 chap 301: if ((mididev->flags & FWRITE) && mididev->out_jack) {
302: err = open_out_jack(mididev->out_jack, arg, ointr);
303: if ( err != USBD_NORMAL_COMPLETION )
304: goto bad;
305: }
1.3 tshiozak 306: if ((mididev->flags & FREAD) && mididev->in_jack) {
1.25.2.2 chap 307: err = open_in_jack(mididev->in_jack, arg, iintr);
308: if ( err != USBD_NORMAL_COMPLETION
309: && err != USBD_IN_PROGRESS )
310: goto bad;
1.3 tshiozak 311: }
1.1 tshiozak 312:
313: return 0;
1.25.2.2 chap 314: bad:
315: mididev->opened = 0;
316: DPRINTF(("umidi_open: usbd_status %d\n", err));
317: return USBD_IN_USE == err ? EBUSY : EIO;
1.1 tshiozak 318: }
319:
320: void
321: umidi_close(void *addr)
322: {
323: int s;
1.3 tshiozak 324: struct umidi_mididev *mididev = addr;
1.1 tshiozak 325:
326: s = splusb();
327: if ((mididev->flags & FWRITE) && mididev->out_jack)
1.4 tshiozak 328: close_out_jack(mididev->out_jack);
1.1 tshiozak 329: if ((mididev->flags & FREAD) && mididev->in_jack)
1.4 tshiozak 330: close_in_jack(mididev->in_jack);
1.1 tshiozak 331: mididev->opened = 0;
332: splx(s);
333: }
334:
335: int
1.25.2.5 chap 336: umidi_channelmsg(void *addr, int status, int channel, u_char *msg, int len)
337: {
338: struct umidi_mididev *mididev = addr;
339:
340: if (!mididev->out_jack || !mididev->opened)
341: return EIO;
342:
343: return out_jack_output(mididev->out_jack, msg, len, (status>>4)&0xf);
344: }
345:
346: int
347: umidi_commonmsg(void *addr, int status, u_char *msg, int len)
348: {
349: struct umidi_mididev *mididev = addr;
350: int cin;
351:
352: if (!mididev->out_jack || !mididev->opened)
353: return EIO;
354:
355: switch ( len ) {
356: case 1: cin = 5; break;
357: case 2: cin = 2; break;
358: case 3: cin = 3; break;
359: default: return EIO; /* or gcc warns of cin uninitialized */
360: }
361:
362: return out_jack_output(mididev->out_jack, msg, len, cin);
363: }
364:
365: int
366: umidi_sysex(void *addr, u_char *msg, int len)
1.1 tshiozak 367: {
1.3 tshiozak 368: struct umidi_mididev *mididev = addr;
1.25.2.5 chap 369: int cin;
1.1 tshiozak 370:
1.4 tshiozak 371: if (!mididev->out_jack || !mididev->opened)
1.1 tshiozak 372: return EIO;
373:
1.25.2.5 chap 374: switch ( len ) {
375: case 1: cin = 5; break;
376: case 2: cin = 6; break;
377: case 3: cin = (msg[2] == 0xf7) ? 7 : 4; break;
378: default: return EIO; /* or gcc warns of cin uninitialized */
379: }
380:
381: return out_jack_output(mididev->out_jack, msg, len, cin);
382: }
383:
384: int
385: umidi_rtmsg(void *addr, int d)
386: {
387: struct umidi_mididev *mididev = addr;
388: u_char msg = d;
389:
390: if (!mididev->out_jack || !mididev->opened)
391: return EIO;
392:
393: return out_jack_output(mididev->out_jack, &msg, 1, 0xf);
1.1 tshiozak 394: }
395:
396: void
397: umidi_getinfo(void *addr, struct midi_info *mi)
398: {
1.3 tshiozak 399: struct umidi_mididev *mididev = addr;
400: /* struct umidi_softc *sc = mididev->sc; */
1.1 tshiozak 401:
1.3 tshiozak 402: mi->name = "USB MIDI I/F"; /* XXX: model name */
403: mi->props = MIDI_PROP_OUT_INTR;
1.1 tshiozak 404: if (mididev->in_jack)
405: mi->props |= MIDI_PROP_CAN_INPUT;
1.25.2.5 chap 406: midi_register_hw_if_ext(&umidi_hw_if_ext);
1.1 tshiozak 407: }
408:
409:
1.4 tshiozak 410: /*
411: * each endpoint stuffs
412: */
1.1 tshiozak 413:
1.3 tshiozak 414: /* alloc/free pipe */
1.1 tshiozak 415: static usbd_status
1.3 tshiozak 416: alloc_pipe(struct umidi_endpoint *ep)
1.1 tshiozak 417: {
418: struct umidi_softc *sc = ep->sc;
419: usbd_status err;
1.25.2.4 chap 420: usb_endpoint_descriptor_t *epd;
421:
422: if ( UE_DIR_OUT == UE_GET_DIR(ep->addr) )
423: ep->buffer_size = UMIDI_PACKET_SIZE;
424: else { /* only use wMaxPacketSize on inputs (for now) */
425: epd = usbd_get_endpoint_descriptor(sc->sc_iface, ep->addr);
426: ep->buffer_size = UGETW(epd->wMaxPacketSize);
427: ep->buffer_size -= ep->buffer_size % UMIDI_PACKET_SIZE;
428: }
1.1 tshiozak 429:
1.25.2.4 chap 430: DPRINTF(("%s: alloc_pipe %p, buffer size %u\n",
431: USBDEVNAME(sc->sc_dev), ep, ep->buffer_size));
1.4 tshiozak 432: LIST_INIT(&ep->queue_head);
1.3 tshiozak 433: ep->xfer = usbd_alloc_xfer(sc->sc_udev);
1.11 augustss 434: if (ep->xfer == NULL) {
1.3 tshiozak 435: err = USBD_NOMEM;
436: goto quit;
437: }
1.25.2.4 chap 438: ep->buffer = usbd_alloc_buffer(ep->xfer, ep->buffer_size);
1.11 augustss 439: if (ep->buffer == NULL) {
1.3 tshiozak 440: usbd_free_xfer(ep->xfer);
441: err = USBD_NOMEM;
442: goto quit;
443: }
444: err = usbd_open_pipe(sc->sc_iface, ep->addr, 0, &ep->pipe);
445: if (err)
446: usbd_free_xfer(ep->xfer);
1.1 tshiozak 447: quit:
448: return err;
449: }
450:
451: static void
1.3 tshiozak 452: free_pipe(struct umidi_endpoint *ep)
1.1 tshiozak 453: {
1.3 tshiozak 454: DPRINTF(("%s: free_pipe %p\n", USBDEVNAME(ep->sc->sc_dev), ep));
455: usbd_abort_pipe(ep->pipe);
456: usbd_close_pipe(ep->pipe);
457: usbd_free_xfer(ep->xfer);
1.1 tshiozak 458: }
459:
460:
461: /* alloc/free the array of endpoint structures */
462:
463: static usbd_status alloc_all_endpoints_fixed_ep(struct umidi_softc *);
464: static usbd_status alloc_all_endpoints_yamaha(struct umidi_softc *);
465: static usbd_status alloc_all_endpoints_genuine(struct umidi_softc *);
466:
467: static usbd_status
468: alloc_all_endpoints(struct umidi_softc *sc)
469: {
1.3 tshiozak 470: usbd_status err;
471: struct umidi_endpoint *ep;
472: int i;
1.9 tshiozak 473:
1.3 tshiozak 474: if (UMQ_ISTYPE(sc, UMQ_TYPE_FIXED_EP)) {
475: err = alloc_all_endpoints_fixed_ep(sc);
476: } else if (UMQ_ISTYPE(sc, UMQ_TYPE_YAMAHA)) {
477: err = alloc_all_endpoints_yamaha(sc);
1.1 tshiozak 478: } else {
1.3 tshiozak 479: err = alloc_all_endpoints_genuine(sc);
1.1 tshiozak 480: }
1.3 tshiozak 481: if (err!=USBD_NORMAL_COMPLETION)
482: return err;
483:
484: ep = sc->sc_endpoints;
1.8 tshiozak 485: for (i=sc->sc_out_num_endpoints+sc->sc_in_num_endpoints; i>0; i--) {
1.3 tshiozak 486: err = alloc_pipe(ep++);
487: if (err!=USBD_NORMAL_COMPLETION) {
488: for (; ep!=sc->sc_endpoints; ep--)
489: free_pipe(ep-1);
490: free(sc->sc_endpoints, M_USBDEV);
491: sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
492: break;
493: }
494: }
495: return err;
1.1 tshiozak 496: }
497:
498: static void
499: free_all_endpoints(struct umidi_softc *sc)
500: {
1.3 tshiozak 501: int i;
1.8 tshiozak 502: for (i=0; i<sc->sc_in_num_endpoints+sc->sc_out_num_endpoints; i++)
1.3 tshiozak 503: free_pipe(&sc->sc_endpoints[i]);
1.14 kent 504: if (sc->sc_endpoints != NULL)
505: free(sc->sc_endpoints, M_USBDEV);
1.1 tshiozak 506: sc->sc_endpoints = sc->sc_out_ep = sc->sc_in_ep = NULL;
507: }
508:
509: static usbd_status
510: alloc_all_endpoints_fixed_ep(struct umidi_softc *sc)
511: {
1.3 tshiozak 512: usbd_status err;
1.1 tshiozak 513: struct umq_fixed_ep_desc *fp;
1.3 tshiozak 514: struct umidi_endpoint *ep;
1.1 tshiozak 515: usb_endpoint_descriptor_t *epd;
516: int i;
517:
518: fp = umidi_get_quirk_data_from_type(sc->sc_quirk,
519: UMQ_TYPE_FIXED_EP);
520: sc->sc_out_num_jacks = 0;
521: sc->sc_in_num_jacks = 0;
522: sc->sc_out_num_endpoints = fp->num_out_ep;
523: sc->sc_in_num_endpoints = fp->num_in_ep;
524: sc->sc_endpoints = malloc(sizeof(*sc->sc_out_ep)*
525: (sc->sc_out_num_endpoints+
526: sc->sc_in_num_endpoints),
527: M_USBDEV, M_WAITOK);
528: if (!sc->sc_endpoints) {
529: return USBD_NOMEM;
530: }
531: sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
532: sc->sc_in_ep =
533: sc->sc_in_num_endpoints ?
534: sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
1.3 tshiozak 535:
536: ep = &sc->sc_out_ep[0];
1.1 tshiozak 537: for (i=0; i<sc->sc_out_num_endpoints; i++) {
538: epd = usbd_interface2endpoint_descriptor(
539: sc->sc_iface,
540: fp->out_ep[i].ep);
541: if (!epd) {
542: printf("%s: cannot get endpoint descriptor(out:%d)\n",
543: USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
1.3 tshiozak 544: err = USBD_INVAL;
1.1 tshiozak 545: goto error;
546: }
547: if (UE_GET_XFERTYPE(epd->bmAttributes)!=UE_BULK ||
548: UE_GET_DIR(epd->bEndpointAddress)!=UE_DIR_OUT) {
549: printf("%s: illegal endpoint(out:%d)\n",
550: USBDEVNAME(sc->sc_dev), fp->out_ep[i].ep);
1.3 tshiozak 551: err = USBD_INVAL;
1.1 tshiozak 552: goto error;
553: }
1.3 tshiozak 554: ep->sc = sc;
555: ep->addr = epd->bEndpointAddress;
556: ep->num_jacks = fp->out_ep[i].num_jacks;
1.1 tshiozak 557: sc->sc_out_num_jacks += fp->out_ep[i].num_jacks;
1.3 tshiozak 558: ep->num_open = 0;
559: memset(ep->jacks, 0, sizeof(ep->jacks));
1.25.2.2 chap 560: /* other ep alloc subrs don't, and alloc_pipe does, anyway: */
561: /* LIST_INIT(&ep->queue_head); */
1.3 tshiozak 562: ep++;
1.1 tshiozak 563: }
1.3 tshiozak 564: ep = &sc->sc_in_ep[0];
1.1 tshiozak 565: for (i=0; i<sc->sc_in_num_endpoints; i++) {
566: epd = usbd_interface2endpoint_descriptor(
567: sc->sc_iface,
568: fp->in_ep[i].ep);
569: if (!epd) {
570: printf("%s: cannot get endpoint descriptor(in:%d)\n",
571: USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
1.3 tshiozak 572: err = USBD_INVAL;
1.1 tshiozak 573: goto error;
574: }
1.25.2.2 chap 575: /*
576: * MIDISPORT_2X4 inputs on an interrupt rather than a bulk
577: * endpoint. The existing input logic in this driver seems
578: * to work successfully if we just stop treating an interrupt
579: * endpoint as illegal (or the in_progress status we get on
580: * the initial transfer). It does not seem necessary to
581: * actually use the interrupt flavor of alloc_pipe or make
582: * other serious rearrangements of logic. I like that.
583: */
584: switch ( UE_GET_XFERTYPE(epd->bmAttributes) ) {
585: case UE_BULK:
586: case UE_INTERRUPT:
587: if ( UE_DIR_IN == UE_GET_DIR(epd->bEndpointAddress) )
588: break;
589: /*FALLTHROUGH*/
590: default:
1.1 tshiozak 591: printf("%s: illegal endpoint(in:%d)\n",
592: USBDEVNAME(sc->sc_dev), fp->in_ep[i].ep);
1.3 tshiozak 593: err = USBD_INVAL;
1.1 tshiozak 594: goto error;
595: }
1.25.2.2 chap 596:
1.3 tshiozak 597: ep->sc = sc;
598: ep->addr = epd->bEndpointAddress;
599: ep->num_jacks = fp->in_ep[i].num_jacks;
1.1 tshiozak 600: sc->sc_in_num_jacks += fp->in_ep[i].num_jacks;
1.3 tshiozak 601: ep->num_open = 0;
602: memset(ep->jacks, 0, sizeof(ep->jacks));
603: ep++;
1.1 tshiozak 604: }
605:
606: return USBD_NORMAL_COMPLETION;
607: error:
608: free(sc->sc_endpoints, M_USBDEV);
609: sc->sc_endpoints = NULL;
1.3 tshiozak 610: return err;
1.1 tshiozak 611: }
612:
613: static usbd_status
614: alloc_all_endpoints_yamaha(struct umidi_softc *sc)
615: {
616: /* This driver currently supports max 1in/1out bulk endpoints */
617: usb_descriptor_t *desc;
1.8 tshiozak 618: usb_endpoint_descriptor_t *epd;
619: int out_addr, in_addr, i;
620: int dir;
1.1 tshiozak 621: size_t remain, descsize;
622:
1.8 tshiozak 623: sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
624: out_addr = in_addr = 0;
625:
626: /* detect endpoints */
1.1 tshiozak 627: desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
1.8 tshiozak 628: for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) {
629: epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
630: if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) {
631: dir = UE_GET_DIR(epd->bEndpointAddress);
632: if (dir==UE_DIR_OUT && !out_addr)
633: out_addr = epd->bEndpointAddress;
634: else if (dir==UE_DIR_IN && !in_addr)
635: in_addr = epd->bEndpointAddress;
636: }
637: }
1.3 tshiozak 638: desc = NEXT_D(desc);
1.1 tshiozak 639:
1.8 tshiozak 640: /* count jacks */
641: if (!(desc->bDescriptorType==UDESC_CS_INTERFACE &&
642: desc->bDescriptorSubtype==UMIDI_MS_HEADER))
643: return USBD_INVAL;
644: remain = (size_t)UGETW(TO_CSIFD(desc)->wTotalLength) -
645: (size_t)desc->bLength;
646: desc = NEXT_D(desc);
1.1 tshiozak 647:
648: while (remain>=sizeof(usb_descriptor_t)) {
649: descsize = desc->bLength;
650: if (descsize>remain || descsize==0)
651: break;
652: if (desc->bDescriptorType==UDESC_CS_INTERFACE &&
653: remain>=UMIDI_JACK_DESCRIPTOR_SIZE) {
654: if (desc->bDescriptorSubtype==UMIDI_OUT_JACK)
655: sc->sc_out_num_jacks++;
656: else if (desc->bDescriptorSubtype==UMIDI_IN_JACK)
657: sc->sc_in_num_jacks++;
658: }
659: desc = NEXT_D(desc);
660: remain-=descsize;
661: }
662:
1.8 tshiozak 663: /* validate some parameters */
1.1 tshiozak 664: if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS)
665: sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS;
666: if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS)
667: sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS;
1.8 tshiozak 668: if (sc->sc_out_num_jacks && out_addr) {
1.1 tshiozak 669: sc->sc_out_num_endpoints = 1;
670: } else {
671: sc->sc_out_num_endpoints = 0;
672: sc->sc_out_num_jacks = 0;
673: }
1.8 tshiozak 674: if (sc->sc_in_num_jacks && in_addr) {
1.1 tshiozak 675: sc->sc_in_num_endpoints = 1;
676: } else {
677: sc->sc_in_num_endpoints = 0;
678: sc->sc_in_num_jacks = 0;
679: }
680: sc->sc_endpoints = malloc(sizeof(struct umidi_endpoint)*
681: (sc->sc_out_num_endpoints+
682: sc->sc_in_num_endpoints),
683: M_USBDEV, M_WAITOK);
684: if (!sc->sc_endpoints)
685: return USBD_NOMEM;
686: if (sc->sc_out_num_endpoints) {
687: sc->sc_out_ep = sc->sc_endpoints;
688: sc->sc_out_ep->sc = sc;
689: sc->sc_out_ep->addr = out_addr;
690: sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks;
691: sc->sc_out_ep->num_open = 0;
692: memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks));
693: } else
694: sc->sc_out_ep = NULL;
695:
696: if (sc->sc_in_num_endpoints) {
697: sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints;
698: sc->sc_in_ep->sc = sc;
699: sc->sc_in_ep->addr = in_addr;
700: sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks;
701: sc->sc_in_ep->num_open = 0;
702: memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks));
703: } else
704: sc->sc_in_ep = NULL;
705:
706: return USBD_NORMAL_COMPLETION;
707: }
708:
709: static usbd_status
710: alloc_all_endpoints_genuine(struct umidi_softc *sc)
711: {
1.20 gson 712: usb_interface_descriptor_t *interface_desc;
713: usb_config_descriptor_t *config_desc;
1.1 tshiozak 714: usb_descriptor_t *desc;
1.7 tshiozak 715: int num_ep;
1.1 tshiozak 716: size_t remain, descsize;
717: struct umidi_endpoint *p, *q, *lowest, *endep, tmpep;
718: int epaddr;
719:
1.20 gson 720: interface_desc = usbd_get_interface_descriptor(sc->sc_iface);
721: num_ep = interface_desc->bNumEndpoints;
722: sc->sc_endpoints = p = malloc(sizeof(struct umidi_endpoint) * num_ep,
1.1 tshiozak 723: M_USBDEV, M_WAITOK);
724: if (!p)
725: return USBD_NOMEM;
726:
727: sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
728: sc->sc_out_num_endpoints = sc->sc_in_num_endpoints = 0;
729: epaddr = -1;
730:
731: /* get the list of endpoints for midi stream */
1.20 gson 732: config_desc = usbd_get_config_descriptor(sc->sc_udev);
733: desc = (usb_descriptor_t *) config_desc;
734: remain = (size_t)UGETW(config_desc->wTotalLength);
1.1 tshiozak 735: while (remain>=sizeof(usb_descriptor_t)) {
736: descsize = desc->bLength;
737: if (descsize>remain || descsize==0)
738: break;
739: if (desc->bDescriptorType==UDESC_ENDPOINT &&
740: remain>=USB_ENDPOINT_DESCRIPTOR_SIZE &&
741: UE_GET_XFERTYPE(TO_EPD(desc)->bmAttributes) == UE_BULK) {
742: epaddr = TO_EPD(desc)->bEndpointAddress;
743: } else if (desc->bDescriptorType==UDESC_CS_ENDPOINT &&
744: remain>=UMIDI_CS_ENDPOINT_DESCRIPTOR_SIZE &&
745: epaddr!=-1) {
746: if (num_ep>0) {
1.9 tshiozak 747: num_ep--;
1.1 tshiozak 748: p->sc = sc;
749: p->addr = epaddr;
750: p->num_jacks = TO_CSEPD(desc)->bNumEmbMIDIJack;
751: if (UE_GET_DIR(epaddr)==UE_DIR_OUT) {
752: sc->sc_out_num_endpoints++;
753: sc->sc_out_num_jacks += p->num_jacks;
754: } else {
755: sc->sc_in_num_endpoints++;
756: sc->sc_in_num_jacks += p->num_jacks;
757: }
758: p++;
759: }
760: } else
761: epaddr = -1;
762: desc = NEXT_D(desc);
763: remain-=descsize;
764: }
765:
766: /* sort endpoints */
767: num_ep = sc->sc_out_num_endpoints + sc->sc_in_num_endpoints;
768: p = sc->sc_endpoints;
769: endep = p + num_ep;
770: while (p<endep) {
771: lowest = p;
772: for (q=p+1; q<endep; q++) {
773: if ((UE_GET_DIR(lowest->addr)==UE_DIR_IN &&
774: UE_GET_DIR(q->addr)==UE_DIR_OUT) ||
775: ((UE_GET_DIR(lowest->addr)==
776: UE_GET_DIR(q->addr)) &&
777: (UE_GET_ADDR(lowest->addr)>
778: UE_GET_ADDR(q->addr))))
779: lowest = q;
780: }
781: if (lowest != p) {
782: memcpy((void *)&tmpep, (void *)p, sizeof(tmpep));
783: memcpy((void *)p, (void *)lowest, sizeof(tmpep));
784: memcpy((void *)lowest, (void *)&tmpep, sizeof(tmpep));
785: }
1.7 tshiozak 786: p->num_open = 0;
787: p++;
1.1 tshiozak 788: }
1.16 augustss 789:
1.1 tshiozak 790: sc->sc_out_ep = sc->sc_out_num_endpoints ? sc->sc_endpoints : NULL;
791: sc->sc_in_ep =
792: sc->sc_in_num_endpoints ?
793: sc->sc_endpoints+sc->sc_out_num_endpoints : NULL;
794:
795: return USBD_NORMAL_COMPLETION;
796: }
797:
798:
1.4 tshiozak 799: /*
800: * jack stuffs
801: */
802:
1.1 tshiozak 803: static usbd_status
804: alloc_all_jacks(struct umidi_softc *sc)
805: {
806: int i, j;
807: struct umidi_endpoint *ep;
808: struct umidi_jack *jack, **rjack;
809:
810: /* allocate/initialize structures */
811: sc->sc_jacks =
812: malloc(sizeof(*sc->sc_out_jacks)*(sc->sc_in_num_jacks+
813: sc->sc_out_num_jacks),
814: M_USBDEV, M_WAITOK);
815: if (!sc->sc_jacks)
816: return USBD_NOMEM;
817: sc->sc_out_jacks =
818: sc->sc_out_num_jacks ? sc->sc_jacks : NULL;
819: sc->sc_in_jacks =
820: sc->sc_in_num_jacks ? sc->sc_jacks+sc->sc_out_num_jacks : NULL;
821:
822: jack = &sc->sc_out_jacks[0];
823: for (i=0; i<sc->sc_out_num_jacks; i++) {
1.4 tshiozak 824: jack->opened = 0;
825: jack->binded = 0;
826: jack->arg = NULL;
827: jack->u.out.intr = NULL;
1.1 tshiozak 828: jack->cable_number = i;
829: jack++;
830: }
831: jack = &sc->sc_in_jacks[0];
832: for (i=0; i<sc->sc_in_num_jacks; i++) {
1.4 tshiozak 833: jack->opened = 0;
834: jack->binded = 0;
835: jack->arg = NULL;
836: jack->u.in.intr = NULL;
1.1 tshiozak 837: jack->cable_number = i;
838: jack++;
839: }
840:
841: /* assign each jacks to each endpoints */
842: jack = &sc->sc_out_jacks[0];
843: ep = &sc->sc_out_ep[0];
844: for (i=0; i<sc->sc_out_num_endpoints; i++) {
845: rjack = &ep->jacks[0];
846: for (j=0; j<ep->num_jacks; j++) {
847: *rjack = jack;
848: jack->endpoint = ep;
849: jack++;
850: rjack++;
851: }
852: ep++;
853: }
854: jack = &sc->sc_in_jacks[0];
855: ep = &sc->sc_in_ep[0];
856: for (i=0; i<sc->sc_in_num_endpoints; i++) {
857: rjack = &ep->jacks[0];
858: for (j=0; j<ep->num_jacks; j++) {
859: *rjack = jack;
860: jack->endpoint = ep;
861: jack++;
862: rjack++;
863: }
864: ep++;
865: }
866:
867: return USBD_NORMAL_COMPLETION;
868: }
869:
870: static void
871: free_all_jacks(struct umidi_softc *sc)
872: {
873: int s;
874:
875: s = splaudio();
876: if (sc->sc_out_jacks) {
877: free(sc->sc_jacks, M_USBDEV);
878: sc->sc_jacks = sc->sc_in_jacks = sc->sc_out_jacks = NULL;
879: }
880: splx(s);
881: }
882:
883: static usbd_status
884: bind_jacks_to_mididev(struct umidi_softc *sc,
885: struct umidi_jack *out_jack,
886: struct umidi_jack *in_jack,
887: struct umidi_mididev *mididev)
888: {
1.8 tshiozak 889: if ((out_jack && out_jack->binded) || (in_jack && in_jack->binded))
1.4 tshiozak 890: return USBD_IN_USE;
891: if (mididev->out_jack || mididev->in_jack)
1.1 tshiozak 892: return USBD_IN_USE;
893:
1.4 tshiozak 894: if (out_jack)
895: out_jack->binded = 1;
896: if (in_jack)
897: in_jack->binded = 1;
1.1 tshiozak 898: mididev->in_jack = in_jack;
899: mididev->out_jack = out_jack;
900:
901: return USBD_NORMAL_COMPLETION;
902: }
903:
1.4 tshiozak 904: static void
1.1 tshiozak 905: unbind_jacks_from_mididev(struct umidi_mididev *mididev)
906: {
1.15 tshiozak 907: if ((mididev->flags & FWRITE) && mididev->out_jack)
1.4 tshiozak 908: close_out_jack(mididev->out_jack);
1.15 tshiozak 909: if ((mididev->flags & FREAD) && mididev->in_jack)
1.4 tshiozak 910: close_in_jack(mididev->in_jack);
1.1 tshiozak 911:
1.4 tshiozak 912: if (mididev->out_jack)
913: mididev->out_jack->binded = 0;
914: if (mididev->in_jack)
915: mididev->in_jack->binded = 0;
916: mididev->out_jack = mididev->in_jack = NULL;
1.1 tshiozak 917: }
918:
1.4 tshiozak 919: static void
1.1 tshiozak 920: unbind_all_jacks(struct umidi_softc *sc)
921: {
922: int i;
923:
924: if (sc->sc_mididevs)
925: for (i=0; i<sc->sc_num_mididevs; i++) {
1.4 tshiozak 926: unbind_jacks_from_mididev(&sc->sc_mididevs[i]);
1.1 tshiozak 927: }
928: }
929:
930: static usbd_status
931: assign_all_jacks_automatically(struct umidi_softc *sc)
932: {
933: usbd_status err;
934: int i;
935: struct umidi_jack *out, *in;
936:
937: err =
938: alloc_all_mididevs(sc,
939: max(sc->sc_out_num_jacks, sc->sc_in_num_jacks));
940: if (err!=USBD_NORMAL_COMPLETION)
941: return err;
942:
943: for (i=0; i<sc->sc_num_mididevs; i++) {
944: out = (i<sc->sc_out_num_jacks) ? &sc->sc_out_jacks[i]:NULL;
945: in = (i<sc->sc_in_num_jacks) ? &sc->sc_in_jacks[i]:NULL;
946: err = bind_jacks_to_mididev(sc, out, in, &sc->sc_mididevs[i]);
947: if (err!=USBD_NORMAL_COMPLETION) {
948: free_all_mididevs(sc);
949: return err;
950: }
951: }
952:
953: return USBD_NORMAL_COMPLETION;
954: }
955:
956: static usbd_status
1.4 tshiozak 957: open_out_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *))
958: {
959: struct umidi_endpoint *ep = jack->endpoint;
960:
961: if (jack->opened)
962: return USBD_IN_USE;
963:
964: jack->arg = arg;
965: jack->u.out.intr = intr;
966: jack->opened = 1;
967: ep->num_open++;
968:
969: return USBD_NORMAL_COMPLETION;
970: }
971:
972: static usbd_status
973: open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int))
1.1 tshiozak 974: {
1.3 tshiozak 975: usbd_status err = USBD_NORMAL_COMPLETION;
976: struct umidi_endpoint *ep = jack->endpoint;
977:
1.4 tshiozak 978: if (jack->opened)
979: return USBD_IN_USE;
980:
981: jack->arg = arg;
982: jack->u.in.intr = intr;
983: jack->opened = 1;
1.3 tshiozak 984: if (ep->num_open++==0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
985: err = start_input_transfer(ep);
1.18 gson 986: if (err != USBD_NORMAL_COMPLETION &&
987: err != USBD_IN_PROGRESS) {
1.3 tshiozak 988: ep->num_open--;
989: }
990: }
991:
992: return err;
1.1 tshiozak 993: }
994:
995: static void
1.4 tshiozak 996: close_out_jack(struct umidi_jack *jack)
1.1 tshiozak 997: {
1.3 tshiozak 998: struct umidi_jack *tail;
999: int s;
1.4 tshiozak 1000:
1001: if (jack->opened) {
1002: s = splusb();
1.15 tshiozak 1003: LIST_FOREACH(tail,
1004: &jack->endpoint->queue_head,
1005: u.out.queue_entry)
1006: if (tail == jack) {
1007: LIST_REMOVE(jack, u.out.queue_entry);
1008: break;
1009: }
1010: if (jack == jack->endpoint->queue_tail) {
1.4 tshiozak 1011: /* find tail */
1012: LIST_FOREACH(tail,
1013: &jack->endpoint->queue_head,
1014: u.out.queue_entry) {
1015: if (!LIST_NEXT(tail, u.out.queue_entry)) {
1016: jack->endpoint->queue_tail = tail;
1017: }
1.3 tshiozak 1018: }
1019: }
1.4 tshiozak 1020: splx(s);
1021: jack->opened = 0;
1022: jack->endpoint->num_open--;
1.3 tshiozak 1023: }
1.1 tshiozak 1024: }
1025:
1.4 tshiozak 1026: static void
1027: close_in_jack(struct umidi_jack *jack)
1028: {
1029: if (jack->opened) {
1030: jack->opened = 0;
1.19 gson 1031: if (--jack->endpoint->num_open == 0) {
1032: usbd_abort_pipe(jack->endpoint->pipe);
1033: }
1.4 tshiozak 1034: }
1035: }
1.1 tshiozak 1036:
1037: static usbd_status
1038: attach_mididev(struct umidi_softc *sc, struct umidi_mididev *mididev)
1039: {
1040: if (mididev->sc)
1041: return USBD_IN_USE;
1042:
1043: mididev->sc = sc;
1044:
1045: mididev->mdev = midi_attach_mi(&umidi_hw_if, mididev, &sc->sc_dev);
1046:
1047: return USBD_NORMAL_COMPLETION;
1048: }
1049:
1050: static usbd_status
1051: detach_mididev(struct umidi_mididev *mididev, int flags)
1052: {
1053: if (!mididev->sc)
1054: return USBD_NO_ADDR;
1055:
1056: if (mididev->opened) {
1057: umidi_close(mididev);
1058: }
1.4 tshiozak 1059: unbind_jacks_from_mididev(mididev);
1.1 tshiozak 1060:
1061: if (mididev->mdev)
1062: config_detach(mididev->mdev, flags);
1063:
1064: mididev->sc = NULL;
1065:
1066: return USBD_NORMAL_COMPLETION;
1067: }
1068:
1069: static usbd_status
1070: deactivate_mididev(struct umidi_mididev *mididev)
1071: {
1.4 tshiozak 1072: if (mididev->out_jack)
1073: mididev->out_jack->binded = 0;
1074: if (mididev->in_jack)
1075: mididev->in_jack->binded = 0;
1.1 tshiozak 1076: config_deactivate(mididev->mdev);
1077:
1078: return USBD_NORMAL_COMPLETION;
1079: }
1080:
1081: static usbd_status
1082: alloc_all_mididevs(struct umidi_softc *sc, int nmidi)
1083: {
1084: sc->sc_num_mididevs = nmidi;
1085: sc->sc_mididevs = malloc(sizeof(*sc->sc_mididevs)*nmidi,
1.13 tsutsui 1086: M_USBDEV, M_WAITOK|M_ZERO);
1.1 tshiozak 1087: if (!sc->sc_mididevs)
1088: return USBD_NOMEM;
1089:
1090: return USBD_NORMAL_COMPLETION;
1091: }
1092:
1093: static void
1094: free_all_mididevs(struct umidi_softc *sc)
1095: {
1096: sc->sc_num_mididevs = 0;
1097: if (sc->sc_mididevs)
1098: free(sc->sc_mididevs, M_USBDEV);
1099: }
1100:
1101: static usbd_status
1102: attach_all_mididevs(struct umidi_softc *sc)
1103: {
1104: usbd_status err;
1105: int i;
1106:
1107: if (sc->sc_mididevs)
1108: for (i=0; i<sc->sc_num_mididevs; i++) {
1109: err = attach_mididev(sc, &sc->sc_mididevs[i]);
1110: if (err!=USBD_NORMAL_COMPLETION)
1111: return err;
1112: }
1113:
1114: return USBD_NORMAL_COMPLETION;
1115: }
1116:
1117: static usbd_status
1118: detach_all_mididevs(struct umidi_softc *sc, int flags)
1119: {
1120: usbd_status err;
1121: int i;
1122:
1123: if (sc->sc_mididevs)
1124: for (i=0; i<sc->sc_num_mididevs; i++) {
1125: err = detach_mididev(&sc->sc_mididevs[i], flags);
1126: if (err!=USBD_NORMAL_COMPLETION)
1127: return err;
1128: }
1129:
1130: return USBD_NORMAL_COMPLETION;
1131: }
1132:
1133: static usbd_status
1134: deactivate_all_mididevs(struct umidi_softc *sc)
1135: {
1136: usbd_status err;
1137: int i;
1138:
1139: if (sc->sc_mididevs)
1140: for (i=0; i<sc->sc_num_mididevs; i++) {
1141: err = deactivate_mididev(&sc->sc_mididevs[i]);
1142: if (err!=USBD_NORMAL_COMPLETION)
1143: return err;
1144: }
1145:
1146: return USBD_NORMAL_COMPLETION;
1147: }
1148:
1149: #ifdef UMIDI_DEBUG
1150: static void
1151: dump_sc(struct umidi_softc *sc)
1152: {
1153: int i;
1154:
1155: DPRINTFN(10, ("%s: dump_sc\n", USBDEVNAME(sc->sc_dev)));
1156: for (i=0; i<sc->sc_out_num_endpoints; i++) {
1157: DPRINTFN(10, ("\tout_ep(%p):\n", &sc->sc_out_ep[i]));
1158: dump_ep(&sc->sc_out_ep[i]);
1159: }
1160: for (i=0; i<sc->sc_in_num_endpoints; i++) {
1161: DPRINTFN(10, ("\tin_ep(%p):\n", &sc->sc_in_ep[i]));
1162: dump_ep(&sc->sc_in_ep[i]);
1163: }
1164: }
1165:
1166: static void
1167: dump_ep(struct umidi_endpoint *ep)
1168: {
1169: int i;
1170: for (i=0; i<ep->num_jacks; i++) {
1171: DPRINTFN(10, ("\t\tjack(%p):\n", ep->jacks[i]));
1172: dump_jack(ep->jacks[i]);
1173: }
1174: }
1175: static void
1176: dump_jack(struct umidi_jack *jack)
1177: {
1.15 tshiozak 1178: DPRINTFN(10, ("\t\t\tep=%p\n",
1179: jack->endpoint));
1.1 tshiozak 1180: }
1181:
1182: #endif /* UMIDI_DEBUG */
1183:
1184:
1185:
1186: /*
1187: * MUX MIDI PACKET
1188: */
1189:
1.5 jdolecek 1190: static const int packet_length[16] = {
1.1 tshiozak 1191: /*0*/ -1,
1192: /*1*/ -1,
1193: /*2*/ 2,
1194: /*3*/ 3,
1195: /*4*/ 3,
1196: /*5*/ 1,
1197: /*6*/ 2,
1198: /*7*/ 3,
1199: /*8*/ 3,
1200: /*9*/ 3,
1201: /*A*/ 3,
1202: /*B*/ 3,
1203: /*C*/ 2,
1204: /*D*/ 2,
1205: /*E*/ 3,
1206: /*F*/ 1,
1207: };
1208:
1209: #define GET_CN(p) (((unsigned char)(p)>>4)&0x0F)
1210: #define GET_CIN(p) ((unsigned char)(p)&0x0F)
1211: #define MIX_CN_CIN(cn, cin) \
1212: ((unsigned char)((((unsigned char)(cn)&0x0F)<<4)| \
1.3 tshiozak 1213: ((unsigned char)(cin)&0x0F)))
1.1 tshiozak 1214:
1215: static usbd_status
1216: start_input_transfer(struct umidi_endpoint *ep)
1217: {
1218: usbd_setup_xfer(ep->xfer, ep->pipe,
1219: (usbd_private_handle)ep,
1.25.2.4 chap 1220: ep->buffer, ep->buffer_size,
1221: USBD_SHORT_XFER_OK | USBD_NO_COPY,
1222: USBD_NO_TIMEOUT, in_intr);
1.1 tshiozak 1223: return usbd_transfer(ep->xfer);
1224: }
1225:
1226: static usbd_status
1227: start_output_transfer(struct umidi_endpoint *ep)
1228: {
1229: usbd_setup_xfer(ep->xfer, ep->pipe,
1230: (usbd_private_handle)ep,
1231: ep->buffer, UMIDI_PACKET_SIZE,
1.11 augustss 1232: USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr);
1.1 tshiozak 1233: return usbd_transfer(ep->xfer);
1234: }
1235:
1.4 tshiozak 1236: #ifdef UMIDI_DEBUG
1237: #define DPR_PACKET(dir, sc, p) \
1238: if ((unsigned char)(p)->buffer[1]!=0xFE) \
1239: DPRINTFN(500, \
1240: ("%s: umidi packet(" #dir "): %02X %02X %02X %02X\n", \
1241: USBDEVNAME(sc->sc_dev), \
1242: (unsigned char)(p)->buffer[0], \
1243: (unsigned char)(p)->buffer[1], \
1244: (unsigned char)(p)->buffer[2], \
1245: (unsigned char)(p)->buffer[3]));
1246: #else
1247: #define DPR_PACKET(dir, sc, p)
1248: #endif
1249:
1.25.2.4 chap 1250: /*
1251: * A 4-byte Midiman packet superficially resembles a 4-byte USB MIDI packet
1252: * with the cable number and length in the last byte instead of the first,
1253: * but there the resemblance ends. Where a USB MIDI packet is a semantic
1254: * unit, a Midiman packet is just a wrapper for 1 to 3 bytes of raw MIDI
1255: * with a cable nybble and a length nybble (which, unlike the CIN of a
1256: * real USB MIDI packet, has no semantics at all besides the length).
1257: * A packet received from a Midiman may contain part of a MIDI message,
1258: * more than one MIDI message, or parts of more than one MIDI message. A
1259: * three-byte MIDI message may arrive in three packets of data length 1, and
1260: * running status may be used. Happily, the midi(4) driver above us will put
1261: * it all back together, so the only cost is in USB bandwidth. The device
1262: * has an easier time with what it receives from us, as we'll just take
1263: * already formed, semantically reasonable USB MIDI packets and munge them
1264: * into Midiman form.
1265: */
1.25.2.2 chap 1266:
1.4 tshiozak 1267: static int
1.25.2.5 chap 1268: out_jack_output(struct umidi_jack *out_jack, u_char *src, int len, int cin)
1.4 tshiozak 1269: {
1270: struct umidi_endpoint *ep = out_jack->endpoint;
1271: struct umidi_softc *sc = ep->sc;
1.25.2.5 chap 1272: struct umidi_packet *packet = &out_jack->packet;
1.4 tshiozak 1273: int error;
1274: int s;
1275:
1276: if (sc->sc_dying)
1277: return EIO;
1278:
1.25.2.5 chap 1279: if (!out_jack->opened)
1280: return ENODEV; /* XXX as it was, is this the right errno? */
1281:
1.4 tshiozak 1282: error = 0;
1.25.2.5 chap 1283: DPRINTFN(1000, ("umidi_output: ep=%p len=%d cin=%#x\n", ep, len, cin));
1284:
1285: memset(packet->buffer, 0, UMIDI_PACKET_SIZE);
1286: if (UMQ_ISTYPE(sc, UMQ_TYPE_MIDIMAN_GARBLE)) {
1287: memcpy(packet->buffer, src, len);
1288: packet->buffer[3] = MIX_CN_CIN(out_jack->cable_number, len);
1289: } else {
1290: packet->buffer[0] = MIX_CN_CIN(out_jack->cable_number, cin);
1291: memcpy(packet->buffer+1, src, len);
1292: }
1293:
1294: DPR_PACKET(out, sc, &out_jack->packet);
1295: s = splusb();
1296: if (LIST_EMPTY(&ep->queue_head)) {
1297: memcpy(ep->buffer, out_jack->packet.buffer, UMIDI_PACKET_SIZE);
1298: start_output_transfer(ep);
1299: }
1300: if (LIST_EMPTY(&ep->queue_head))
1301: LIST_INSERT_HEAD(&ep->queue_head, out_jack, u.out.queue_entry);
1302: else
1303: LIST_INSERT_AFTER(ep->queue_tail, out_jack, u.out.queue_entry);
1304: ep->queue_tail = out_jack;
1305: splx(s);
1.4 tshiozak 1306:
1307: return error;
1308: }
1309:
1.1 tshiozak 1310: static void
1311: in_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
1312: {
1.4 tshiozak 1313: int cn, len, i;
1.1 tshiozak 1314: struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
1.4 tshiozak 1315: struct umidi_jack *jack;
1.25.2.4 chap 1316: unsigned char *packet;
1317: unsigned char *end;
1.25.2.3 chap 1318: unsigned char *data;
1.25.2.4 chap 1319: u_int32_t count;
1.1 tshiozak 1320:
1.3 tshiozak 1321: if (ep->sc->sc_dying || !ep->num_open)
1.1 tshiozak 1322: return;
1323:
1.25.2.4 chap 1324: usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1325: if ( 0 == count % UMIDI_PACKET_SIZE ) {
1326: DPRINTFN(100,("%s: input endpoint %p transfer length %u\n",
1327: USBDEVNAME(ep->sc->sc_dev), ep, count));
1328: } else {
1329: DPRINTF(("%s: input endpoint %p odd transfer length %u\n",
1330: USBDEVNAME(ep->sc->sc_dev), ep, count));
1331: count -= count % UMIDI_PACKET_SIZE;
1332: }
1333:
1334: packet = ep->buffer;
1335: for ( end = packet+count; packet < end; packet += UMIDI_PACKET_SIZE ) {
1336:
1337: if ( UMQ_ISTYPE(ep->sc, UMQ_TYPE_MIDIMAN_GARBLE) ) {
1338: cn = (0xf0&(packet[3]))>>4;
1339: len = 0x0f&(packet[3]);
1340: data = packet;
1341: } else {
1342: cn = GET_CN(packet[0]);
1343: len = packet_length[GET_CIN(packet[0])];
1344: data = packet + 1;
1345: }
1346:
1347: if (cn>=ep->num_jacks || !(jack = ep->jacks[cn])) {
1348: DPRINTF(("%s: stray input endpoint %p cable %d len %d: "
1349: "%02X %02X %02X\n",
1350: USBDEVNAME(ep->sc->sc_dev), ep, cn, len,
1351: (unsigned)data[0],
1352: (unsigned)data[1],
1353: (unsigned)data[2]));
1354: return;
1355: }
1356:
1357: if (!jack->binded || !jack->opened)
1358: return;
1359:
1360: DPRINTFN(500,("%s: input endpoint %p cable %d len %d: "
1361: "%02X %02X %02X\n",
1362: USBDEVNAME(ep->sc->sc_dev), ep, cn, len,
1363: (unsigned)data[0],
1364: (unsigned)data[1],
1365: (unsigned)data[2]));
1366:
1367: if (jack->u.in.intr) {
1368: for (i=0; i<len; i++) {
1369: (*jack->u.in.intr)(jack->arg, data[i]);
1370: }
1.4 tshiozak 1371: }
1.25.2.4 chap 1372:
1.4 tshiozak 1373: }
1.1 tshiozak 1374:
1375: (void)start_input_transfer(ep);
1376: }
1377:
1378: static void
1379: out_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
1380: {
1381: struct umidi_endpoint *ep = (struct umidi_endpoint *)priv;
1382: struct umidi_softc *sc = ep->sc;
1383: struct umidi_jack *jack;
1384:
1.3 tshiozak 1385: if (sc->sc_dying || !ep->num_open)
1.1 tshiozak 1386: return;
1387:
1.4 tshiozak 1388: jack = LIST_FIRST(&ep->queue_head);
1389: if (jack && jack->opened) {
1390: LIST_REMOVE(jack, u.out.queue_entry);
1391: if (!LIST_EMPTY(&ep->queue_head)) {
1.25.2.5 chap 1392: memcpy(ep->buffer,
1.4 tshiozak 1393: LIST_FIRST(&ep->queue_head)->packet.buffer,
1.3 tshiozak 1394: UMIDI_PACKET_SIZE);
1395: (void)start_output_transfer(ep);
1396: }
1.4 tshiozak 1397: if (jack->u.out.intr) {
1398: (*jack->u.out.intr)(jack->arg);
1.3 tshiozak 1399: }
1.1 tshiozak 1400: }
1401: }
CVSweb <webmaster@jp.NetBSD.org>