ALSA: usb-mixer: Add support for Audio Class v2.0

USB Audio Class v2.0 compliant devices have different descriptors and a
different way of setting/getting min/max/res/cur properties. This patch
adds support for them.

Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 3b8560d..0952231 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -43,6 +43,53 @@
 	__u8 baCSourceID[];
 } __attribute__((packed));
 
+/* 4.7.2.4 Input terminal descriptor */
+
+struct uac2_input_terminal_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bTerminalID;
+	__u16 wTerminalType;
+	__u8 bAssocTerminal;
+	__u8 bCSourceID;
+	__u8 bNrChannels;
+	__u32 bmChannelConfig;
+	__u8 iChannelNames;
+	__u16 bmControls;
+	__u8 iTerminal;
+} __attribute__((packed));
+
+/* 4.7.2.5 Output terminal descriptor */
+
+struct uac2_output_terminal_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bTerminalID;
+	__u16 wTerminalType;
+	__u8 bAssocTerminal;
+	__u8 bSourceID;
+	__u8 bCSourceID;
+	__u16 bmControls;
+	__u8 iTerminal;
+} __attribute__((packed));
+
+
+
+/* 4.7.2.8 Feature Unit Descriptor */
+
+struct uac2_feature_unit_descriptor {
+	__u8 bLength;
+	__u8 bDescriptorType;
+	__u8 bDescriptorSubtype;
+	__u8 bUnitID;
+	__u8 bSourceID;
+	/* bmaControls is actually u32,
+	 * but u8 is needed for the hybrid parser */
+	__u8 bmaControls[0]; /* variable length */
+} __attribute__((packed));
+
 /* 4.9.2 Class-Specific AS Interface Descriptor */
 
 struct uac_as_header_descriptor_v2 {
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index bc78a83..905a87c 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -196,20 +196,33 @@
 	return desc->baSourceID[desc->bNrInPins];
 }
 
-static inline __u16 uac_mixer_unit_wChannelConfig(struct uac_mixer_unit_descriptor *desc)
+static inline __u32 uac_mixer_unit_wChannelConfig(struct uac_mixer_unit_descriptor *desc,
+						  int protocol)
 {
-	return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
-		desc->baSourceID[desc->bNrInPins + 1];
+	if (protocol == UAC_VERSION_1)
+		return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
+			desc->baSourceID[desc->bNrInPins + 1];
+	else
+		return  (desc->baSourceID[desc->bNrInPins + 4] << 24) |
+			(desc->baSourceID[desc->bNrInPins + 3] << 16) |
+			(desc->baSourceID[desc->bNrInPins + 2] << 8)  |
+			(desc->baSourceID[desc->bNrInPins + 1]);
 }
 
-static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor *desc)
+static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor *desc,
+						int protocol)
 {
-	return desc->baSourceID[desc->bNrInPins + 3];
+	return (protocol == UAC_VERSION_1) ?
+		desc->baSourceID[desc->bNrInPins + 3] :
+		desc->baSourceID[desc->bNrInPins + 5];
 }
 
-static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc)
+static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc,
+					      int protocol)
 {
-	return &desc->baSourceID[desc->bNrInPins + 4];
+	return (protocol == UAC_VERSION_1) ?
+		&desc->baSourceID[desc->bNrInPins + 4] :
+		&desc->baSourceID[desc->bNrInPins + 6];
 }
 
 static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc)
@@ -267,36 +280,54 @@
 	return desc->baSourceID[desc->bNrInPins];
 }
 
-static inline __u16 uac_processing_unit_wChannelConfig(struct uac_processing_unit_descriptor *desc)
+static inline __u32 uac_processing_unit_wChannelConfig(struct uac_processing_unit_descriptor *desc,
+						       int protocol)
 {
-	return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
-		desc->baSourceID[desc->bNrInPins + 1];
+	if (protocol == UAC_VERSION_1)
+		return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
+			desc->baSourceID[desc->bNrInPins + 1];
+	else
+		return  (desc->baSourceID[desc->bNrInPins + 4] << 24) |
+			(desc->baSourceID[desc->bNrInPins + 3] << 16) |
+			(desc->baSourceID[desc->bNrInPins + 2] << 8)  |
+			(desc->baSourceID[desc->bNrInPins + 1]);
 }
 
-static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_descriptor *desc)
+static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_descriptor *desc,
+						     int protocol)
 {
-	return desc->baSourceID[desc->bNrInPins + 3];
+	return (protocol == UAC_VERSION_1) ?
+		desc->baSourceID[desc->bNrInPins + 3] :
+		desc->baSourceID[desc->bNrInPins + 5];
 }
 
-static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc)
+static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
+						    int protocol)
 {
-	return desc->baSourceID[desc->bNrInPins + 4];
+	return (protocol == UAC_VERSION_1) ?
+		desc->baSourceID[desc->bNrInPins + 4] :
+		desc->baSourceID[desc->bNrInPins + 6];
 }
 
-static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc)
+static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc,
+						   int protocol)
 {
-	return &desc->baSourceID[desc->bNrInPins + 5];
+	return (protocol == UAC_VERSION_1) ?
+		&desc->baSourceID[desc->bNrInPins + 5] :
+		&desc->baSourceID[desc->bNrInPins + 7];
 }
 
-static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc)
+static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc,
+						   int protocol)
 {
-	__u8 control_size = uac_processing_unit_bControlSize(desc);
+	__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
 	return desc->baSourceID[desc->bNrInPins + control_size];
 }
 
-static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc)
+static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc,
+						 int protocol)
 {
-	__u8 control_size = uac_processing_unit_bControlSize(desc);
+	__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
 	return &desc->baSourceID[desc->bNrInPins + control_size + 1];
 }