diff options
| author | Sergiy Kovalchuk <cnb_zerg@yahoo.com> | 2009-12-27 12:13:41 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2009-12-28 06:29:39 -0500 |
| commit | 7d2b451e65d255427c108e990507964ac39c13ee (patch) | |
| tree | 86e977405ae88b08fa74dff3202c9f88207dfacb | |
| parent | 44eba3e82b35ae796826a65d8040001582adc10a (diff) | |
ALSA: usb-audio - Added functionality for E-mu 0404USB/0202USB/TrackerPre
Added functionality:
1) Extension Units support (all XU settings now available at alsamixer,
kmix, etc):
- "AnalogueIn soft limiter" switch;
- "Sample rate" selector (values 0,1,2,3,4,5 corresponds to 44.1 48 ...
192 kHz);
- "DigitalIn CLK source" selector (internal/external) (**);
- "DigitalOut format SPDIF/AC3" switch (**);
(**)E-mu-0404usb only.
2) Automatic device sample rate adjustment depending on substream
samplerate for both capture and playback substream.
[minor coding-style fixes by tiwai]
Signed-off-by: Sergiy Kovalchuk <cnb_zerg@yahoo.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
| -rw-r--r-- | sound/usb/usbaudio.c | 49 | ||||
| -rw-r--r-- | sound/usb/usbaudio.h | 13 | ||||
| -rw-r--r-- | sound/usb/usbmixer.c | 75 |
3 files changed, 133 insertions, 4 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 31b63ea098b7..286fa14e48bd 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
| @@ -1271,6 +1271,47 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, | |||
| 1271 | } | 1271 | } |
| 1272 | 1272 | ||
| 1273 | /* | 1273 | /* |
| 1274 | * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, | ||
| 1275 | * not for interface. | ||
| 1276 | */ | ||
| 1277 | static void set_format_emu_quirk(struct snd_usb_substream *subs, | ||
| 1278 | struct audioformat *fmt) | ||
| 1279 | { | ||
| 1280 | unsigned char emu_samplerate_id = 0; | ||
| 1281 | |||
| 1282 | /* When capture is active | ||
| 1283 | * sample rate shouldn't be changed | ||
| 1284 | * by playback substream | ||
| 1285 | */ | ||
| 1286 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 1287 | if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) | ||
| 1288 | return; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | switch (fmt->rate_min) { | ||
| 1292 | case 48000: | ||
| 1293 | emu_samplerate_id = EMU_QUIRK_SR_48000HZ; | ||
| 1294 | break; | ||
| 1295 | case 88200: | ||
| 1296 | emu_samplerate_id = EMU_QUIRK_SR_88200HZ; | ||
| 1297 | break; | ||
| 1298 | case 96000: | ||
| 1299 | emu_samplerate_id = EMU_QUIRK_SR_96000HZ; | ||
| 1300 | break; | ||
| 1301 | case 176400: | ||
| 1302 | emu_samplerate_id = EMU_QUIRK_SR_176400HZ; | ||
| 1303 | break; | ||
| 1304 | case 192000: | ||
| 1305 | emu_samplerate_id = EMU_QUIRK_SR_192000HZ; | ||
| 1306 | break; | ||
| 1307 | default: | ||
| 1308 | emu_samplerate_id = EMU_QUIRK_SR_44100HZ; | ||
| 1309 | break; | ||
| 1310 | } | ||
| 1311 | snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | /* | ||
| 1274 | * find a matching format and set up the interface | 1315 | * find a matching format and set up the interface |
| 1275 | */ | 1316 | */ |
| 1276 | static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | 1317 | static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) |
| @@ -1383,6 +1424,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
| 1383 | 1424 | ||
| 1384 | subs->cur_audiofmt = fmt; | 1425 | subs->cur_audiofmt = fmt; |
| 1385 | 1426 | ||
| 1427 | switch (subs->stream->chip->usb_id) { | ||
| 1428 | case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ | ||
| 1429 | case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ | ||
| 1430 | case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ | ||
| 1431 | set_format_emu_quirk(subs, fmt); | ||
| 1432 | break; | ||
| 1433 | } | ||
| 1434 | |||
| 1386 | #if 0 | 1435 | #if 0 |
| 1387 | printk(KERN_DEBUG | 1436 | printk(KERN_DEBUG |
| 1388 | "setting done: format = %d, rate = %d..%d, channels = %d\n", | 1437 | "setting done: format = %d, rate = %d..%d, channels = %d\n", |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 9826337c76b8..152216738cce 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
| @@ -208,6 +208,16 @@ struct snd_usb_midi_endpoint_info { | |||
| 208 | /* | 208 | /* |
| 209 | */ | 209 | */ |
| 210 | 210 | ||
| 211 | /*E-mu USB samplerate control quirk*/ | ||
| 212 | enum { | ||
| 213 | EMU_QUIRK_SR_44100HZ = 0, | ||
| 214 | EMU_QUIRK_SR_48000HZ, | ||
| 215 | EMU_QUIRK_SR_88200HZ, | ||
| 216 | EMU_QUIRK_SR_96000HZ, | ||
| 217 | EMU_QUIRK_SR_176400HZ, | ||
| 218 | EMU_QUIRK_SR_192000HZ | ||
| 219 | }; | ||
| 220 | |||
| 211 | #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) | 221 | #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) |
| 212 | #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) | 222 | #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) |
| 213 | #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) | 223 | #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) |
| @@ -233,6 +243,9 @@ void snd_usbmidi_input_stop(struct list_head* p); | |||
| 233 | void snd_usbmidi_input_start(struct list_head* p); | 243 | void snd_usbmidi_input_start(struct list_head* p); |
| 234 | void snd_usbmidi_disconnect(struct list_head *p); | 244 | void snd_usbmidi_disconnect(struct list_head *p); |
| 235 | 245 | ||
| 246 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | ||
| 247 | unsigned char samplerate_id); | ||
| 248 | |||
| 236 | /* | 249 | /* |
| 237 | * retrieve usb_interface descriptor from the host interface | 250 | * retrieve usb_interface descriptor from the host interface |
| 238 | * (conditional for compatibility with the older API) | 251 | * (conditional for compatibility with the older API) |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c998220b99c6..f5596cfdbde1 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
| @@ -186,6 +186,21 @@ enum { | |||
| 186 | USB_PROC_DCR_RELEASE = 6, | 186 | USB_PROC_DCR_RELEASE = 6, |
| 187 | }; | 187 | }; |
| 188 | 188 | ||
| 189 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ | ||
| 190 | enum { | ||
| 191 | USB_XU_CLOCK_RATE = 0xe301, | ||
| 192 | USB_XU_CLOCK_SOURCE = 0xe302, | ||
| 193 | USB_XU_DIGITAL_IO_STATUS = 0xe303, | ||
| 194 | USB_XU_DEVICE_OPTIONS = 0xe304, | ||
| 195 | USB_XU_DIRECT_MONITORING = 0xe305, | ||
| 196 | USB_XU_METERING = 0xe306 | ||
| 197 | }; | ||
| 198 | enum { | ||
| 199 | USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/ | ||
| 200 | USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */ | ||
| 201 | USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */ | ||
| 202 | USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */ | ||
| 203 | }; | ||
| 189 | 204 | ||
| 190 | /* | 205 | /* |
| 191 | * manual mapping of mixer names | 206 | * manual mapping of mixer names |
| @@ -1330,7 +1345,32 @@ static struct procunit_info procunits[] = { | |||
| 1330 | { USB_PROC_DCR, "DCR", dcr_proc_info }, | 1345 | { USB_PROC_DCR, "DCR", dcr_proc_info }, |
| 1331 | { 0 }, | 1346 | { 0 }, |
| 1332 | }; | 1347 | }; |
| 1333 | 1348 | /* | |
| 1349 | * predefined data for extension units | ||
| 1350 | */ | ||
| 1351 | static struct procunit_value_info clock_rate_xu_info[] = { | ||
| 1352 | { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, | ||
| 1353 | { 0 } | ||
| 1354 | }; | ||
| 1355 | static struct procunit_value_info clock_source_xu_info[] = { | ||
| 1356 | { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, | ||
| 1357 | { 0 } | ||
| 1358 | }; | ||
| 1359 | static struct procunit_value_info spdif_format_xu_info[] = { | ||
| 1360 | { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN }, | ||
| 1361 | { 0 } | ||
| 1362 | }; | ||
| 1363 | static struct procunit_value_info soft_limit_xu_info[] = { | ||
| 1364 | { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN }, | ||
| 1365 | { 0 } | ||
| 1366 | }; | ||
| 1367 | static struct procunit_info extunits[] = { | ||
| 1368 | { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info }, | ||
| 1369 | { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info }, | ||
| 1370 | { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info }, | ||
| 1371 | { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info }, | ||
| 1372 | { 0 } | ||
| 1373 | }; | ||
| 1334 | /* | 1374 | /* |
| 1335 | * build a processing/extension unit | 1375 | * build a processing/extension unit |
| 1336 | */ | 1376 | */ |
| @@ -1391,8 +1431,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
| 1391 | cval->max = dsc[15]; | 1431 | cval->max = dsc[15]; |
| 1392 | cval->res = 1; | 1432 | cval->res = 1; |
| 1393 | cval->initialized = 1; | 1433 | cval->initialized = 1; |
| 1394 | } else | 1434 | } else { |
| 1395 | get_min_max(cval, valinfo->min_value); | 1435 | if (type == USB_XU_CLOCK_RATE) { |
| 1436 | /* E-Mu USB 0404/0202/TrackerPre | ||
| 1437 | * samplerate control quirk | ||
| 1438 | */ | ||
| 1439 | cval->min = 0; | ||
| 1440 | cval->max = 5; | ||
| 1441 | cval->res = 1; | ||
| 1442 | cval->initialized = 1; | ||
| 1443 | } else | ||
| 1444 | get_min_max(cval, valinfo->min_value); | ||
| 1445 | } | ||
| 1396 | 1446 | ||
| 1397 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); | 1447 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); |
| 1398 | if (! kctl) { | 1448 | if (! kctl) { |
| @@ -1433,7 +1483,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un | |||
| 1433 | 1483 | ||
| 1434 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1484 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) |
| 1435 | { | 1485 | { |
| 1436 | return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit"); | 1486 | return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); |
| 1437 | } | 1487 | } |
| 1438 | 1488 | ||
| 1439 | 1489 | ||
| @@ -2109,6 +2159,23 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) | |||
| 2109 | return 0; | 2159 | return 0; |
| 2110 | } | 2160 | } |
| 2111 | 2161 | ||
| 2162 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | ||
| 2163 | unsigned char samplerate_id) | ||
| 2164 | { | ||
| 2165 | struct usb_mixer_interface *mixer; | ||
| 2166 | struct usb_mixer_elem_info *cval; | ||
| 2167 | int unitid = 12; /* SamleRate ExtensionUnit ID */ | ||
| 2168 | |||
| 2169 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
| 2170 | cval = mixer->id_elems[unitid]; | ||
| 2171 | if (cval) { | ||
| 2172 | set_cur_ctl_value(cval, cval->control << 8, samplerate_id); | ||
| 2173 | snd_usb_mixer_notify_id(mixer, unitid); | ||
| 2174 | } | ||
| 2175 | break; | ||
| 2176 | } | ||
| 2177 | } | ||
| 2178 | |||
| 2112 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | 2179 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, |
| 2113 | int ignore_error) | 2180 | int ignore_error) |
| 2114 | { | 2181 | { |
