[alsa-devel] [PATCH 1/1] Added functionality for E-mu 0404USB/0202USB/TrackerPre
Zerg Cannibal
cnb_zerg at yahoo.com
Mon Dec 21 21:39:27 CET 2009
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.
Patch is based on Mac OS-X driver (http://sourceforge.net/projects/zaudiodrivermac/) and successfully tested by Ubuntu community users for 0404usb and 0202usb.
Signed-off-by: CannibalZerg <cnb_zerg at yahoo.com>
---
sound/usb/usbaudio.c | 44 ++++++++++++++++++++++++++++++
sound/usb/usbaudio.h | 2 +
sound/usb/usbmixer.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 115 insertions(+), 4 deletions(-)
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 31b63ea..d8eb029 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -1271,6 +1271,42 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface,
}
/*
+ * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device,
+ * not for interface.
+*/
+static void set_format_emu_quirk(struct snd_usb_substream *subs, struct audioformat *fmt)
+{
+ unsigned char emu_samplerate_id = 0;
+
+ /* When capture is active sample rate shouldn't be changed by playback substream*/
+ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1)
+ return;
+ }
+
+ switch (fmt->rate_min) {
+ case 48000:
+ emu_samplerate_id = 1;
+ break;
+ case 88200:
+ emu_samplerate_id = 2;
+ break;
+ case 96000:
+ emu_samplerate_id = 3;
+ break;
+ case 176400:
+ emu_samplerate_id = 4;
+ break;
+ case 192000:
+ emu_samplerate_id = 5;
+ break;
+ default:
+ emu_samplerate_id = 0;
+ }
+ snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id);
+}
+
+/*
* find a matching format and set up the interface
*/
static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
@@ -1383,6 +1419,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
subs->cur_audiofmt = fmt;
+ switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */
+ case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */
+ case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */
+ set_format_emu_quirk(subs, fmt);
+ break;
+ }
+
#if 0
printk(KERN_DEBUG
"setting done: format = %d, rate = %d..%d, channels = %d\n",
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 9826337..8558773 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -233,6 +233,8 @@ void snd_usbmidi_input_stop(struct list_head* p);
void snd_usbmidi_input_start(struct list_head* p);
void snd_usbmidi_disconnect(struct list_head *p);
+void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, unsigned char samplerate_id);
+
/*
* retrieve usb_interface descriptor from the host interface
* (conditional for compatibility with the older API)
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index c998220..400208c 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -186,6 +186,21 @@ enum {
USB_PROC_DCR_RELEASE = 6,
};
+/*E-mu 0202(0404) eXtension Unit(XU) control*/
+enum {
+ USB_XU_CLOCK_RATE = 0xe301,
+ USB_XU_CLOCK_SOURCE = 0xe302,
+ USB_XU_DIGITAL_IO_STATUS = 0xe303,
+ USB_XU_DEVICE_OPTIONS = 0xe304,
+ USB_XU_DIRECT_MONITORING = 0xe305,
+ USB_XU_METERING = 0xe306
+};
+enum {
+ USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/
+ USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */
+ USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */
+ USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */
+};
/*
* manual mapping of mixer names
@@ -1330,7 +1345,32 @@ static struct procunit_info procunits[] = {
{ USB_PROC_DCR, "DCR", dcr_proc_info },
{ 0 },
};
-
+/*
+ * predefined data for extension units
+ */
+static struct procunit_value_info clock_rate_xu_info[] = {
+ { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0},
+ { 0 }
+};
+static struct procunit_value_info clock_source_xu_info[] = {
+ { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN},
+ { 0 }
+};
+static struct procunit_value_info spdif_format_xu_info[] = {
+ { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN},
+ { 0 }
+};
+static struct procunit_value_info soft_limit_xu_info[] = {
+ { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN},
+ { 0 }
+};
+static struct procunit_info extunits[] = {
+ { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info },
+ { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info },
+ { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info },
+ { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info },
+ { 0 }
+};
/*
* build a processing/extension unit
*/
@@ -1391,8 +1431,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
cval->max = dsc[15];
cval->res = 1;
cval->initialized = 1;
- } else
- get_min_max(cval, valinfo->min_value);
+ } else {
+ if (type == USB_XU_CLOCK_RATE) {
+ /*E-Mu USB 0404/0202/TrackerPre samplerate control quirk*/
+ cval->min = 0;
+ cval->max = 5;
+ cval->res = 1;
+ cval->initialized = 1;
+ } else
+ get_min_max(cval, valinfo->min_value);
+ }
kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
if (! kctl) {
@@ -1433,7 +1481,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un
static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc)
{
- return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit");
+ return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit");
}
@@ -2109,6 +2157,23 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
return 0;
}
+void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, unsigned char samplerate_id)
+{
+ struct usb_mixer_interface *mixer;
+ struct list_head *p;
+ struct usb_mixer_elem_info *cval;
+ int unitid = 12; /*SampleRate ExtensionUnit ID*/
+ list_for_each(p, &chip->mixer_list) {
+ mixer = list_entry(p, struct usb_mixer_interface, list);
+ cval = mixer->id_elems[unitid];
+ if (cval) {
+ set_cur_ctl_value(cval, cval->control << 8, samplerate_id);
+ snd_usb_mixer_notify_id(mixer, unitid);
+ }
+ break;
+ }
+}
+
int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
int ignore_error)
{
--
1.6.5.6
More information about the Alsa-devel
mailing list