Merge "usb: core: Add support to handle multi config audio device"

This commit is contained in:
Linux Build Service Account 2017-06-22 23:41:04 -07:00 committed by Gerrit - the friendly Code Review server
commit 6c27d8d8b7
4 changed files with 69 additions and 2 deletions

View file

@ -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;
}

View file

@ -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));

View file

@ -330,6 +330,8 @@ struct usb_host_bos {
struct usb_ss_cap_descriptor *ss_cap;
struct usb_ssp_cap_descriptor *ssp_cap;
struct usb_ss_container_id_descriptor *ss_id;
struct usb_config_summary_descriptor *config_summary;
unsigned int num_config_summary_desc;
};
int __usb_get_extra_descriptor(char *buffer, unsigned size,

View file

@ -894,6 +894,29 @@ struct usb_ssp_cap_descriptor {
#define USB_SSP_SUBLINK_SPEED_LSM (0xff << 16) /* Lanespeed mantissa */
} __attribute__((packed));
/*
* Configuration Summary descriptors: Defines a list of functions in the
* configuration. This descriptor may be used by Host software to decide
* which Configuration to use to obtain the desired functionality.
*/
#define USB_CAP_TYPE_CONFIG_SUMMARY 0x10
struct function_class_info {
__u8 bClass;
__u8 bSubClass;
__u8 bProtocol;
};
struct usb_config_summary_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
__u16 bcdVersion;
__u8 bConfigurationValue;
__u8 bMaxPower;
__u8 bNumFunctions;
struct function_class_info cs_info[];
} __attribute__((packed));
/*-------------------------------------------------------------------------*/