summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-06-22 23:41:04 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2017-06-22 23:41:03 -0700
commit6c27d8d8b7fe8916d436b3db4ce67ef9ba9c8f23 (patch)
tree2481c9212cab610b65617a9932e3db3c6fff9032 /drivers
parentc7572d54add260a1416b8411ac6ac21ccdd6e441 (diff)
parent58e69aad4486408aea8cffbabc4155fc85ac984c (diff)
Merge "usb: core: Add support to handle multi config audio device"
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/config.c8
-rw-r--r--drivers/usb/core/generic.c38
2 files changed, 44 insertions, 2 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 325cbc9c35d8..b1298f093f13 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -949,6 +949,14 @@ int usb_get_bos_descriptor(struct usb_device *dev)
dev->bos->ss_id =
(struct usb_ss_container_id_descriptor *)buffer;
break;
+ case USB_CAP_TYPE_CONFIG_SUMMARY:
+ /* one such desc per configuration */
+ if (!dev->bos->num_config_summary_desc)
+ dev->bos->config_summary =
+ (struct usb_config_summary_descriptor *)buffer;
+
+ dev->bos->num_config_summary_desc++;
+ break;
default:
break;
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 358ca8dd784f..72d1109f13eb 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -19,6 +19,8 @@
#include <linux/usb.h>
#include <linux/usb/hcd.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v3.h>
#include "usb.h"
static inline const char *plural(int n)
@@ -40,6 +42,36 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
+static int usb_audio_max_rev_config(struct usb_host_bos *bos)
+{
+ int desc_cnt, func_cnt, numfunc;
+ int num_cfg_desc;
+ struct usb_config_summary_descriptor *conf_summary;
+
+ if (!bos || !bos->config_summary)
+ goto done;
+
+ conf_summary = bos->config_summary;
+ num_cfg_desc = bos->num_config_summary_desc;
+
+ for (desc_cnt = 0; desc_cnt < num_cfg_desc; desc_cnt++) {
+ numfunc = conf_summary->bNumFunctions;
+ for (func_cnt = 0; func_cnt < numfunc; func_cnt++) {
+ /* look for BADD 3.0 */
+ if (conf_summary->cs_info[func_cnt].bClass ==
+ USB_CLASS_AUDIO &&
+ conf_summary->cs_info[func_cnt].bProtocol ==
+ UAC_VERSION_3 &&
+ conf_summary->cs_info[func_cnt].bSubClass !=
+ FULL_ADC_PROFILE)
+ return conf_summary->bConfigurationValue;
+ }
+ }
+
+done:
+ return -EINVAL;
+}
+
int usb_choose_configuration(struct usb_device *udev)
{
int i;
@@ -130,7 +162,6 @@ int usb_choose_configuration(struct usb_device *udev)
best = c;
break;
}
-
/* If all the remaining configs are vendor-specific,
* choose the first one. */
else if (!best)
@@ -143,7 +174,10 @@ int usb_choose_configuration(struct usb_device *udev)
insufficient_power, plural(insufficient_power));
if (best) {
- i = best->desc.bConfigurationValue;
+ /* choose usb audio class preferred config if available */
+ i = usb_audio_max_rev_config(udev->bos);
+ if (i < 0)
+ i = best->desc.bConfigurationValue;
dev_dbg(&udev->dev,
"configuration #%d chosen from %d choice%s\n",
i, num_configs, plural(num_configs));