[ALSA] Fixes audiophile usb analog capture with the new device_setup parameter

Modules: Documentation,USB generic driver

The patch adds the 'device_setup' module parameter and a specific
quirk to correctly initialize the audiophile usb device: this fixes
the distorted sound bug on the Analog capture port. Backward
compatibility is achieved by simply omitting the new parameter.

Signed-off-by: Thibault LE MEUR <Thibault.LeMeur@supelec.fr>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 1065bee..f947c4b 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1411,6 +1411,9 @@
 
     vid             - Vendor ID for the device (optional)
     pid             - Product ID for the device (optional)
+    device_setup    - Device specific magic number (optional)
+                    - Influence depends on the device
+                    - Default: 0x0000 
 
     This module supports multiple devices, autoprobe and hotplugging.
 
diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
new file mode 100644
index 0000000..3ba45ad
--- /dev/null
+++ b/Documentation/sound/alsa/Audiophile-Usb.txt
@@ -0,0 +1,330 @@
+	Guide to using M-Audio Audiophile USB with ALSA and Jack	v1.1
+	========================================================
+
+	    Thibault Le Meur <Thibault.LeMeur@supelec.fr>
+
+This document is a guide to using the M-Audio Audiophile USB (tm) device with 
+ALSA and JACK.
+
+1 - Audiophile USB Specs and correct usage
+==========================================
+This part is a reminder of important facts about the functions and limitations 
+of the device.
+
+The device has 4 audio interfaces, and 2 MIDI ports:
+ * Analog Stereo Input (Ai)
+ * Analog Stereo Output (Ao)
+ * Digital Stereo Input (Di)
+ * Digital Stereo Output (Do)
+ * Midi In (Mi)
+ * Midi Out (Mo)
+
+The internal DAC/ADC has the following caracteristics:
+* sample depth of 16 or 24 bits
+* sample rate from 8kHz to 96kHz
+* Two ports can't use different sample depths at the same time.Moreover, the 
+Audiophile USB documentation gives the following Warning: "Please exit any 
+audio application running before switching between bit depths"
+
+Due to the USB 1.1 bandwidth limitation, a limited number of interfaces can be 
+activated at the same time depending on the audio mode selected:
+ * 16-bit/48kHz ==> 4 channels in/ 4 channels out
+   - Ai+Ao+Di+Do
+ * 24-bit/48kHz ==> 4 channels in/2 channels out, 
+                    or 2 channels in/4 channels out
+   - Ai+Ao+Do or Ai+Di+Ao or Ai+Di+Do or Di+Ao+Do
+ * 24-bit/96kHz ==> 2 channels in, or 2 channels out (half duplex only)
+   - Ai or Ao or Di or Do
+
+Important facts about the Digital interface:
+--------------------------------------------
+ * The Do port additionnaly supports surround-encoded AC-3 and DTS passthrough, 
+though I haven't tested it under linux
+   - Note that in this setup only the Do interface can be enabled
+ * Apart from recording an audio digital stream, enabling the Di port is a way 
+to syncrhonize the device to an external sample clock
+   - As a consequence, the Di port must be enable only if an active Digital 
+source is connected
+   - Enabling Di when no digital source is connected can result in a 
+synchronization error (for instance sound played at an odd sample rate)
+
+
+2 - Audiophile USB support in ALSA
+==================================
+
+2.1 - MIDI ports
+----------------
+The Audiophile USB MIDI ports will be automatically supported once the 
+following modules have been loaded:
+ * snd-usb-audio
+ * snd-seq
+ * snd-seq-midi
+
+No additionnal setting is required.
+
+2.2 - Audio ports
+-----------------
+
+Audio functions of the Audiophile USB device are handled by the snd-usb-audio 
+module. This module can work in a default mode (without any device-specific 
+parameter), or in an advanced mode with the device-specific parameter called 
+"device_setup".
+
+2.2.1 - Default Alsa driver mode
+
+The default behaviour of the snd-usb-audio driver is to parse the device 
+capabilities at startup and enable all functions inside the device (including 
+all ports at any sample rates and any sample depths supported). This approach 
+has the advantage to let the driver easily switch from sample rates/depths 
+automatically according to the need of the application claiming the device.
+
+In this case the Audiophile ports are mapped to alsa pcm devices in the 
+following way (I suppose the device's index is 1):
+ * hw:1,0 is Ao in playback and Di in capture
+ * hw:1,1 is Do in playback and Ai in capture
+ * hw:1,2 is Do in AC3/DTS passthrough mode
+
+You must note as well that the device uses Big Endian byte encoding so that 
+supported audio format are S16_BE  for 16-bit depth modes and S24_3BE for 
+24-bits depth mode. One exception is the hw:1,2 port which is Little Endian 
+compliant and thus uses S16_LE.
+
+Examples:
+ * playing a S24_3BE encoded raw file to the Ao port
+   % aplay -D hw:1,0 -c2 -t raw -r48000 -fS24_3BE test.raw
+ * recording a  S24_3BE encoded raw file from the Ai port
+   % arecord -D hw:1,1 -c2  -t raw -r48000 -fS24_3BE test.raw
+ * playing a S16_BE encoded raw file to the Do port
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test.raw
+
+If you're happy with the default Alsa driver setup and don't experience any 
+issue with this mode, then you can skip the following chapter.
+
+2.2.2 - Advanced module setup
+
+Due to the hardware constraints described above, the device initialization made 
+by the Alsa driver in default mode may result in a corrupted state of the 
+device. For instance, a particularly annoying issue is that the sound captured 
+from the Ai port sounds distorted (as if boosted with an excessive high volume 
+gain).
+
+For people having this problem, the snd-usb-audio module has a new module 
+parameter called "device_setup".
+
+2.2.2.1 - Initializing the working mode of the Audiohile USB
+
+As far as the Audiohile USB device is concerned, this value let the user 
+specify:
+ * the sample depth
+ * the sample rate
+ * whether the Di port is used or not 
+
+Here is a list of supported device_setup values for this device:
+ * device_setup=0x00 (or omitted)
+   - Alsa driver default mode
+   - maintains backward compatibility with setups that do not use this 
+     parameter by not introducing any change
+   - results sometimes in corrupted sound as decribed earlier
+ * device_setup=0x01
+   - 16bits 48kHz mode with Di disabled
+   - Ai,Ao,Do can be used at the same time
+   - hw:1,0 is not available in capture mode
+   - hw:1,2 is not available
+ * device_setup=0x11
+   - 16bits 48kHz mode with Di enabled
+   - Ai,Ao,Di,Do can be used at the same time
+   - hw:1,0 is available in capture mode
+   - hw:1,2 is not available
+ * device_setup=0x09
+   - 24bits 48kHz mode with Di disabled
+   - Ai,Ao,Do can be used at the same time
+   - hw:1,0 is not available in capture mode
+   - hw:1,2 is not available
+ * device_setup=0x19
+   - 24bits 48kHz mode with Di enabled
+   - 3 ports from {Ai,Ao,Di,Do} can be used at the same time
+   - hw:1,0 is available in capture mode and an active digital source must be 
+     connected to Di
+   - hw:1,2 is not available
+ * device_setup=0x0D or 0x10
+   - 24bits 96kHz mode
+   - Di is enabled by default for this mode but does not need to be connected 
+     to an active source
+   - Only 1 port from {Ai,Ao,Di,Do} can be used at the same time
+   - hw:1,0 is available in captured mode
+   - hw:1,2 is not available
+ * device_setup=0x03
+   - 16bits 48kHz mode with only the Do port enabled 
+   - AC3 with DTS passthru (not tested)
+   - Caution with this setup the Do port is mapped to the pcm device hw:1,0
+
+2.2.2.2 - Setting and switching configurations with the device_setup parameter
+
+The parameter can be given:
+ * By manually probing the device (as root):
+   # modprobe -r snd-usb-audio
+   # modprobe snd-usb-audio index=1 device_setup=0x09
+ * Or while configuring the modules options in your modules configuration file
+   - For Fedora distributions, edit the /etc/modprobe.conf file:
+       alias snd-card-1 snd-usb-audio
+       options snd-usb-audio index=1 device_setup=0x09
+
+IMPORTANT NOTE WHEN SWITCHING CONFIGURATION:
+-------------------------------------------
+ * You may need to _first_ intialize the module with the correct device_setup 
+   parameter and _only_after_ turn on the Audiophile USB device
+ * This is especially true when switching the sample depth:
+   - first trun off the device
+   - de-register the snd-usb-audio module
+   - change the device_setup parameter (by either manually reprobing the module 
+     or changing modprobe.conf)
+   - turn on the device
+
+2.2.2.3 - Setting and switching configurations with the device_setup parameter
+
+If you want to understand the device_setup magic numbers for the Audiophile 
+USB, you need some very basic understanding of binary computation. However, 
+this is not required to use the parameter and you may skip thi section.
+
+The device_setup is one byte long and its structure is the following:
+
+       +---+---+---+---+---+---+---+---+
+       | b7| b6| b5| b4| b3| b2| b1| b0|
+       +---+---+---+---+---+---+---+---+
+       | 0 | 0 | 0 | Di|24B|96K|DTS|SET|
+       +---+---+---+---+---+---+---+---+
+
+Where:
+ * b0 is the "SET" bit
+   - it MUST be set if device_setup is initialized 
+ * b1 is the "DTS" bit
+   - it is set only for Digital output with DTS/AC3
+   - this setup is not tested
+ * b2 is the Rate selection flag
+   - When set to "1" the rate range is 48.1-96kHz
+   - Otherwise the sample rate range is 8-48kHz
+ * b3 is the bit depth selection flag
+   - When set to "1" samples are 24bits long
+   - Otherwise they are 16bits long
+   - Note that b2 implies b3 as the 96kHz mode is only supported for 24 bits 
+     samples
+ * b4 is the Digital input flag
+   - When set to "1" the device assumes that an active digital source is 
+     connected 
+   - You shouldn't enable Di if no source is seen on the port (this leads to 
+     synchronization issues)
+   - b4 is implied by b2 (since only one port is enabled at a time no synch 
+     error can occur) 
+ * b5 to b7 are reserved for future uses, and must be set to "0"
+   - might become Ao, Do, Ai, for b7, b6, b4 respectively
+
+Caution:
+ * there is no check on the value you will give to device_setup
+   - for instance choosing 0x05 (16bits 96kHz) will fail back to 0x09 since 
+     b2 implies b3. But _there_will_be_no_warning_ in /var/log/messages
+ * Hardware constraints due to the USB bus limitation aren't checked
+   - choosing b2 will prepare all interfaces for 24bits/96kHz but you'll
+     only be able to use one at the same time
+
+2.2.3 -  Technical Details for Audiophile Usb 
+
+You may safely skip this section if you're not interrested in driver 
+development.
+
+This section describes some internals aspect of the device and summarize the 
+data I got by usb-snooping the windows and linux drivers.
+
+The M-Audio Audiophile USB has 7 Usb Interfaces:
+a "USB interface":
+ * Usb Interface nb.0
+ * Usb Interface nb.1
+   - Audio Control function
+ * Usb Interface nb.2
+   - Analog Output
+ * Usb Interface nb.3
+   - Digital Output
+ * Usb Interface nb.4
+   - Analog Input
+ * Usb Interface nb.5
+   - Digital Input
+ * Usb Interface nb.6
+   - MIDI interface compliant with the MIDIMAN quirk 
+
+Each interface has 5 altsettings (AltSet 1,2,3,4,5) except:
+ * Interface 3 (Digital Out) has an extra Alset nb.6 
+ * Interface 5 (Digital In) does not have Alset nb.3 and 5 
+
+Here is a short description of the AltSettings capabilities:
+ * AltSettings 1 corresponds to
+  - 24-bit depth, 48.1-96kHz sample mode
+  - Adaptive playback (Ao and Do), Synch capture (Ai), or Asynch capture (Di)
+ * AltSettings 2 corresponds to
+  - 24-bit depth, 8-48kHz sample mode
+  - Asynch capture and playback  (Ao,Ai,Do,Di)
+ * AltSettings 3 corresponds to
+  - 24-bit depth, 8-48kHz sample mode
+  - Synch capture (Ai) and Adaptive playback (Ao,Do)
+ * AltSettings 4 corresponds to
+  - 16-bit depth, 8-48kHz sample mode
+  - Asynch capture and playback  (Ao,Ai,Do,Di)
+ * AltSettings 5 corresponds to
+  - 16-bit depth, 8-48kHz sample mode
+  - Synch capture (Ai) and Adaptive playback (Ao,Do)
+ * AltSettings 6 corresponds to
+  - 16-bit depth, 8-48kHz sample mode
+  - Synch playback (Do), audio format type III IEC1937_AC-3
+
+In order to ensure a correct intialization of the device, the driver 
+_must_know_ how the device will be used:
+ * if DTS is choosen, only Interface 2 with AltSet nb.6 must be
+   registered
+ * if 96KHz only AltSets nb.1 of each interface must be selected
+ * if samples are using 24bits/48KHz then AltSet 2 must me used if
+   Digital input is connected, and only AltSet nb.3 if Digital input
+   is not connected
+ * if samples are using 16bits/48KHz then AltSet 4 must me used if
+   Digital input is connected, and only AltSet nb.5 if Digital input
+   is not connected
+
+When device_setup is given as a parameter to the snd-usb-audio module, the 
+parse_audio_enpoint function uses a quirk called 
+"audiophile_skip_setting_quirk" in order to prevent AltSettings not 
+corresponding to device_setup from being registered in the driver.
+
+3 - Audiophile USB and Jack support
+===================================
+
+This section deals with support of the Audiophile USB device in Jack.
+The main issue regarding this support is that the device is Big Endian 
+compliant.
+
+3.1 - Using the plug alsa plugin
+--------------------------------
+
+Jack doesn't directly support big endian devices. Thus, one way to have support 
+for this device with Alsa is to use the Alsa "plug" converter.
+
+For instance here is one way to run Jack with 2 playback channels on Ao and 2 
+capture channels from Ai:
+  % jackd -R -dalsa -dplughw:1 -r48000 -p256 -n2 -D -Cplughw:1,1
+
+
+However you may see the following warning message:
+"You appear to be using the ALSA software "plug" layer, probably a result of 
+using the "default" ALSA device. This is less efficient than it could be. 
+Consider using a hardware device instead rather than using the plug layer."
+
+
+3.2 - Patching alsa to use direct pcm device
+-------------------------------------------
+A patch for Jack by Andreas Steinmetz adds support for Big Endian devices. 
+However it has not been included in the CVS tree.
+
+You can find it at the following URL:
+http://sourceforge.net/tracker/index.php?func=detail&aid=1289682&group_id=39687&
+atid=425939
+
+After having applied the patch you can run jackd with the following command 
+line:
+# /usr/local/bin/jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
+
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 6fad2c4..4e614ac 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -70,6 +70,7 @@
 static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
 static int nrpacks = 4;		/* max. number of packets per urb */
 static int async_unlink = 1;
+static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -85,6 +86,8 @@
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
+module_param_array(device_setup, int, NULL, 0444);
+MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
 
 
 /*
@@ -2547,6 +2550,8 @@
 	return 0;
 }
 
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+					 int iface, int altno);
 static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
 	struct usb_device *dev;
@@ -2581,6 +2586,12 @@
 		stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
 			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
 		altno = altsd->bAlternateSetting;
+	
+		/* audiophile usb: skip altsets incompatible with device_setup
+		 */
+		if (chip->usb_id == USB_ID(0x0763, 0x2003) && 
+		    audiophile_skip_setting_quirk(chip, iface_no, altno))
+			continue;
 
 		/* get audio formats */
 		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL);
@@ -2675,7 +2686,7 @@
 			continue;
 		}
 
-		snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint);
+		snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
 		err = add_audio_endpoint(chip, stream, fp);
 		if (err < 0) {
 			kfree(fp->rate_table);
@@ -3083,6 +3094,45 @@
 	return 0;
 }
 
+/*
+ * Setup quirks
+ */
+#define AUDIOPHILE_SET			0x01 /* if set, parse device_setup */
+#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */
+#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
+#define AUDIOPHILE_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */
+#define AUDIOPHILE_SET_DI		0x10 /* if set, enable Digital Input */
+#define AUDIOPHILE_SET_MASK		0x1F /* bit mask for setup value */
+#define AUDIOPHILE_SET_24B_48K_DI	0x19 /* value for 24bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_24B_48K_NOTDI	0x09 /* value for 24bits+48KHz+No Digital Input */
+#define AUDIOPHILE_SET_16B_48K_DI	0x11 /* value for 16bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_16B_48K_NOTDI	0x01 /* value for 16bits+48KHz+No Digital Input */
+
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+					 int iface, int altno)
+{
+	if (device_setup[chip->index] & AUDIOPHILE_SET) {
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
+		    && altno != 6)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_96K)
+		    && altno != 1)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_24B_48K_DI && altno != 2)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_16B_48K_DI && altno != 4)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5)
+			return 1; /* skip this altsetting */
+	}	
+	return 0; /* keep this altsetting */
+}
 
 /*
  * audio-interface quirks