This patch completes the support for Digidesign Mbox 1 sound card by adding capture.

The issue with this card is that it has two endpoints on the same
interface.  This patch creates a dual endpoint quirk.
The quirk interface needs a second audioformat struct for this to work
which I called ".data2".

Signed-off-by: Damien Zammit <damien@zamaudio.com>
---
 sound/usb/quirks-table.h |   25 +++++++++++++++
 sound/usb/quirks.c       |   79 ++++++++++++++++++++++++++++++++++++++++++++++
 sound/usb/usbaudio.h     |    2 ++
 3 files changed, 106 insertions(+)

diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index f652b10..0ea9f00 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2895,7 +2895,32 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 					.channels = 2,
 					.iface = 1,
 					.altsetting = 1,
+	                                .altset_idx = 1,
+					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+					.endpoint = 0x02,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_SYNC,
+					.maxpacksize = 0x130,
+					.rates = SNDRV_PCM_RATE_44100 |
+						 SNDRV_PCM_RATE_48000,
+					.rate_min = 44100,
+					.rate_max = 48000,
+					.nr_rates = 2,
+					.rate_table = (unsigned int[]) {
+						44100, 48000
+					}
+				},
+				.data2 = &(const struct audioformat) {
+					.formats = SNDRV_PCM_FMTBIT_S24_3BE,
+					.channels = 2,
+					.iface = 1,
+					.altsetting = 1,
 					.altset_idx = 1,
+					.attributes = 0x00,
+					.endpoint = 0x81,
+					.ep_attr = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+					.maxpacksize = 0x130,
+					.rates = SNDRV_PCM_RATE_44100 |
+						 SNDRV_PCM_RATE_48000,
 					.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
 					.endpoint = 0x02,
 					.ep_attr = 0x01,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 8973070..3ad6aa2 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -387,6 +387,84 @@ static int create_autodetect_quirks(struct snd_usb_audio *chip,
 }
 
 /*
+ * create 2 streams for an interface without proper descriptors but with dual endpoints
+ */
+static int create_fixed_dual_stream_quirk(struct snd_usb_audio *chip,
+				     struct usb_interface *iface,
+				     struct usb_driver *driver,
+				     const struct snd_usb_audio_quirk *quirk)
+{
+	struct audioformat *fp1;
+	struct audioformat *fp2;
+	struct usb_host_interface *alts;
+	int stream1, stream2, err;
+	unsigned *rate_table = NULL;
+
+	fp1 = kmemdup(quirk->data, sizeof(*fp1), GFP_KERNEL);
+	if (!fp1) {
+		snd_printk(KERN_ERR "cannot memdup 1\n");
+		return -ENOMEM;
+	}
+	fp2 = kmemdup(quirk->data2, sizeof(*fp2), GFP_KERNEL);
+	if (!fp2) {
+		snd_printk(KERN_ERR "cannot memdup 2\n");
+		return -ENOMEM;
+	}
+	if (fp1->nr_rates > MAX_NR_RATES) {
+		kfree(fp1);
+		kfree(fp2);
+		return -EINVAL;
+	}
+	if (fp1->nr_rates > 0) {
+		rate_table = kmemdup(fp1->rate_table,
+				     sizeof(int) * fp1->nr_rates, GFP_KERNEL);
+		if (!rate_table) {
+			kfree(fp1);
+			kfree(fp2);
+			return -ENOMEM;
+		}
+		fp1->rate_table = rate_table;
+		fp2->rate_table = rate_table;
+	}
+
+	stream1 = (fp1->endpoint & USB_DIR_IN)
+		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+	stream2 = (fp2->endpoint & USB_DIR_IN)
+		? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
+	err = snd_usb_add_audio_stream(chip, stream1, fp1);
+	if (err < 0) {
+		kfree(fp1);
+		kfree(fp2);
+		kfree(rate_table);
+		return err;
+	}
+	err = snd_usb_add_audio_stream(chip, stream2, fp2);
+	if (err < 0) {
+		kfree(fp1);
+		kfree(fp2);
+		kfree(rate_table);
+		return err;
+	}
+	if (fp1->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
+	    fp1->altset_idx >= iface->num_altsetting ||
+	    fp2->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
+	    fp2->altset_idx >= iface->num_altsetting
+	    ) {
+		kfree(fp1);
+		kfree(fp2);
+		kfree(rate_table);
+		return -EINVAL;
+	}
+	alts = &iface->altsetting[fp1->altset_idx];
+	fp1->datainterval = fp2->datainterval = snd_usb_parse_datainterval(chip, alts);
+	fp1->maxpacksize = fp2->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+	usb_set_interface(chip->dev, fp1->iface, 0);
+	snd_usb_init_pitch(chip, fp1->iface, alts, fp1);
+	snd_usb_init_sample_rate(chip, fp1->iface, alts, fp1, fp1->rate_max);
+	return 0;
+}
+
+/*
  * Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.  
  * The only way to detect the sample rate is by looking at wMaxPacketSize.
  */
@@ -528,6 +606,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
 		[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
 		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
 		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
+		[QUIRK_AUDIO_FIXED_DUAL_ENDPOINT] = create_fixed_dual_stream_quirk,
 		[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
 		[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
 		[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 5d2fe05..66fd867 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -86,6 +86,7 @@ enum quirk_type {
 	QUIRK_MIDI_FTDI,
 	QUIRK_AUDIO_STANDARD_INTERFACE,
 	QUIRK_AUDIO_FIXED_ENDPOINT,
+	QUIRK_AUDIO_FIXED_DUAL_ENDPOINT,
 	QUIRK_AUDIO_EDIROL_UAXX,
 	QUIRK_AUDIO_ALIGN_TRANSFER,
 	QUIRK_AUDIO_STANDARD_MIXER,
@@ -99,6 +100,7 @@ struct snd_usb_audio_quirk {
 	int16_t ifnum;
 	uint16_t type;
 	const void *data;
+	const void *data2;
 };
 
 #define combine_word(s)    ((*(s)) | ((unsigned int)(s)[1] << 8))
-- 
1.7.9.5

