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 /sound | |
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>
Diffstat (limited to 'sound')
-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 | { |