xref: /netbsd-src/sys/dev/usb/umidi_quirks.c (revision 267197ec1eebfcb9810ea27a89625b6ddf68e3e7)
1 /*	$NetBSD: umidi_quirks.c,v 1.14 2008/01/04 21:18:07 ad Exp $	*/
2 
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	  This product includes software developed by the NetBSD
21  *	  Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: umidi_quirks.c,v 1.14 2008/01/04 21:18:07 ad Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/device.h>
47 #include <sys/ioctl.h>
48 #include <sys/conf.h>
49 #include <sys/file.h>
50 #include <sys/select.h>
51 #include <sys/proc.h>
52 #include <sys/vnode.h>
53 #include <sys/poll.h>
54 
55 #include <dev/usb/usb.h>
56 #include <dev/usb/usbdi.h>
57 #include <dev/usb/usbdi_util.h>
58 
59 #include <dev/usb/usbdevs.h>
60 #include <dev/usb/uaudioreg.h>
61 #include <dev/usb/umidireg.h>
62 #include <dev/usb/umidivar.h>
63 #include <dev/usb/umidi_quirks.h>
64 
65 /*
66  * quirk codes for UMIDI
67  */
68 
69 #ifdef UMIDIQUIRK_DEBUG
70 #define DPRINTF(x)	if (umidiquirkdebug) printf x
71 #define DPRINTFN(n,x)	if (umidiquirkdebug >= (n)) printf x
72 int	umidiquirkdebug = 1;
73 #else
74 #define DPRINTF(x)
75 #define DPRINTFN(n,x)
76 #endif
77 
78 
79 /*
80  * YAMAHA UX-256
81  *  --- this is a typical yamaha device, but has a broken descriptor :-<
82  */
83 
84 UMQ_FIXED_EP_DEF(YAMAHA, YAMAHA_UX256, ANYIFACE, 1, 1) = {
85 	/* out */
86 	{ 0, 16 },
87 	/* in */
88 	{ 1, 8 }
89 };
90 
91 UMQ_DEF(YAMAHA, YAMAHA_UX256, ANYIFACE) = {
92 	UMQ_FIXED_EP_REG(YAMAHA, YAMAHA_UX256, ANYIFACE),
93 #if 0
94 	UMQ_YAMAHA_REG(YAMAHA, ANYPRODUCT, ANYIFACE),
95 #endif
96 	UMQ_TERMINATOR
97 };
98 
99 
100 /*
101  * YAMAHA generic
102  */
103 UMQ_DEF(YAMAHA, ANYPRODUCT, ANYIFACE) = {
104 	UMQ_YAMAHA_REG(YAMAHA, ANYPRODUCT, ANYIFACE),
105 	UMQ_TERMINATOR
106 };
107 
108 
109 /*
110  * ROLAND UM-1
111  */
112 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM1, 2, 1, 1) = {
113 	/* out */
114 	{ 0, 1 },
115 	/* in */
116 	{ 1, 1 }
117 };
118 
119 UMQ_DEF(ROLAND, ROLAND_UM1, 2) = {
120 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM1, 2),
121 	UMQ_TERMINATOR
122 };
123 
124 /*
125  * ROLAND SC-8850
126  */
127 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SC8850, 2, 1, 1) = {
128 	/* out */
129 	{ 0, 6 },
130 	/* in */
131 	{ 1, 6 }
132 };
133 
134 UMQ_DEF(ROLAND, ROLAND_SC8850, 2) = {
135 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SC8850, 2),
136 	UMQ_TERMINATOR
137 };
138 
139 /*
140  * ROLAND SD-90
141  */
142 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SD90, 2, 1, 1) = {
143 	/* out */
144 	{ 0, 4 },
145 	/* in */
146 	{ 1, 4 }
147 };
148 
149 UMQ_DEF(ROLAND, ROLAND_SD90, 2) = {
150 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SD90, 2),
151 	UMQ_TERMINATOR
152 };
153 
154 
155 /*
156  * ROLAND UM-880 (native mode)
157  */
158 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM880N, 0, 1, 1) = {
159 	/* out */
160 	{ 0, 9 },
161 	/* in */
162 	{ 1, 9 }
163 };
164 
165 UMQ_DEF(ROLAND, ROLAND_UM880N, 0) = {
166 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM880N, 0),
167 	UMQ_TERMINATOR
168 };
169 
170 /*
171  * ROLAND UA-100
172  */
173 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA100, 2, 1, 1) = {
174 	/* out */
175 	{ 0, 3 },
176 	/* in */
177 	{ 1, 3 }
178 };
179 
180 UMQ_DEF(ROLAND, ROLAND_UA100, 2) = {
181 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA100, 2),
182 	UMQ_TERMINATOR
183 };
184 
185 /*
186  * ROLAND UM-4
187  */
188 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM4, 2, 1, 1) = {
189 	/* out */
190 	{ 0, 4 },
191 	/* in */
192 	{ 1, 4 }
193 };
194 
195 UMQ_DEF(ROLAND, ROLAND_UM4, 2) = {
196 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM4, 2),
197 	UMQ_TERMINATOR
198 };
199 
200 /*
201  * ROLAND U-8
202  */
203 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_U8, 2, 1, 1) = {
204 	/* out */
205 	{ 0, 2 },
206 	/* in */
207 	{ 1, 2 }
208 };
209 
210 UMQ_DEF(ROLAND, ROLAND_U8, 2) = {
211 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_U8, 2),
212 	UMQ_TERMINATOR
213 };
214 
215 /*
216  * ROLAND UM-2
217  */
218 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM2, 2, 1, 1) = {
219 	/* out */
220 	{ 0, 2 },
221 	/* in */
222 	{ 1, 2 }
223 };
224 
225 UMQ_DEF(ROLAND, ROLAND_UM2, 2) = {
226 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM2, 2),
227 	UMQ_TERMINATOR
228 };
229 
230 /*
231  * ROLAND SC-8820
232  */
233 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SC8820, 2, 1, 1) = {
234 	/* out */
235 	{ 0, 5 }, /* cables 0, 1, 4 only */
236 	/* in */
237 	{ 1, 5 } /* do. */
238 };
239 
240 UMQ_DEF(ROLAND, ROLAND_SC8820, 2) = {
241 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SC8820, 2),
242 	UMQ_TERMINATOR
243 };
244 
245 /*
246  * ROLAND PC-300
247  */
248 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_PC300, 2, 1, 1) = {
249 	/* out */
250 	{ 0, 1 },
251 	/* in */
252 	{ 1, 1 }
253 };
254 
255 UMQ_DEF(ROLAND, ROLAND_PC300, 2) = {
256 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_PC300, 2),
257 	UMQ_TERMINATOR
258 };
259 
260 /*
261  * ROLAND SK-500
262  */
263 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SK500, 2, 1, 1) = {
264 	/* out */
265 	{ 0, 5 }, /* cables 0, 1, 4 only */
266 	/* in */
267 	{ 1, 5 } /* do. */
268 };
269 
270 UMQ_DEF(ROLAND, ROLAND_SK500, 2) = {
271 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SK500, 2),
272 	UMQ_TERMINATOR
273 };
274 
275 /*
276  * ROLAND SC-D70
277  */
278 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SCD70, 2, 1, 1) = {
279 	/* out */
280 	{ 0, 3 },
281 	/* in */
282 	{ 1, 3 }
283 };
284 
285 UMQ_DEF(ROLAND, ROLAND_SCD70, 2) = {
286 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SCD70, 2),
287 	UMQ_TERMINATOR
288 };
289 
290 /*
291  * ROLAND XV-5050
292  */
293 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_XV5050, 0, 1, 1) = {
294 	/* out */
295 	{ 0, 1 },
296 	/* in */
297 	{ 1, 1 }
298 };
299 
300 UMQ_DEF(ROLAND, ROLAND_XV5050, 0) = {
301 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_XV5050, 0),
302 	UMQ_TERMINATOR
303 };
304 
305 /*
306  * ROLAND UM-550
307  */
308 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM550, 0, 1, 1) = {
309 	/* out */
310 	{ 0, 6 },
311 	/* in */
312 	{ 1, 6 }
313 };
314 
315 UMQ_DEF(ROLAND, ROLAND_UM550, 0) = {
316 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM550, 0),
317 	UMQ_TERMINATOR
318 };
319 
320 /*
321  * ROLAND SD-20
322  */
323 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SD20, 0, 1, 1) = {
324 	/* out */
325 	{ 0, 2 },
326 	/* in */
327 	{ 1, 3 }
328 };
329 
330 UMQ_DEF(ROLAND, ROLAND_SD20, 0) = {
331 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SD20, 0),
332 	UMQ_TERMINATOR
333 };
334 
335 /*
336  * ROLAND SD-80
337  */
338 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SD80, 0, 1, 1) = {
339 	/* out */
340 	{ 0, 4 },
341 	/* in */
342 	{ 1, 4 }
343 };
344 
345 UMQ_DEF(ROLAND, ROLAND_SD80, 0) = {
346 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SD80, 0),
347 	UMQ_TERMINATOR
348 };
349 
350 /*
351  * ROLAND UA-700
352  */
353 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA700, 3, 1, 1) = {
354 	/* out */
355 	{ 0, 2 },
356 	/* in */
357 	{ 1, 2 }
358 };
359 
360 UMQ_DEF(ROLAND, ROLAND_UA700, 3) = {
361 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA700, 3),
362 	UMQ_TERMINATOR
363 };
364 
365 /*
366  * ROLAND UA-1000
367  */
368 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA1000, 3, 1, 1) = {
369 	/* out */
370 	{ 0, 2 },
371 	/* in */
372 	{ 1, 2 }
373 };
374 
375 UMQ_DEF(ROLAND, ROLAND_UA1000, 3) = {
376 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA1000, 3),
377 	UMQ_TERMINATOR
378 };
379 
380 /*
381  * ROLAND UA-101
382  */
383 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA101, 2, 1, 1) = {
384 	/* out */
385 	{ 0, 2 },
386 	/* in */
387 	{ 1, 2 }
388 };
389 
390 UMQ_DEF(ROLAND, ROLAND_UA101, 2) = {
391 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA101, 2),
392 	UMQ_TERMINATOR
393 };
394 
395 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA101F, 2, 1, 1) = {
396 	/* out */
397 	{ 0, 2 },
398 	/* in */
399 	{ 1, 2 }
400 };
401 
402 UMQ_DEF(ROLAND, ROLAND_UA101F, 2) = {
403 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA101F, 2),
404 	UMQ_TERMINATOR
405 };
406 
407 /*
408  * ROLAND Fantom-X
409  */
410 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_FANTOMX, 0, 1, 1) = {
411 	/* out */
412 	{ 0, 1 },
413 	/* in */
414 	{ 1, 1 }
415 };
416 
417 UMQ_DEF(ROLAND, ROLAND_FANTOMX, 0) = {
418 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_FANTOMX, 0),
419 	UMQ_TERMINATOR
420 };
421 
422 /*
423  * ROLAND PCR
424  */
425 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_PCR, 0, 1, 1) = {
426 	/* out */
427 	{ 0, 3 },
428 	/* in */
429 	{ 1, 3 }
430 };
431 
432 UMQ_DEF(ROLAND, ROLAND_PCR, 0) = {
433 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_PCR, 0),
434 	UMQ_TERMINATOR
435 };
436 
437 /*
438  * ROLAND UM-3EX
439  */
440 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UM3, 0, 1, 1) = {
441 	/* out */
442 	{ 0, 3 },
443 	/* in */
444 	{ 1, 3 }
445 };
446 
447 UMQ_DEF(ROLAND, ROLAND_UM3, 0) = {
448 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UM3, 0),
449 	UMQ_TERMINATOR
450 };
451 
452 /*
453  * ROLAND UA-25
454  */
455 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA25, 2, 1, 1) = {
456 	/* out */
457 	{ 0, 1 },
458 	/* in */
459 	{ 1, 1 }
460 };
461 
462 UMQ_DEF(ROLAND, ROLAND_UA25, 2) = {
463 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA25, 2),
464 	UMQ_TERMINATOR
465 };
466 
467 /*
468  * ROLAND UA-4FX
469  */
470 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_UA4FX, 2, 1, 1) = {
471 	/* out */
472 	{ 0, 1 },
473 	/* in */
474 	{ 1, 1 }
475 };
476 
477 UMQ_DEF(ROLAND, ROLAND_UA4FX, 2) = {
478 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_UA4FX, 2),
479 	UMQ_TERMINATOR
480 };
481 
482 /*
483  * ROLAND SonicCell
484  */
485 UMQ_FIXED_EP_DEF(ROLAND, ROLAND_SONICCELL, 2, 1, 1) = {
486 	/* out */
487 	{ 0, 1 },
488 	/* in */
489 	{ 1, 1 }
490 };
491 
492 UMQ_DEF(ROLAND, ROLAND_SONICCELL, 2) = {
493 	UMQ_FIXED_EP_REG(ROLAND, ROLAND_SONICCELL, 2),
494 	UMQ_TERMINATOR
495 };
496 
497 /*
498  * Midiman Midisport 2x4. This has 2 physical MIDI IN jacks that are read
499  * on endpoint 0x81 (descriptor index 0). It has 4 physical MIDI OUT jacks
500  * that can be written on endpoints 2 or 4 (at descriptor index 2 or 4,
501  * coincidentally) interchangeably: either endpoint will accept a Cable Number
502  * field of 0 to 3, and data for a given CN will be routed to the same
503  * physical output regardless of the endpoint used for the transfer. But
504  * there's a catch: flow-control feedback only goes to endpoint 2 for
505  * CN 0 and 2, and only to endpoint 4 for CN 1 and 3. If you send output at
506  * high rates for CN 0 or 2 over endpoint 4, or for CN 1 or 3 over endpoint 2,
507  * the USB transfers complete as fast as possible, giving you an apparent data
508  * rate much higher than MIDI's 3125 cps (easy to measure using dd to blast a
509  * bunch of midi data to the rmidi device). Of course that isn't a way to make
510  * MIDI faster, just a way to overrun the device buffer and spray bits on the
511  * floor. So this device needs the fixed endpoint quirk, the fixed cable number
512  * quirk (to make sure CNs 0 and 2 are put on the first endpoint and 1 and 3
513  * on the other), and then the fixed mididev-assignment quirk (to match jacks
514  * to mididevs so the rmidi devices match the order of the blinkenlights).
515  */
516 UMQ_FIXED_EP_DEF(MIDIMAN, MIDIMAN_MIDISPORT2X4, ANYIFACE, 2, 1) = {
517 	/* out: ep# jacks */
518 	{ 2, 2 },
519 	{ 4, 2 },
520 	/* in: ep# jacks */
521 	{ 0, 2 }
522 };
523 UMQ_DEF(MIDIMAN, MIDIMAN_MIDISPORT2X4, ANYIFACE) = {
524 	UMQ_FIXED_EP_REG(MIDIMAN, MIDIMAN_MIDISPORT2X4, ANYIFACE),
525 	UMQ_CN_FIXED_REG(0, 2, 1, 3, 0, 1),
526 	UMQ_MD_FIXED_REG(0, 0, 2, 1, 1, -1, 3, -1),
527 	UMQ_TYPE(MIDIMAN_GARBLE),
528 	UMQ_TERMINATOR
529 };
530 
531 /*
532  * quirk list
533  */
534 struct umidi_quirk umidi_quirklist[] = {
535 	UMQ_REG(YAMAHA, YAMAHA_UX256, ANYIFACE),
536 	UMQ_REG(YAMAHA, ANYPRODUCT, ANYIFACE),
537 	UMQ_REG(ROLAND, ROLAND_UM1, 2),
538 	UMQ_REG(ROLAND, ROLAND_SC8850, 2),
539 	UMQ_REG(ROLAND, ROLAND_SD90, 2),
540 	UMQ_REG(ROLAND, ROLAND_UM880N, 0),
541 	UMQ_REG(ROLAND, ROLAND_UA100, 2),
542 	UMQ_REG(ROLAND, ROLAND_UM4, 2),
543 	UMQ_REG(ROLAND, ROLAND_U8, 2),
544 	UMQ_REG(ROLAND, ROLAND_UM2, 2),
545 	UMQ_REG(ROLAND, ROLAND_SC8820, 2),
546 	UMQ_REG(ROLAND, ROLAND_PC300, 2),
547 	UMQ_REG(ROLAND, ROLAND_SK500, 2),
548 	UMQ_REG(ROLAND, ROLAND_SCD70, 2),
549 	UMQ_REG(ROLAND, ROLAND_XV5050, 0),
550 	UMQ_REG(ROLAND, ROLAND_UM550, 0),
551 	UMQ_REG(ROLAND, ROLAND_SD20, 0),
552 	UMQ_REG(ROLAND, ROLAND_SD80, 0),
553 	UMQ_REG(ROLAND, ROLAND_UA700, 3),
554 	UMQ_REG(ROLAND, ROLAND_UA1000, 3),
555 	UMQ_REG(ROLAND, ROLAND_UA101, 2),
556 	UMQ_REG(ROLAND, ROLAND_UA101F, 2),
557 	UMQ_REG(ROLAND, ROLAND_FANTOMX, 0),
558 	UMQ_REG(ROLAND, ROLAND_PCR, 0),
559 	UMQ_REG(ROLAND, ROLAND_UM3, 0),
560 	UMQ_REG(ROLAND, ROLAND_UA25, 2),
561 	UMQ_REG(ROLAND, ROLAND_UA4FX, 2),
562 	UMQ_REG(ROLAND, ROLAND_SONICCELL, 2),
563 	UMQ_REG(MIDIMAN, MIDIMAN_MIDISPORT2X4, ANYIFACE),
564 	{ .vendor = 0 },
565 };
566 
567 
568 /*
569  * quirk utilities
570  */
571 
572 struct umidi_quirk *
573 umidi_search_quirk(int vendor, int product, int ifaceno)
574 {
575 	struct umidi_quirk *p;
576 	struct umq_data *q;
577 
578 	DPRINTF(("umidi_search_quirk: v=%d, p=%d, i=%d\n",
579 		 vendor, product, ifaceno));
580 
581 	for (p=&umidi_quirklist[0]; p->vendor; p++) {
582 		DPRINTFN(10, ("\tv=%d, p=%d, i=%d",
583 			      p->vendor, p->product, p->iface));
584 		if ((p->vendor==vendor || p->vendor==ANYVENDOR) &&
585 		    (p->product==product || p->product==ANYPRODUCT) &&
586 		    (p->iface==ifaceno || p->iface==ANYIFACE)) {
587 			DPRINTFN(10, (" found\n"));
588 			if (!p->type_mask)
589 				/* make quirk mask */
590 				for (q=p->quirks; q->type; q++)
591 					p->type_mask |= 1<<(q->type-1);
592 			return p;
593 		}
594 		DPRINTFN(10, ("\n"));
595 	}
596 
597 	return NULL;
598 }
599 
600 static const char *quirk_name[] = {
601 	"NULL",
602 	"Fixed Endpoint",
603 	"Yamaha Specific",
604 	"Midiman Packet Garbling",
605 	"Cable Numbers per Endpoint",
606 	"Cable Numbers Global",
607 	"Cable Numbers Fixed",
608 	"Unit Mapping Fixed",
609 };
610 
611 void
612 umidi_print_quirk(struct umidi_quirk *q)
613 {
614 	struct umq_data *qd;
615 	if (q) {
616 		printf("(");
617 		for (qd=q->quirks; qd->type; qd++)
618 			printf("%s%s", quirk_name[qd->type],
619 			       (qd+1)->type?", ":")\n");
620 	} else {
621 		printf("(genuine USB-MIDI)\n");
622 	}
623 }
624 
625 void *
626 umidi_get_quirk_data_from_type(struct umidi_quirk *q, u_int32_t type)
627 {
628 	struct umq_data *qd;
629 	if (q) {
630 		for (qd=q->quirks; qd->type; qd++)
631 			if (qd->type == type)
632 				return qd->data;
633 	}
634 	return NULL;
635 }
636