aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/quirks.c
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-03-04 13:46:13 -0500
committerTakashi Iwai <tiwai@suse.de>2010-03-05 02:17:14 -0500
commite5779998bf8b70e48a6cc208c8b61b33bd6117ea (patch)
tree512568f0fc4b81eac8019522c10df5b81483bcca /sound/usb/quirks.c
parent3e1aebef6fb55e35668d2d7cf608cf03f30c904f (diff)
ALSA: usb-audio: refactor code
Clean up the usb audio driver by factoring out a lot of functions to separate files. Code for procfs, quirks, urbs, format parsers etc all got a new home now. Moved almost all special quirk handling to quirks.c and introduced new generic functions to handle them, so the exceptions do not pollute the whole driver. Renamed usbaudio.c to card.c because this is what it actually does now. Renamed usbmidi.c to midi.c for namespace clarity. Removed more things from usbaudio.h. The non-standard drivers were adopted accordingly. Signed-off-by: Daniel Mack <daniel@caiaq.de> Cc: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/quirks.c')
-rw-r--r--sound/usb/quirks.c592
1 files changed, 592 insertions, 0 deletions
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
new file mode 100644
index 000000000000..4c16920844ea
--- /dev/null
+++ b/sound/usb/quirks.c
@@ -0,0 +1,592 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17#include <linux/init.h>
18#include <linux/usb.h>
19#include <linux/usb/audio.h>
20
21#include <sound/core.h>
22#include <sound/info.h>
23#include <sound/pcm.h>
24
25#include "usbaudio.h"
26#include "card.h"
27#include "usbmixer.h"
28#include "midi.h"
29#include "quirks.h"
30#include "helper.h"
31#include "endpoint.h"
32#include "pcm.h"
33
34/*
35 * handle the quirks for the contained interfaces
36 */
37static int create_composite_quirk(struct snd_usb_audio *chip,
38 struct usb_interface *iface,
39 struct usb_driver *driver,
40 const struct snd_usb_audio_quirk *quirk)
41{
42 int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
43 int err;
44
45 for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) {
46 iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
47 if (!iface)
48 continue;
49 if (quirk->ifnum != probed_ifnum &&
50 usb_interface_claimed(iface))
51 continue;
52 err = snd_usb_create_quirk(chip, iface, driver, quirk);
53 if (err < 0)
54 return err;
55 if (quirk->ifnum != probed_ifnum)
56 usb_driver_claim_interface(driver, iface, (void *)-1L);
57 }
58 return 0;
59}
60
61static int ignore_interface_quirk(struct snd_usb_audio *chip,
62 struct usb_interface *iface,
63 struct usb_driver *driver,
64 const struct snd_usb_audio_quirk *quirk)
65{
66 return 0;
67}
68
69
70/*
71 * Allow alignment on audio sub-slot (channel samples) rather than
72 * on audio slots (audio frames)
73 */
74static int create_align_transfer_quirk(struct snd_usb_audio *chip,
75 struct usb_interface *iface,
76 struct usb_driver *driver,
77 const struct snd_usb_audio_quirk *quirk)
78{
79 chip->txfr_quirk = 1;
80 return 1; /* Continue with creating streams and mixer */
81}
82
83static int create_any_midi_quirk(struct snd_usb_audio *chip,
84 struct usb_interface *intf,
85 struct usb_driver *driver,
86 const struct snd_usb_audio_quirk *quirk)
87{
88 return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk);
89}
90
91/*
92 * create a stream for an interface with proper descriptors
93 */
94static int create_standard_audio_quirk(struct snd_usb_audio *chip,
95 struct usb_interface *iface,
96 struct usb_driver *driver,
97 const struct snd_usb_audio_quirk *quirk)
98{
99 struct usb_host_interface *alts;
100 struct usb_interface_descriptor *altsd;
101 int err;
102
103 alts = &iface->altsetting[0];
104 altsd = get_iface_desc(alts);
105 err = snd_usb_parse_audio_endpoints(chip, altsd->bInterfaceNumber);
106 if (err < 0) {
107 snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
108 altsd->bInterfaceNumber, err);
109 return err;
110 }
111 /* reset the current interface */
112 usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0);
113 return 0;
114}
115
116/*
117 * create a stream for an endpoint/altsetting without proper descriptors
118 */
119static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
120 struct usb_interface *iface,
121 struct usb_driver *driver,
122 const struct snd_usb_audio_quirk *quirk)
123{
124 struct audioformat *fp;
125 struct usb_host_interface *alts;
126 int stream, err;
127 unsigned *rate_table = NULL;
128
129 fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
130 if (! fp) {
131 snd_printk(KERN_ERR "cannot memdup\n");
132 return -ENOMEM;
133 }
134 if (fp->nr_rates > 0) {
135 rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
136 if (!rate_table) {
137 kfree(fp);
138 return -ENOMEM;
139 }
140 memcpy(rate_table, fp->rate_table, sizeof(int) * fp->nr_rates);
141 fp->rate_table = rate_table;
142 }
143
144 stream = (fp->endpoint & USB_DIR_IN)
145 ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
146 err = snd_usb_add_audio_endpoint(chip, stream, fp);
147 if (err < 0) {
148 kfree(fp);
149 kfree(rate_table);
150 return err;
151 }
152 if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
153 fp->altset_idx >= iface->num_altsetting) {
154 kfree(fp);
155 kfree(rate_table);
156 return -EINVAL;
157 }
158 alts = &iface->altsetting[fp->altset_idx];
159 fp->datainterval = snd_usb_parse_datainterval(chip, alts);
160 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
161 usb_set_interface(chip->dev, fp->iface, 0);
162 snd_usb_init_pitch(chip->dev, fp->iface, alts, fp);
163 snd_usb_init_sample_rate(chip->dev, fp->iface, alts, fp, fp->rate_max);
164 return 0;
165}
166
167/*
168 * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.
169 * The only way to detect the sample rate is by looking at wMaxPacketSize.
170 */
171static int create_uaxx_quirk(struct snd_usb_audio *chip,
172 struct usb_interface *iface,
173 struct usb_driver *driver,
174 const struct snd_usb_audio_quirk *quirk)
175{
176 static const struct audioformat ua_format = {
177 .format = SNDRV_PCM_FORMAT_S24_3LE,
178 .channels = 2,
179 .fmt_type = UAC_FORMAT_TYPE_I,
180 .altsetting = 1,
181 .altset_idx = 1,
182 .rates = SNDRV_PCM_RATE_CONTINUOUS,
183 };
184 struct usb_host_interface *alts;
185 struct usb_interface_descriptor *altsd;
186 struct audioformat *fp;
187 int stream, err;
188
189 /* both PCM and MIDI interfaces have 2 or more altsettings */
190 if (iface->num_altsetting < 2)
191 return -ENXIO;
192 alts = &iface->altsetting[1];
193 altsd = get_iface_desc(alts);
194
195 if (altsd->bNumEndpoints == 2) {
196 static const struct snd_usb_midi_endpoint_info ua700_ep = {
197 .out_cables = 0x0003,
198 .in_cables = 0x0003
199 };
200 static const struct snd_usb_audio_quirk ua700_quirk = {
201 .type = QUIRK_MIDI_FIXED_ENDPOINT,
202 .data = &ua700_ep
203 };
204 static const struct snd_usb_midi_endpoint_info uaxx_ep = {
205 .out_cables = 0x0001,
206 .in_cables = 0x0001
207 };
208 static const struct snd_usb_audio_quirk uaxx_quirk = {
209 .type = QUIRK_MIDI_FIXED_ENDPOINT,
210 .data = &uaxx_ep
211 };
212 const struct snd_usb_audio_quirk *quirk =
213 chip->usb_id == USB_ID(0x0582, 0x002b)
214 ? &ua700_quirk : &uaxx_quirk;
215 return snd_usbmidi_create(chip->card, iface,
216 &chip->midi_list, quirk);
217 }
218
219 if (altsd->bNumEndpoints != 1)
220 return -ENXIO;
221
222 fp = kmalloc(sizeof(*fp), GFP_KERNEL);
223 if (!fp)
224 return -ENOMEM;
225 memcpy(fp, &ua_format, sizeof(*fp));
226
227 fp->iface = altsd->bInterfaceNumber;
228 fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
229 fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
230 fp->datainterval = 0;
231 fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
232
233 switch (fp->maxpacksize) {
234 case 0x120:
235 fp->rate_max = fp->rate_min = 44100;
236 break;
237 case 0x138:
238 case 0x140:
239 fp->rate_max = fp->rate_min = 48000;
240 break;
241 case 0x258:
242 case 0x260:
243 fp->rate_max = fp->rate_min = 96000;
244 break;
245 default:
246 snd_printk(KERN_ERR "unknown sample rate\n");
247 kfree(fp);
248 return -ENXIO;
249 }
250
251 stream = (fp->endpoint & USB_DIR_IN)
252 ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
253 err = snd_usb_add_audio_endpoint(chip, stream, fp);
254 if (err < 0) {
255 kfree(fp);
256 return err;
257 }
258 usb_set_interface(chip->dev, fp->iface, 0);
259 return 0;
260}
261
262/*
263 * audio-interface quirks
264 *
265 * returns zero if no standard audio/MIDI parsing is needed.
266 * returns a postive value if standard audio/midi interfaces are parsed
267 * after this.
268 * returns a negative value at error.
269 */
270int snd_usb_create_quirk(struct snd_usb_audio *chip,
271 struct usb_interface *iface,
272 struct usb_driver *driver,
273 const struct snd_usb_audio_quirk *quirk)
274{
275 typedef int (*quirk_func_t)(struct snd_usb_audio *,
276 struct usb_interface *,
277 struct usb_driver *,
278 const struct snd_usb_audio_quirk *);
279 static const quirk_func_t quirk_funcs[] = {
280 [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
281 [QUIRK_COMPOSITE] = create_composite_quirk,
282 [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
283 [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
284 [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
285 [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
286 [QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
287 [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
288 [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
289 [QUIRK_MIDI_CME] = create_any_midi_quirk,
290 [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
291 [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
292 [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
293 [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk
294 };
295
296 if (quirk->type < QUIRK_TYPE_COUNT) {
297 return quirk_funcs[quirk->type](chip, iface, driver, quirk);
298 } else {
299 snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
300 return -ENXIO;
301 }
302}
303
304/*
305 * boot quirks
306 */
307
308#define EXTIGY_FIRMWARE_SIZE_OLD 794
309#define EXTIGY_FIRMWARE_SIZE_NEW 483
310
311static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf)
312{
313 struct usb_host_config *config = dev->actconfig;
314 int err;
315
316 if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
317 le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_NEW) {
318 snd_printdd("sending Extigy boot sequence...\n");
319 /* Send message to force it to reconnect with full interface. */
320 err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev,0),
321 0x10, 0x43, 0x0001, 0x000a, NULL, 0, 1000);
322 if (err < 0) snd_printdd("error sending boot message: %d\n", err);
323 err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
324 &dev->descriptor, sizeof(dev->descriptor));
325 config = dev->actconfig;
326 if (err < 0) snd_printdd("error usb_get_descriptor: %d\n", err);
327 err = usb_reset_configuration(dev);
328 if (err < 0) snd_printdd("error usb_reset_configuration: %d\n", err);
329 snd_printdd("extigy_boot: new boot length = %d\n",
330 le16_to_cpu(get_cfg_desc(config)->wTotalLength));
331 return -ENODEV; /* quit this anyway */
332 }
333 return 0;
334}
335
336static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
337{
338 u8 buf = 1;
339
340 snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
341 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
342 0, 0, &buf, 1, 1000);
343 if (buf == 0) {
344 snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0x29,
345 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
346 1, 2000, NULL, 0, 1000);
347 return -ENODEV;
348 }
349 return 0;
350}
351
352/*
353 * C-Media CM106/CM106+ have four 16-bit internal registers that are nicely
354 * documented in the device's data sheet.
355 */
356static int snd_usb_cm106_write_int_reg(struct usb_device *dev, int reg, u16 value)
357{
358 u8 buf[4];
359 buf[0] = 0x20;
360 buf[1] = value & 0xff;
361 buf[2] = (value >> 8) & 0xff;
362 buf[3] = reg;
363 return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_SET_CONFIGURATION,
364 USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
365 0, 0, &buf, 4, 1000);
366}
367
368static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
369{
370 /*
371 * Enable line-out driver mode, set headphone source to front
372 * channels, enable stereo mic.
373 */
374 return snd_usb_cm106_write_int_reg(dev, 2, 0x8004);
375}
376
377/*
378 * C-Media CM6206 is based on CM106 with two additional
379 * registers that are not documented in the data sheet.
380 * Values here are chosen based on sniffing USB traffic
381 * under Windows.
382 */
383static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
384{
385 int err, reg;
386 int val[] = {0x200c, 0x3000, 0xf800, 0x143f, 0x0000, 0x3000};
387
388 for (reg = 0; reg < ARRAY_SIZE(val); reg++) {
389 err = snd_usb_cm106_write_int_reg(dev, reg, val[reg]);
390 if (err < 0)
391 return err;
392 }
393
394 return err;
395}
396
397/*
398 * This call will put the synth in "USB send" mode, i.e it will send MIDI
399 * messages through USB (this is disabled at startup). The synth will
400 * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
401 * sign on its LCD. Values here are chosen based on sniffing USB traffic
402 * under Windows.
403 */
404static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
405{
406 int err, actual_length;
407
408 /* "midi send" enable */
409 static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
410
411 void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
412 if (!buf)
413 return -ENOMEM;
414 err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
415 ARRAY_SIZE(seq), &actual_length, 1000);
416 kfree(buf);
417 if (err < 0)
418 return err;
419
420 return 0;
421}
422
423/*
424 * Setup quirks
425 */
426#define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */
427#define AUDIOPHILE_SET_DTS 0x02 /* if set, enable DTS Digital Output */
428#define AUDIOPHILE_SET_96K 0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
429#define AUDIOPHILE_SET_24B 0x08 /* 24bits sample if set, 16bits otherwise */
430#define AUDIOPHILE_SET_DI 0x10 /* if set, enable Digital Input */
431#define AUDIOPHILE_SET_MASK 0x1F /* bit mask for setup value */
432#define AUDIOPHILE_SET_24B_48K_DI 0x19 /* value for 24bits+48KHz+Digital Input */
433#define AUDIOPHILE_SET_24B_48K_NOTDI 0x09 /* value for 24bits+48KHz+No Digital Input */
434#define AUDIOPHILE_SET_16B_48K_DI 0x11 /* value for 16bits+48KHz+Digital Input */
435#define AUDIOPHILE_SET_16B_48K_NOTDI 0x01 /* value for 16bits+48KHz+No Digital Input */
436
437static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
438 int iface,
439 int altno)
440{
441 /* Reset ALL ifaces to 0 altsetting.
442 * Call it for every possible altsetting of every interface.
443 */
444 usb_set_interface(chip->dev, iface, 0);
445
446 if (chip->setup & AUDIOPHILE_SET) {
447 if ((chip->setup & AUDIOPHILE_SET_DTS)
448 && altno != 6)
449 return 1; /* skip this altsetting */
450 if ((chip->setup & AUDIOPHILE_SET_96K)
451 && altno != 1)
452 return 1; /* skip this altsetting */
453 if ((chip->setup & AUDIOPHILE_SET_MASK) ==
454 AUDIOPHILE_SET_24B_48K_DI && altno != 2)
455 return 1; /* skip this altsetting */
456 if ((chip->setup & AUDIOPHILE_SET_MASK) ==
457 AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3)
458 return 1; /* skip this altsetting */
459 if ((chip->setup & AUDIOPHILE_SET_MASK) ==
460 AUDIOPHILE_SET_16B_48K_DI && altno != 4)
461 return 1; /* skip this altsetting */
462 if ((chip->setup & AUDIOPHILE_SET_MASK) ==
463 AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5)
464 return 1; /* skip this altsetting */
465 }
466
467 return 0; /* keep this altsetting */
468}
469
470int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
471 int iface,
472 int altno)
473{
474 /* audiophile usb: skip altsets incompatible with device_setup */
475 if (chip->usb_id == USB_ID(0x0763, 0x2003))
476 return audiophile_skip_setting_quirk(chip, iface, altno);
477
478 return 0;
479}
480
481int snd_usb_apply_boot_quirk(struct usb_device *dev,
482 struct usb_interface *intf,
483 const struct snd_usb_audio_quirk *quirk)
484{
485 u32 id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
486 le16_to_cpu(dev->descriptor.idProduct));
487
488 /* SB Extigy needs special boot-up sequence */
489 /* if more models come, this will go to the quirk list. */
490 if (id == USB_ID(0x041e, 0x3000))
491 return snd_usb_extigy_boot_quirk(dev, intf);
492
493 /* SB Audigy 2 NX needs its own boot-up magic, too */
494 if (id == USB_ID(0x041e, 0x3020))
495 return snd_usb_audigy2nx_boot_quirk(dev);
496
497 /* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
498 if (id == USB_ID(0x10f5, 0x0200))
499 return snd_usb_cm106_boot_quirk(dev);
500
501 /* C-Media CM6206 / CM106-Like Sound Device */
502 if (id == USB_ID(0x0d8c, 0x0102))
503 return snd_usb_cm6206_boot_quirk(dev);
504
505 /* Access Music VirusTI Desktop */
506 if (id == USB_ID(0x133e, 0x0815))
507 return snd_usb_accessmusic_boot_quirk(dev);
508
509 return 0;
510}
511
512/*
513 * check if the device uses big-endian samples
514 */
515int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp)
516{
517 switch (chip->usb_id) {
518 case USB_ID(0x0763, 0x2001): /* M-Audio Quattro: captured data only */
519 if (fp->endpoint & USB_DIR_IN)
520 return 1;
521 break;
522 case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
523 if (chip->setup == 0x00 ||
524 fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
525 return 1;
526 }
527 return 0;
528}
529
530/*
531 * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device,
532 * not for interface.
533 */
534
535enum {
536 EMU_QUIRK_SR_44100HZ = 0,
537 EMU_QUIRK_SR_48000HZ,
538 EMU_QUIRK_SR_88200HZ,
539 EMU_QUIRK_SR_96000HZ,
540 EMU_QUIRK_SR_176400HZ,
541 EMU_QUIRK_SR_192000HZ
542};
543
544static void set_format_emu_quirk(struct snd_usb_substream *subs,
545 struct audioformat *fmt)
546{
547 unsigned char emu_samplerate_id = 0;
548
549 /* When capture is active
550 * sample rate shouldn't be changed
551 * by playback substream
552 */
553 if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
554 if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1)
555 return;
556 }
557
558 switch (fmt->rate_min) {
559 case 48000:
560 emu_samplerate_id = EMU_QUIRK_SR_48000HZ;
561 break;
562 case 88200:
563 emu_samplerate_id = EMU_QUIRK_SR_88200HZ;
564 break;
565 case 96000:
566 emu_samplerate_id = EMU_QUIRK_SR_96000HZ;
567 break;
568 case 176400:
569 emu_samplerate_id = EMU_QUIRK_SR_176400HZ;
570 break;
571 case 192000:
572 emu_samplerate_id = EMU_QUIRK_SR_192000HZ;
573 break;
574 default:
575 emu_samplerate_id = EMU_QUIRK_SR_44100HZ;
576 break;
577 }
578 snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
579}
580
581void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
582 struct audioformat *fmt)
583{
584 switch (subs->stream->chip->usb_id) {
585 case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
586 case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
587 case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
588 set_format_emu_quirk(subs, fmt);
589 break;
590 }
591}
592