aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorSergiy Kovalchuk <cnb_zerg@yahoo.com>2009-12-27 12:13:41 -0500
committerTakashi Iwai <tiwai@suse.de>2009-12-28 06:29:39 -0500
commit7d2b451e65d255427c108e990507964ac39c13ee (patch)
tree86e977405ae88b08fa74dff3202c9f88207dfacb /sound
parent44eba3e82b35ae796826a65d8040001582adc10a (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.c49
-rw-r--r--sound/usb/usbaudio.h13
-rw-r--r--sound/usb/usbmixer.c75
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 */
1277static 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 */
1276static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) 1317static 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*/
212enum {
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);
233void snd_usbmidi_input_start(struct list_head* p); 243void snd_usbmidi_input_start(struct list_head* p);
234void snd_usbmidi_disconnect(struct list_head *p); 244void snd_usbmidi_disconnect(struct list_head *p);
235 245
246void 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*/
190enum {
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};
198enum {
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 */
1351static struct procunit_value_info clock_rate_xu_info[] = {
1352 { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 },
1353 { 0 }
1354};
1355static struct procunit_value_info clock_source_xu_info[] = {
1356 { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN },
1357 { 0 }
1358};
1359static struct procunit_value_info spdif_format_xu_info[] = {
1360 { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN },
1361 { 0 }
1362};
1363static struct procunit_value_info soft_limit_xu_info[] = {
1364 { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN },
1365 { 0 }
1366};
1367static 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
1434static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) 1484static 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
2162void 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
2112int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, 2179int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
2113 int ignore_error) 2180 int ignore_error)
2114{ 2181{