On Wed, 2022-06-29 at 12:46 +0300, Ruslan Bilovol wrote: > On Wed, Jun 29, 2022 at 5:13 AM Chunfeng Yun < > chunfeng.yun@xxxxxxxxxxxx> wrote: > > > > From: xin lin <xin.lin@xxxxxxxxxxxx> > > > > When we want to use a composite device that supports UVC, UAC1 and > > ADB at the same time, encounter that UAC1 can't work when connected > > to windows 10 system. > > From the online documents of microsoft, "overview of enumeration of > > interface collections on usb composite devices", it recommends that > > vendors use IADs (interface association descriptor) to define > > interface collections. > > After addding IAD, we can fix the issue. > > It is incorrect to add Interface Association Descriptor to the UAC1 > function. > The UAC1 specification was developed much earlier than IAD was > invented, and it > implements this functionality in another way - by describing number > of > associated > interfaces and interface numbers on Class-Specific AC Interface > Descriptor level; > see *bInCollection* and *baInterfaceNr* fields of UAC1 Class-Specific > AC Interface > Header Descriptor in 4.3.2 section of UAC1 specification. > > This is already implemented in f_uac1.c (see where *bInCollection* > and > *baInterfaceNr* > are updated), along with support of dynamic capture/playback > endpoints > enablement. > Adding IAD to the UAC1 driver is duplicating that functionality and > isn't supported > by UAC1 spec. Ok, seems win10 don't support this way. Abandon this patch. > > On the other hand, the USB orgcommittee switched the approach of > interface collection > definition from a class-specific descriptors level to IAD in the UAC2 > spec. > So why not use UAC2 function for the same purpose, it already has IAD > implemented > and is supported by Win10? unfortunately, also encounter enumeration issues on some versions of win10. Thanks > > Thanks, > Ruslan > > > > > Signed-off-by: xin lin <xin.lin@xxxxxxxxxxxx> > > Signed-off-by: Chunfeng Yun <chunfeng.yun@xxxxxxxxxxxx> > > --- > > v2: modify commit log suggested by Greg > > --- > > drivers/usb/gadget/function/f_uac1.c | 21 +++++++++++++++++++++ > > 1 file changed, 21 insertions(+) > > > > diff --git a/drivers/usb/gadget/function/f_uac1.c > > b/drivers/usb/gadget/function/f_uac1.c > > index 6f0e1d803dc2..8390207bc513 100644 > > --- a/drivers/usb/gadget/function/f_uac1.c > > +++ b/drivers/usb/gadget/function/f_uac1.c > > @@ -71,6 +71,17 @@ static inline struct f_uac1_opts > > *g_audio_to_uac1_opts(struct g_audio *audio) > > * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN > > */ > > > > +static struct usb_interface_assoc_descriptor iad_desc = { > > + .bLength = sizeof(iad_desc), > > + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, > > + > > + .bFirstInterface = 0, > > + .bInterfaceCount = 3, > > + .bFunctionClass = USB_CLASS_AUDIO, > > + .bFunctionSubClass = 0, > > + .bFunctionProtocol = UAC_VERSION_1, > > +}; > > + > > /* B.3.1 Standard AC Interface Descriptor */ > > static struct usb_interface_descriptor ac_interface_desc = { > > .bLength = USB_DT_INTERFACE_SIZE, > > @@ -259,6 +270,7 @@ static struct uac_iso_endpoint_descriptor > > as_iso_in_desc = { > > }; > > > > static struct usb_descriptor_header *f_audio_desc[] = { > > + (struct usb_descriptor_header *)&iad_desc, > > (struct usb_descriptor_header *)&ac_interface_desc, > > (struct usb_descriptor_header *)&ac_header_desc, > > > > @@ -293,6 +305,7 @@ static struct usb_descriptor_header > > *f_audio_desc[] = { > > }; > > > > enum { > > + STR_ASSOC, > > STR_AC_IF, > > STR_USB_OUT_IT, > > STR_USB_OUT_IT_CH_NAMES, > > @@ -310,6 +323,7 @@ enum { > > > > static struct usb_string strings_uac1[] = { > > /* [STR_AC_IF].s = DYNAMIC, */ > > + [STR_ASSOC].s = "Source/Sink", > > [STR_USB_OUT_IT].s = "Playback Input terminal", > > [STR_USB_OUT_IT_CH_NAMES].s = "Playback Channels", > > [STR_IO_OUT_OT].s = "Playback Output terminal", > > @@ -1058,6 +1072,7 @@ static void setup_descriptor(struct > > f_uac1_opts *opts) > > as_out_header_desc.bTerminalLink = > > usb_out_it_desc.bTerminalID; > > as_in_header_desc.bTerminalLink = > > usb_in_ot_desc.bTerminalID; > > > > + iad_desc.bInterfaceCount = 1; > > ac_header_desc->wTotalLength = cpu_to_le16(ac_header_desc- > > >bLength); > > > > if (EPIN_EN(opts)) { > > @@ -1068,6 +1083,7 @@ static void setup_descriptor(struct > > f_uac1_opts *opts) > > if (FUIN_EN(opts)) > > len += in_feature_unit_desc->bLength; > > ac_header_desc->wTotalLength = cpu_to_le16(len); > > + iad_desc.bInterfaceCount++; > > } > > if (EPOUT_EN(opts)) { > > u16 len = le16_to_cpu(ac_header_desc- > > >wTotalLength); > > @@ -1077,9 +1093,11 @@ static void setup_descriptor(struct > > f_uac1_opts *opts) > > if (FUOUT_EN(opts)) > > len += out_feature_unit_desc->bLength; > > ac_header_desc->wTotalLength = cpu_to_le16(len); > > + iad_desc.bInterfaceCount++; > > } > > > > i = 0; > > + f_audio_desc[i++] = USBDHDR(&iad_desc); > > f_audio_desc[i++] = USBDHDR(&ac_interface_desc); > > f_audio_desc[i++] = USBDHDR(ac_header_desc); > > > > @@ -1217,6 +1235,7 @@ static int f_audio_bind(struct > > usb_configuration *c, struct usb_function *f) > > } > > } > > > > + iad_desc.iFunction = us[STR_ASSOC].id; > > ac_interface_desc.iInterface = us[STR_AC_IF].id; > > usb_out_it_desc.iTerminal = us[STR_USB_OUT_IT].id; > > usb_out_it_desc.iChannelNames = > > us[STR_USB_OUT_IT_CH_NAMES].id; > > @@ -1302,6 +1321,8 @@ static int f_audio_bind(struct > > usb_configuration *c, struct usb_function *f) > > status = usb_interface_id(c, f); > > if (status < 0) > > goto err_free_fu; > > + > > + iad_desc.bFirstInterface = status; > > ac_interface_desc.bInterfaceNumber = status; > > uac1->ac_intf = status; > > uac1->ac_alt = 0; > > -- > > 2.18.0 > >