diff options
| author | Hemant Kumar <hemantk@codeaurora.org> | 2017-06-07 19:08:33 -0700 |
|---|---|---|
| committer | Hemant Kumar <hemantk@codeaurora.org> | 2017-06-20 16:45:40 -0700 |
| commit | 58e69aad4486408aea8cffbabc4155fc85ac984c (patch) | |
| tree | 3e923233da4dc9a556132a874c5a29f45b6f592d /drivers/usb | |
| parent | e5223a9107e5ee250ad67ea4cb68eac7f1365e17 (diff) | |
usb: core: Add support to handle multi config audio device
A USB audio class 3.0 based device may express different audio interface
associations representing the same underlying hardware by using multiple
USB device configuration descriptors. Using BOS configuration summary
descriptor host software can choose which configuration to set. This is
done by going over list of configuration summary descriptors and selecting
the first available configuration supporting BADD subclass of UAC 3.0
protocol.
Change-Id: I548b362437deb525f952d4450cfae7420a524c65
Signed-off-by: Hemant Kumar <hemantk@codeaurora.org>
Diffstat (limited to 'drivers/usb')
| -rw-r--r-- | drivers/usb/core/generic.c | 38 |
1 files changed, 36 insertions, 2 deletions
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)); |
