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