sound: usb: Add support for parsing AudioStreaming intf for BADD devices

BADD(Basic Audio Device Definition) is a subset of UAC3
specifications. It defines standard profiles which provide
specific attributes of class descriptors. BADD audio device
provides profile id and BADD supporting host will infer
attributes from profile-id.

Currently USB Audio Host driver has support for UAC1
and UAC2 devices. To handle BADD 3.0 devices, AudioControl
and AudioStreaming Interfaces have to be properly parsed.
The Host has to derive all class-specific information based
on the profile ID that the device exposes. Add support for
parsing the AudioStreaming interfaces exposed by the device.

Change-Id: I726bbb735708fe8e395011c7228a73d5f65c092d
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
diff --git a/sound/usb/card.c b/sound/usb/card.c
index ccf06de..eaf18aa 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -45,6 +45,7 @@
 #include <linux/usb/audio.h>
 #include <linux/usb/audio-v2.h>
 #include <linux/module.h>
+#include <linux/usb/audio-v3.h>
 
 #include <sound/control.h>
 #include <sound/core.h>
@@ -285,7 +286,6 @@
 	struct usb_host_interface *host_iface;
 	struct usb_interface_descriptor *altsd;
 	struct usb_interface *usb_iface;
-	void *control_header;
 	int i, protocol;
 
 	usb_iface = usb_ifnum_to_if(dev, ctrlif);
@@ -302,16 +302,13 @@
 		return -EINVAL;
 	}
 
-	control_header = snd_usb_find_csint_desc(host_iface->extra,
-						 host_iface->extralen,
-						 NULL, UAC_HEADER);
 	altsd = get_iface_desc(host_iface);
 	protocol = altsd->bInterfaceProtocol;
 
-	if (!control_header) {
-		dev_err(&dev->dev, "cannot find UAC_HEADER\n");
-		return -EINVAL;
-	}
+	/*
+	 * UAC 1.0 devices use AC HEADER Desc for linking AS interfaces;
+	 * UAC 2.0 and 3.0 devices use IAD for linking AS interfaces
+	 */
 
 	switch (protocol) {
 	default:
@@ -321,8 +318,17 @@
 		/* fall through */
 
 	case UAC_VERSION_1: {
-		struct uac1_ac_header_descriptor *h1 = control_header;
+		void *control_header;
+		struct uac1_ac_header_descriptor *h1;
 
+		control_header = snd_usb_find_csint_desc(host_iface->extra,
+					host_iface->extralen, NULL, UAC_HEADER);
+		if (!control_header) {
+			dev_err(&dev->dev, "cannot find UAC_HEADER\n");
+			return -EINVAL;
+		}
+
+		h1 = control_header;
 		if (!h1->bInCollection) {
 			dev_info(&dev->dev, "skipping empty audio interface (v1)\n");
 			return -EINVAL;
@@ -339,7 +345,8 @@
 		break;
 	}
 
-	case UAC_VERSION_2: {
+	case UAC_VERSION_2:
+	case UAC_VERSION_3: {
 		struct usb_interface_assoc_descriptor *assoc =
 						usb_iface->intf_assoc;
 		if (!assoc) {
@@ -358,7 +365,8 @@
 		}
 
 		if (!assoc) {
-			dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n");
+			dev_err(&dev->dev, "Audio class V%d interfaces need an interface association\n",
+					protocol);
 			return -EINVAL;
 		}
 
@@ -606,6 +614,15 @@
 	struct usb_host_interface *alts;
 	int ifnum;
 	u32 id;
+	struct usb_interface_assoc_descriptor *assoc;
+
+	assoc = intf->intf_assoc;
+	if (assoc && assoc->bFunctionClass == USB_CLASS_AUDIO &&
+	    assoc->bFunctionProtocol == UAC_VERSION_3 &&
+	    assoc->bFunctionSubClass == FULL_ADC_PROFILE) {
+		dev_info(&dev->dev, "No support for full-fledged ADC 3.0 yet!!\n");
+		return -EINVAL;
+	}
 
 	alts = &intf->altsetting[0];
 	ifnum = get_iface_desc(alts)->bInterfaceNumber;