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