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