diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2013-03-31 17:43:12 -0400 |
---|---|---|
committer | Clemens Ladisch <clemens@ladisch.de> | 2013-06-27 15:59:48 -0400 |
commit | aafe77cc45a595ca1d4536f2412ddf671ea9108c (patch) | |
tree | f21cc9256d40ece84da14b0c10d097fe859d4cdb /sound/usb/quirks.c | |
parent | ba7c2be114243fa4cfcbc66a81db18e1d55abf4b (diff) |
ALSA: usb-audio: add support for many Roland/Yamaha devices
Add quirks to detect the various vendor-specific descriptors used by
Roland and Yamaha in most of their recent USB audio and MIDI devices.
Together with the previous patch, this should add audio/MIDI support for
the following USB devices:
- Edirol motion dive .tokyo performance package
- Roland MC-808 Synthesizer
- Roland BK-7m Synthesizer
- Roland VIMA JM-5/8 Synthesizer
- Roland SP-555 Sequencer
- Roland V-Synth GT Synthesizer
- Roland Music Atelier AT-75/100/300/350C/500/800/900/900C Organ
- Edirol V-Mixer M-200i/300/380/400/480/R-1000
- BOSS GT-10B Effects Processor
- Roland Fantom G6/G7/G8 Keyboard
- Cakewalk Sonar V-Studio 20/100/700 Audio Interface
- Roland GW-8 Keyboard
- Roland AX-Synth Keyboard
- Roland JUNO-Di/STAGE/Gi Keyboard
- Roland VB-99 Effects Processor
- Cakewalk UM-2G MIDI Interface
- Roland A-500S Keyboard
- Roland SD-50 Synthesizer
- Roland OCTAPAD SPD-30 Controller
- Roland Lucina AX-09 Synthesizer
- BOSS BR-800 Digital Recorder
- Roland DUO/TRI-CAPTURE (EX) Audio Interface
- BOSS RC-300 Loop Station
- Roland JUPITER-50/80 Keyboard
- Roland R-26 Recorder
- Roland SPD-SX Controller
- BOSS JS-10 Audio Player
- Roland TD-11/15/30 Drum Module
- Roland A-49/88 Keyboard
- Roland INTEGRA-7 Synthesizer
- Roland R-88 Recorder
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Diffstat (limited to 'sound/usb/quirks.c')
-rw-r--r-- | sound/usb/quirks.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 3879eae7e874..5363bcca9494 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/usb.h> | 19 | #include <linux/usb.h> |
20 | #include <linux/usb/audio.h> | 20 | #include <linux/usb/audio.h> |
21 | #include <linux/usb/midi.h> | ||
21 | 22 | ||
22 | #include <sound/control.h> | 23 | #include <sound/control.h> |
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
@@ -175,6 +176,178 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, | |||
175 | return 0; | 176 | return 0; |
176 | } | 177 | } |
177 | 178 | ||
179 | static int create_auto_pcm_quirk(struct snd_usb_audio *chip, | ||
180 | struct usb_interface *iface, | ||
181 | struct usb_driver *driver) | ||
182 | { | ||
183 | struct usb_host_interface *alts; | ||
184 | struct usb_interface_descriptor *altsd; | ||
185 | struct usb_endpoint_descriptor *epd; | ||
186 | struct uac1_as_header_descriptor *ashd; | ||
187 | struct uac_format_type_i_discrete_descriptor *fmtd; | ||
188 | |||
189 | /* | ||
190 | * Most Roland/Yamaha audio streaming interfaces have more or less | ||
191 | * standard descriptors, but older devices might lack descriptors, and | ||
192 | * future ones might change, so ensure that we fail silently if the | ||
193 | * interface doesn't look exactly right. | ||
194 | */ | ||
195 | |||
196 | /* must have a non-zero altsetting for streaming */ | ||
197 | if (iface->num_altsetting < 2) | ||
198 | return -ENODEV; | ||
199 | alts = &iface->altsetting[1]; | ||
200 | altsd = get_iface_desc(alts); | ||
201 | |||
202 | /* must have an isochronous endpoint for streaming */ | ||
203 | if (altsd->bNumEndpoints < 1) | ||
204 | return -ENODEV; | ||
205 | epd = get_endpoint(alts, 0); | ||
206 | if (!usb_endpoint_xfer_isoc(epd)) | ||
207 | return -ENODEV; | ||
208 | |||
209 | /* must have format descriptors */ | ||
210 | ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, | ||
211 | UAC_AS_GENERAL); | ||
212 | fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, | ||
213 | UAC_FORMAT_TYPE); | ||
214 | if (!ashd || ashd->bLength < 7 || | ||
215 | !fmtd || fmtd->bLength < 8) | ||
216 | return -ENODEV; | ||
217 | |||
218 | return create_standard_audio_quirk(chip, iface, driver, NULL); | ||
219 | } | ||
220 | |||
221 | static int create_yamaha_midi_quirk(struct snd_usb_audio *chip, | ||
222 | struct usb_interface *iface, | ||
223 | struct usb_driver *driver, | ||
224 | struct usb_host_interface *alts) | ||
225 | { | ||
226 | static const struct snd_usb_audio_quirk yamaha_midi_quirk = { | ||
227 | .type = QUIRK_MIDI_YAMAHA | ||
228 | }; | ||
229 | struct usb_midi_in_jack_descriptor *injd; | ||
230 | struct usb_midi_out_jack_descriptor *outjd; | ||
231 | |||
232 | /* must have some valid jack descriptors */ | ||
233 | injd = snd_usb_find_csint_desc(alts->extra, alts->extralen, | ||
234 | NULL, USB_MS_MIDI_IN_JACK); | ||
235 | outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen, | ||
236 | NULL, USB_MS_MIDI_OUT_JACK); | ||
237 | if (!injd && !outjd) | ||
238 | return -ENODEV; | ||
239 | if (injd && (injd->bLength < 5 || | ||
240 | (injd->bJackType != USB_MS_EMBEDDED && | ||
241 | injd->bJackType != USB_MS_EXTERNAL))) | ||
242 | return -ENODEV; | ||
243 | if (outjd && (outjd->bLength < 6 || | ||
244 | (outjd->bJackType != USB_MS_EMBEDDED && | ||
245 | outjd->bJackType != USB_MS_EXTERNAL))) | ||
246 | return -ENODEV; | ||
247 | return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk); | ||
248 | } | ||
249 | |||
250 | static int create_roland_midi_quirk(struct snd_usb_audio *chip, | ||
251 | struct usb_interface *iface, | ||
252 | struct usb_driver *driver, | ||
253 | struct usb_host_interface *alts) | ||
254 | { | ||
255 | static const struct snd_usb_audio_quirk roland_midi_quirk = { | ||
256 | .type = QUIRK_MIDI_ROLAND | ||
257 | }; | ||
258 | u8 *roland_desc = NULL; | ||
259 | |||
260 | /* might have a vendor-specific descriptor <06 24 F1 02 ...> */ | ||
261 | for (;;) { | ||
262 | roland_desc = snd_usb_find_csint_desc(alts->extra, | ||
263 | alts->extralen, | ||
264 | roland_desc, 0xf1); | ||
265 | if (!roland_desc) | ||
266 | return -ENODEV; | ||
267 | if (roland_desc[0] < 6 || roland_desc[3] != 2) | ||
268 | continue; | ||
269 | return create_any_midi_quirk(chip, iface, driver, | ||
270 | &roland_midi_quirk); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static int create_std_midi_quirk(struct snd_usb_audio *chip, | ||
275 | struct usb_interface *iface, | ||
276 | struct usb_driver *driver, | ||
277 | struct usb_host_interface *alts) | ||
278 | { | ||
279 | struct usb_ms_header_descriptor *mshd; | ||
280 | struct usb_ms_endpoint_descriptor *msepd; | ||
281 | |||
282 | /* must have the MIDIStreaming interface header descriptor*/ | ||
283 | mshd = (struct usb_ms_header_descriptor *)alts->extra; | ||
284 | if (alts->extralen < 7 || | ||
285 | mshd->bLength < 7 || | ||
286 | mshd->bDescriptorType != USB_DT_CS_INTERFACE || | ||
287 | mshd->bDescriptorSubtype != USB_MS_HEADER) | ||
288 | return -ENODEV; | ||
289 | /* must have the MIDIStreaming endpoint descriptor*/ | ||
290 | msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra; | ||
291 | if (alts->endpoint[0].extralen < 4 || | ||
292 | msepd->bLength < 4 || | ||
293 | msepd->bDescriptorType != USB_DT_CS_ENDPOINT || | ||
294 | msepd->bDescriptorSubtype != UAC_MS_GENERAL || | ||
295 | msepd->bNumEmbMIDIJack < 1 || | ||
296 | msepd->bNumEmbMIDIJack > 16) | ||
297 | return -ENODEV; | ||
298 | |||
299 | return create_any_midi_quirk(chip, iface, driver, NULL); | ||
300 | } | ||
301 | |||
302 | static int create_auto_midi_quirk(struct snd_usb_audio *chip, | ||
303 | struct usb_interface *iface, | ||
304 | struct usb_driver *driver) | ||
305 | { | ||
306 | struct usb_host_interface *alts; | ||
307 | struct usb_interface_descriptor *altsd; | ||
308 | struct usb_endpoint_descriptor *epd; | ||
309 | int err; | ||
310 | |||
311 | alts = &iface->altsetting[0]; | ||
312 | altsd = get_iface_desc(alts); | ||
313 | |||
314 | /* must have at least one bulk/interrupt endpoint for streaming */ | ||
315 | if (altsd->bNumEndpoints < 1) | ||
316 | return -ENODEV; | ||
317 | epd = get_endpoint(alts, 0); | ||
318 | if (!usb_endpoint_xfer_bulk(epd) || | ||
319 | !usb_endpoint_xfer_int(epd)) | ||
320 | return -ENODEV; | ||
321 | |||
322 | switch (USB_ID_VENDOR(chip->usb_id)) { | ||
323 | case 0x0499: /* Yamaha */ | ||
324 | err = create_yamaha_midi_quirk(chip, iface, driver, alts); | ||
325 | if (err < 0 && err != -ENODEV) | ||
326 | return err; | ||
327 | break; | ||
328 | case 0x0582: /* Roland */ | ||
329 | err = create_roland_midi_quirk(chip, iface, driver, alts); | ||
330 | if (err < 0 && err != -ENODEV) | ||
331 | return err; | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | return create_std_midi_quirk(chip, iface, driver, alts); | ||
336 | } | ||
337 | |||
338 | static int create_autodetect_quirk(struct snd_usb_audio *chip, | ||
339 | struct usb_interface *iface, | ||
340 | struct usb_driver *driver, | ||
341 | const struct snd_usb_audio_quirk *quirk) | ||
342 | { | ||
343 | int err; | ||
344 | |||
345 | err = create_auto_pcm_quirk(chip, iface, driver); | ||
346 | if (err == -ENODEV) | ||
347 | err = create_auto_midi_quirk(chip, iface, driver); | ||
348 | return err; | ||
349 | } | ||
350 | |||
178 | /* | 351 | /* |
179 | * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface. | 352 | * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface. |
180 | * The only way to detect the sample rate is by looking at wMaxPacketSize. | 353 | * The only way to detect the sample rate is by looking at wMaxPacketSize. |
@@ -303,9 +476,11 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
303 | static const quirk_func_t quirk_funcs[] = { | 476 | static const quirk_func_t quirk_funcs[] = { |
304 | [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, | 477 | [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, |
305 | [QUIRK_COMPOSITE] = create_composite_quirk, | 478 | [QUIRK_COMPOSITE] = create_composite_quirk, |
479 | [QUIRK_AUTODETECT] = create_autodetect_quirk, | ||
306 | [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, | 480 | [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, |
307 | [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, | 481 | [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, |
308 | [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, | 482 | [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, |
483 | [QUIRK_MIDI_ROLAND] = create_any_midi_quirk, | ||
309 | [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, | 484 | [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, |
310 | [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, | 485 | [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, |
311 | [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, | 486 | [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, |