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