Message ID | f861e345-3642-5bfa-0ce7-a5cd34204613@ivitera.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | usb:gadget:u_audio: Regression in [v3,3/3] usb: gadget: u_audio: add real feedback implementation - wMaxPacketSize calculation | expand |
On Tue, Jul 13, 2021 at 12:22:38PM +0200, Pavel Hofman wrote: > Hi, > > I am testing the three Ruslan's async feedback patches as modified by Jerome > and I hit a regression in windows 10 enumeration. > > Ruslan posted an already accepted patch https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 We do not use github for kernel stuff, just reference the git commit id properly and all is good. > which allowed win10 enumeration. > > Ruslan's async feedback patchset kept the change: https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ I do not understand this reference at all. > > diff --git a/drivers/usb/gadget/function/f_uac2.c > b/drivers/usb/gadget/function/f_uac2.c > index 72b42f8..91b22fb 100644 > --- a/drivers/usb/gadget/function/f_uac2.c > +++ b/drivers/usb/gadget/function/f_uac2.c > @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct > f_uac2_opts *uac2_opts, > > max_size_bw = num_channels(chmask) * ssize * > ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); > + > + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) > + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; > + > ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, > max_size_ep)); > > > Jerome's rebase patch which was accepted recently changed the functionality > to the original code: > https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ > > diff --git a/drivers/usb/gadget/function/f_uac2.c > b/drivers/usb/gadget/function/f_uac2.c > index 321e6c05ba93..ae29ff2b2b68 100644 > --- a/drivers/usb/gadget/function/f_uac2.c > +++ b/drivers/usb/gadget/function/f_uac2.c > @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct > f_uac2_opts *uac2_opts, > ssize = uac2_opts->c_ssize; > } > > + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) > + srate = srate * (1000 + uac2_opts->fb_max) / 1000; > + > max_size_bw = num_channels(chmask) * ssize * > - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); > + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); > ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, > max_size_ep)); > > With this version my Win10 does not enumerate the USB AUDIO device, even if > it has only EP-IN capability (i.e. is_playback = true). For my setup the > EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing > win10 reporting "The specified range could not be found in the range list." > > A simple change makes Win10 enumerate both playback-only as well as duplex > playback/capture async device: > > diff --git a/drivers/usb/gadget/function/f_uac2.c > b/drivers/usb/gadget/function/f_uac2.c > index ae29ff2b2b68..5ba778814796 100644 > --- a/drivers/usb/gadget/function/f_uac2.c > +++ b/drivers/usb/gadget/function/f_uac2.c > @@ -588,7 +588,7 @@ static int set_ep_max_packet_size(const struct > f_uac2_opts *uac2_opts, > srate = srate * (1000 + uac2_opts->fb_max) / 1000; > > max_size_bw = num_channels(chmask) * ssize * > - DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - > 1))); > + (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - > 1))) + 1); > ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, > max_size_ep)); > > > I do not know if this is the most correct solution but IMO a similar patch > should be applied. I can send a proper patch mail if this solution is > acceptable. Just send the patch and we will go from there. thanks, greg k-h
On Tue 13 Jul 2021 at 12:22, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > Hi, > > I am testing the three Ruslan's async feedback patches as modified by > Jerome and I hit a regression in windows 10 enumeration. > > Ruslan posted an already accepted patch > https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 > which allowed win10 enumeration. > > Ruslan's async feedback patchset kept the change: > https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ > > diff --git a/drivers/usb/gadget/function/f_uac2.c > b/drivers/usb/gadget/function/f_uac2.c > index 72b42f8..91b22fb 100644 > --- a/drivers/usb/gadget/function/f_uac2.c > +++ b/drivers/usb/gadget/function/f_uac2.c > @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct > f_uac2_opts *uac2_opts, > > max_size_bw = num_channels(chmask) * ssize * > ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); > + > + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) > + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; > + > ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, > max_size_ep)); > > > Jerome's rebase patch which was accepted recently changed the functionality > to the original code: > https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ > > diff --git a/drivers/usb/gadget/function/f_uac2.c > b/drivers/usb/gadget/function/f_uac2.c > index 321e6c05ba93..ae29ff2b2b68 100644 > --- a/drivers/usb/gadget/function/f_uac2.c > +++ b/drivers/usb/gadget/function/f_uac2.c > @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct > f_uac2_opts *uac2_opts, > ssize = uac2_opts->c_ssize; > } > > + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) > + srate = srate * (1000 + uac2_opts->fb_max) / 1000; > + > max_size_bw = num_channels(chmask) * ssize * > - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); > + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); > ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, > max_size_ep)); > > With this version my Win10 does not enumerate the USB AUDIO device, even if > it has only EP-IN capability (i.e. is_playback = true). For my setup the > EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing > win10 reporting "The specified range could not be found in the range list." > Maybe I am lacking USB expertize, but is there any reason why a 192bytes maximum packet size should be considered invalid ? Just from your comment, I can't figure it out. It would help if you could detail the parameters you started your gadget with (rate, format, channel number) IIRC, Ruslan initial patchset reserved a fixed additional bandwidth (around 20% I think) to deal with the explicit feedback. The idea is that, 99.9% of the time, all you need is the ability to fit one more sample in each packet. This is should be what the default setting provides (up to 192kHz). If it does not do that, I made mistake. The setting configurable because I was trying to avoid wasting USB bandwith but still support poor quality platforms where 1 extra sample is not enough (I think Ruslan mentioned having seen such system) > A simple change makes Win10 enumerate both playback-only as well as duplex > playback/capture async device: > > diff --git a/drivers/usb/gadget/function/f_uac2.c > b/drivers/usb/gadget/function/f_uac2.c > index ae29ff2b2b68..5ba778814796 100644 > --- a/drivers/usb/gadget/function/f_uac2.c > +++ b/drivers/usb/gadget/function/f_uac2.c > @@ -588,7 +588,7 @@ static int set_ep_max_packet_size(const struct > f_uac2_opts *uac2_opts, > srate = srate * (1000 + uac2_opts->fb_max) / 1000; > > max_size_bw = num_channels(chmask) * ssize * > - DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - > 1))); > + (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - > 1))) + 1); I don't really understand why you should add 1 here and how it correlate to your remark above ? > ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, > max_size_ep)); > > > I do not know if this is the most correct solution but IMO a similar patch > should be applied. I can send a proper patch mail if this solution is > acceptable. > > Thanks a lot, > > Pavel.
Hi, Jerome Brunet <jbrunet@baylibre.com> writes: >> I am testing the three Ruslan's async feedback patches as modified by >> Jerome and I hit a regression in windows 10 enumeration. >> >> Ruslan posted an already accepted patch >> https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 >> which allowed win10 enumeration. >> >> Ruslan's async feedback patchset kept the change: >> https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ >> >> diff --git a/drivers/usb/gadget/function/f_uac2.c >> b/drivers/usb/gadget/function/f_uac2.c >> index 72b42f8..91b22fb 100644 >> --- a/drivers/usb/gadget/function/f_uac2.c >> +++ b/drivers/usb/gadget/function/f_uac2.c >> @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct >> f_uac2_opts *uac2_opts, >> >> max_size_bw = num_channels(chmask) * ssize * >> ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >> + >> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >> + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; >> + >> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >> max_size_ep)); >> >> >> Jerome's rebase patch which was accepted recently changed the functionality >> to the original code: >> https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ >> >> diff --git a/drivers/usb/gadget/function/f_uac2.c >> b/drivers/usb/gadget/function/f_uac2.c >> index 321e6c05ba93..ae29ff2b2b68 100644 >> --- a/drivers/usb/gadget/function/f_uac2.c >> +++ b/drivers/usb/gadget/function/f_uac2.c >> @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct >> f_uac2_opts *uac2_opts, >> ssize = uac2_opts->c_ssize; >> } >> >> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >> + srate = srate * (1000 + uac2_opts->fb_max) / 1000; >> + >> max_size_bw = num_channels(chmask) * ssize * >> - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >> + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); >> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >> max_size_ep)); >> >> With this version my Win10 does not enumerate the USB AUDIO device, even if >> it has only EP-IN capability (i.e. is_playback = true). For my setup the >> EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing >> win10 reporting "The specified range could not be found in the range list." >> > > Maybe I am lacking USB expertize, but is there any reason why a 192bytes > maximum packet size should be considered invalid ? Just from your > comment, I can't figure it out. it sounds to me like one part of the descriptor claims 192 while another claims 196, then there is a mismatch and Windows is ignoring the interface. A quick dump of the descriptors would prove this.
Dne 13. 07. 21 v 14:05 Jerome Brunet napsal(a): > > On Tue 13 Jul 2021 at 12:22, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > >> Hi, >> >> I am testing the three Ruslan's async feedback patches as modified by >> Jerome and I hit a regression in windows 10 enumeration. >> >> Ruslan posted an already accepted patch >> https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 >> which allowed win10 enumeration. >> >> Ruslan's async feedback patchset kept the change: >> https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ >> >> diff --git a/drivers/usb/gadget/function/f_uac2.c >> b/drivers/usb/gadget/function/f_uac2.c >> index 72b42f8..91b22fb 100644 >> --- a/drivers/usb/gadget/function/f_uac2.c >> +++ b/drivers/usb/gadget/function/f_uac2.c >> @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct >> f_uac2_opts *uac2_opts, >> >> max_size_bw = num_channels(chmask) * ssize * >> ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >> + >> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >> + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; >> + >> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >> max_size_ep)); >> >> >> Jerome's rebase patch which was accepted recently changed the functionality >> to the original code: >> https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ >> >> diff --git a/drivers/usb/gadget/function/f_uac2.c >> b/drivers/usb/gadget/function/f_uac2.c >> index 321e6c05ba93..ae29ff2b2b68 100644 >> --- a/drivers/usb/gadget/function/f_uac2.c >> +++ b/drivers/usb/gadget/function/f_uac2.c >> @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct >> f_uac2_opts *uac2_opts, >> ssize = uac2_opts->c_ssize; >> } >> >> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >> + srate = srate * (1000 + uac2_opts->fb_max) / 1000; >> + >> max_size_bw = num_channels(chmask) * ssize * >> - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >> + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); >> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >> max_size_ep)); >> >> With this version my Win10 does not enumerate the USB AUDIO device, even if >> it has only EP-IN capability (i.e. is_playback = true). For my setup the >> EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing >> win10 reporting "The specified range could not be found in the range list." >> > > Maybe I am lacking USB expertize, but is there any reason why a 192bytes > maximum packet size should be considered invalid ? Just from your > comment, I can't figure it out. > > It would help if you could detail the parameters you started your gadget > with (rate, format, channel number) > > IIRC, Ruslan initial patchset reserved a fixed additional bandwidth > (around 20% I think) to deal with the explicit feedback. > > The idea is that, 99.9% of the time, all you need is the ability to fit > one more sample in each packet. This is should be what the default > setting provides (up to 192kHz). If it does not do that, I made mistake. > > The setting configurable because I was trying to avoid wasting USB > bandwith but still support poor quality platforms where 1 extra sample > is not enough (I think Ruslan mentioned having seen such system) I am absolutely no USB expert. What I did was testing Jerome's patchset and win10 refused to enumerate, even with the most trivial configuration c_srate=p_srate=48000, 16bits, capture 2ch, playback 0ch which configures no EP-OUT and no feedback EP-IN. To find the cause I went back one patch (HEAD^) and win10 happily enumerated this no-EP-OUT configuration. So I compared the usb config dump - see attached files from Theosycon USB Descriptor Dumper - see the two attached files, named after commit IDs. The dumps differ in only one parameter EP-IN 1 wMaxPacketSize, for both HS and the dumped "Other Speed Configuration Descriptor" i.e. FS: diff 650f7f40dc1691a8ab4d1dc411f8f327b36e8d14.txt cb1c270600b2c6f55f55f227775aaddf2cc78bed.txt 185c185 < 0x00C4 wMaxPacketSize (1 x 196 bytes) --- > 0x00C0 wMaxPacketSize (1 x 192 bytes) 339c339 < 0x00C4 wMaxPacketSize (1 x 196 bytes) --- > 0x00C0 wMaxPacketSize (1 x 192 bytes) So I looked at the patch and saw the changed wMaxPacketSize calculation. Adding +1 yielded what the original Ruslan's code yielded - one more sample (i.e. 196 bytes instead of 192bytes). Therefore I put it in the patch here. This value is accepted by win10. I do not know how windows uac2 driver verifies validity of wMaxPacketSize but clearly 196bytes (+1 sample) is accepted while 192bytes is refused. Linux does not care, just like Ruslan described in his commit 789ea77310f020. I checked duplex with EP-OUT enabled (i.e. with the feedback EP-IN), the "new" calculation works OK in win10 (while the Jerome's values were refused). I really do not know the correct code for calculating the wMaxPacketSize to satisfy the windows driver, but what I am posting works. I'll be happy if someone knowledgeable fixes my layman quickfix. Best regards, Pavel. Information for device Linux USB Audio Gadget (VID=0x1D6B PID=0x0101): ------------------------------ Connection Information: ------------------------------ Device current bus speed: HighSpeed Device supports USB 1.1 specification Device supports USB 2.0 specification Device address: 0x0001 Current configuration value: 0x01 Number of open pipes: 0 ------------------------------ Device Descriptor: ------------------------------ 0x12 bLength 0x01 bDescriptorType 0x0200 bcdUSB 0xEF bDeviceClass (Miscellaneous device) 0x02 bDeviceSubClass 0x01 bDeviceProtocol 0x40 bMaxPacketSize0 (64 bytes) 0x1D6B idVendor 0x0101 idProduct 0x0513 bcdDevice 0x01 iManufacturer "Linux 5.13.1-v8+ with fe980000.usb" 0x02 iProduct "Linux USB Audio Gadget" 0x00 iSerialNumber 0x01 bNumConfigurations Device Qualifier Descriptor: ------------------------------ 0x0A bLength 0x06 bDescriptorType 0x0200 bcdUSB 0xEF bDeviceClass (Miscellaneous device) 0x02 bDeviceSubClass 0x01 bDeviceProtocol 0x40 bMaxPacketSize0 (64 bytes) 0x01 bNumConfigurations 0x00 bReserved ------------------------- Configuration Descriptor: ------------------------- 0x09 bLength 0x02 bDescriptorType 0x007F wTotalLength (127 bytes) 0x02 bNumInterfaces 0x01 bConfigurationValue 0x00 iConfiguration 0xC0 bmAttributes (Self-powered Device) 0x01 bMaxPower (2 mA) Interface Association Descriptor: ------------------------------ 0x08 bLength 0x0B bDescriptorType 0x00 bFirstInterface 0x02 bInterfaceCount 0x01 bFunctionClass (Audio Device Class) 0x00 bFunctionSubClass 0x20 bFunctionProtocol (Audio Protocol IP version 2.00) 0x04 iFunction "Source/Sink" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x00 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x01 bInterfaceSubClass (Audio Control Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x05 iInterface "Topology Control" AC Interface Header Descriptor: ------------------------------ 0x09 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x0200 bcdADC 0x08 bCategory (IO_BOX) 0x002E wTotalLength (46 bytes) 0x00 bmControls AC Clock Source Descriptor: ------------------------------ 0x08 bLength 0x24 bDescriptorType 0x0A bDescriptorSubtype 0x03 bClockID 0x01 bmAttributes 0x01 bmControls Clock Frequency Control - read only 0x00 bAssocTerminal 0x06 iClockSource "48000Hz" AC Input Terminal Descriptor: ------------------------------ 0x11 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bTerminalID 0x0200 wTerminalType (Input Undefined) 0x00 bAssocTerminal 0x03 bCSourceID 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames 0x03 bmControls Copy Protect Control - host programmable 0x09 iTerminal "USBD Out" AC Output Terminal Descriptor: ------------------------------ 0x0C bLength 0x24 bDescriptorType 0x03 bDescriptorSubtype 0x02 bTerminalID 0x0101 wTerminalType (USB Streaming) 0x00 bAssocTerminal 0x01 bSourceID 0x03 bCSourceID 0x0003 bmControls Copy Protect Control - host programmable 0x0A iTerminal "USBH In" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0E iInterface "Capture Inactive" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x01 bAlternateSetting 0x01 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0F iInterface "Capture Active" AS Interface Descriptor: ------------------------------ 0x10 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x02 bTerminalLink 0x00 bmControls 0x01 bFormatType (FORMAT_TYPE_1) 0x00000001 bmFormats PCM 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames AS Format Type 1 Descriptor: ------------------------------ 0x06 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bFormatType (FORMAT_TYPE_1) 0x02 bSubslotSize 0x10 bBitResolution (16 bits per sample) Endpoint Descriptor: ------------------------------ 0x07 bLength 0x05 bDescriptorType 0x81 bEndpointAddress (IN endpoint 1) 0x05 bmAttributes (Transfer: Isochronous / Synch: Asynchronous / Usage: Data) 0x00C4 wMaxPacketSize (1 x 196 bytes) 0x04 bInterval (8 microframes) AS Isochronous Data Endpoint Descriptor: ------------------------------ 0x08 bLength 0x25 bDescriptorType 0x01 bDescriptorSubtype 0x00 bmAttributes 0x00 bmControls 0x00 bLockDelayUnits (undefined) 0x0000 wLockDelay ------------------------------------- Other Speed Configuration Descriptor: ------------------------------------- 0x09 bLength 0x07 bDescriptorType 0x007F wTotalLength (127 bytes) 0x02 bNumInterfaces 0x01 bConfigurationValue 0x00 iConfiguration 0xC0 bmAttributes (Self-powered Device) 0x01 bMaxPower (2 mA) Interface Association Descriptor: ------------------------------ 0x08 bLength 0x0B bDescriptorType 0x00 bFirstInterface 0x02 bInterfaceCount 0x01 bFunctionClass (Audio Device Class) 0x00 bFunctionSubClass 0x20 bFunctionProtocol (Audio Protocol IP version 2.00) 0x04 iFunction "Source/Sink" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x00 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x01 bInterfaceSubClass (Audio Control Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x05 iInterface "Topology Control" AC Interface Header Descriptor: ------------------------------ 0x09 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x0200 bcdADC 0x08 bCategory (IO_BOX) 0x002E wTotalLength (46 bytes) 0x00 bmControls AC Clock Source Descriptor: ------------------------------ 0x08 bLength 0x24 bDescriptorType 0x0A bDescriptorSubtype 0x03 bClockID 0x01 bmAttributes 0x01 bmControls Clock Frequency Control - read only 0x00 bAssocTerminal 0x06 iClockSource "48000Hz" AC Input Terminal Descriptor: ------------------------------ 0x11 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bTerminalID 0x0200 wTerminalType (Input Undefined) 0x00 bAssocTerminal 0x03 bCSourceID 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames 0x03 bmControls Copy Protect Control - host programmable 0x09 iTerminal "USBD Out" AC Output Terminal Descriptor: ------------------------------ 0x0C bLength 0x24 bDescriptorType 0x03 bDescriptorSubtype 0x02 bTerminalID 0x0101 wTerminalType (USB Streaming) 0x00 bAssocTerminal 0x01 bSourceID 0x03 bCSourceID 0x0003 bmControls Copy Protect Control - host programmable 0x0A iTerminal "USBH In" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0E iInterface "Capture Inactive" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x01 bAlternateSetting 0x01 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0F iInterface "Capture Active" AS Interface Descriptor: ------------------------------ 0x10 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x02 bTerminalLink 0x00 bmControls 0x01 bFormatType (FORMAT_TYPE_1) 0x00000001 bmFormats PCM 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames AS Format Type 1 Descriptor: ------------------------------ 0x06 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bFormatType (FORMAT_TYPE_1) 0x02 bSubslotSize 0x10 bBitResolution (16 bits per sample) Endpoint Descriptor: ------------------------------ 0x07 bLength 0x05 bDescriptorType 0x81 bEndpointAddress (IN endpoint 1) 0x05 bmAttributes (Transfer: Isochronous / Synch: Asynchronous / Usage: Data) 0x00C4 wMaxPacketSize (1 x 196 bytes) 0x01 bInterval (1 frames) AS Isochronous Data Endpoint Descriptor: ------------------------------ 0x08 bLength 0x25 bDescriptorType 0x01 bDescriptorSubtype 0x00 bmAttributes 0x00 bmControls 0x00 bLockDelayUnits (undefined) 0x0000 wLockDelay Microsoft OS Descriptor is not available. Error code: 0x0000001F -------------------------------- String Descriptor Table -------------------------------- Index LANGID String 0x00 0x0000 0x0409 0x01 0x0409 "Linux 5.13.1-v8+ with fe980000.usb" 0x02 0x0409 "Linux USB Audio Gadget" 0x04 0x0409 "Source/Sink" 0x05 0x0409 "Topology Control" 0x06 0x0409 "48000Hz" 0x09 0x0409 "USBD Out" 0x0A 0x0409 "USBH In" 0x0E 0x0409 "Capture Inactive" 0x0F 0x0409 "Capture Active" ------------------------------ Connection path for device: Standard Enhanced PCI to USB Host Controller Root Hub Linux USB Audio Gadget (VID=0x1D6B PID=0x0101) Port: 1 Running on: Windows 10 or greater (Build Version 19041) Brought to you by TDD v2.17.0, Feb 23 2021, 14:04:02 Information for device Linux USB Audio Gadget (VID=0x1D6B PID=0x0101): ------------------------------ Connection Information: ------------------------------ Device current bus speed: HighSpeed Device supports USB 1.1 specification Device supports USB 2.0 specification Device address: 0x0001 Current configuration value: 0x01 Number of open pipes: 0 ------------------------------ Device Descriptor: ------------------------------ 0x12 bLength 0x01 bDescriptorType 0x0200 bcdUSB 0xEF bDeviceClass (Miscellaneous device) 0x02 bDeviceSubClass 0x01 bDeviceProtocol 0x40 bMaxPacketSize0 (64 bytes) 0x1D6B idVendor 0x0101 idProduct 0x0513 bcdDevice 0x01 iManufacturer "Linux 5.13.1-v8+ with fe980000.usb" 0x02 iProduct "Linux USB Audio Gadget" 0x00 iSerialNumber 0x01 bNumConfigurations Device Qualifier Descriptor: ------------------------------ 0x0A bLength 0x06 bDescriptorType 0x0200 bcdUSB 0xEF bDeviceClass (Miscellaneous device) 0x02 bDeviceSubClass 0x01 bDeviceProtocol 0x40 bMaxPacketSize0 (64 bytes) 0x01 bNumConfigurations 0x00 bReserved ------------------------- Configuration Descriptor: ------------------------- 0x09 bLength 0x02 bDescriptorType 0x007F wTotalLength (127 bytes) 0x02 bNumInterfaces 0x01 bConfigurationValue 0x00 iConfiguration 0xC0 bmAttributes (Self-powered Device) 0x01 bMaxPower (2 mA) Interface Association Descriptor: ------------------------------ 0x08 bLength 0x0B bDescriptorType 0x00 bFirstInterface 0x02 bInterfaceCount 0x01 bFunctionClass (Audio Device Class) 0x00 bFunctionSubClass 0x20 bFunctionProtocol (Audio Protocol IP version 2.00) 0x04 iFunction "Source/Sink" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x00 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x01 bInterfaceSubClass (Audio Control Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x05 iInterface "Topology Control" AC Interface Header Descriptor: ------------------------------ 0x09 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x0200 bcdADC 0x08 bCategory (IO_BOX) 0x002E wTotalLength (46 bytes) 0x00 bmControls AC Clock Source Descriptor: ------------------------------ 0x08 bLength 0x24 bDescriptorType 0x0A bDescriptorSubtype 0x03 bClockID 0x01 bmAttributes 0x01 bmControls Clock Frequency Control - read only 0x00 bAssocTerminal 0x06 iClockSource "48000Hz" AC Input Terminal Descriptor: ------------------------------ 0x11 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bTerminalID 0x0200 wTerminalType (Input Undefined) 0x00 bAssocTerminal 0x03 bCSourceID 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames 0x03 bmControls Copy Protect Control - host programmable 0x09 iTerminal "USBD Out" AC Output Terminal Descriptor: ------------------------------ 0x0C bLength 0x24 bDescriptorType 0x03 bDescriptorSubtype 0x02 bTerminalID 0x0101 wTerminalType (USB Streaming) 0x00 bAssocTerminal 0x01 bSourceID 0x03 bCSourceID 0x0003 bmControls Copy Protect Control - host programmable 0x0A iTerminal "USBH In" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0E iInterface "Capture Inactive" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x01 bAlternateSetting 0x01 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0F iInterface "Capture Active" AS Interface Descriptor: ------------------------------ 0x10 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x02 bTerminalLink 0x00 bmControls 0x01 bFormatType (FORMAT_TYPE_1) 0x00000001 bmFormats PCM 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames AS Format Type 1 Descriptor: ------------------------------ 0x06 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bFormatType (FORMAT_TYPE_1) 0x02 bSubslotSize 0x10 bBitResolution (16 bits per sample) Endpoint Descriptor: ------------------------------ 0x07 bLength 0x05 bDescriptorType 0x81 bEndpointAddress (IN endpoint 1) 0x05 bmAttributes (Transfer: Isochronous / Synch: Asynchronous / Usage: Data) 0x00C0 wMaxPacketSize (1 x 192 bytes) 0x04 bInterval (8 microframes) AS Isochronous Data Endpoint Descriptor: ------------------------------ 0x08 bLength 0x25 bDescriptorType 0x01 bDescriptorSubtype 0x00 bmAttributes 0x00 bmControls 0x00 bLockDelayUnits (undefined) 0x0000 wLockDelay ------------------------------------- Other Speed Configuration Descriptor: ------------------------------------- 0x09 bLength 0x07 bDescriptorType 0x007F wTotalLength (127 bytes) 0x02 bNumInterfaces 0x01 bConfigurationValue 0x00 iConfiguration 0xC0 bmAttributes (Self-powered Device) 0x01 bMaxPower (2 mA) Interface Association Descriptor: ------------------------------ 0x08 bLength 0x0B bDescriptorType 0x00 bFirstInterface 0x02 bInterfaceCount 0x01 bFunctionClass (Audio Device Class) 0x00 bFunctionSubClass 0x20 bFunctionProtocol (Audio Protocol IP version 2.00) 0x04 iFunction "Source/Sink" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x00 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x01 bInterfaceSubClass (Audio Control Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x05 iInterface "Topology Control" AC Interface Header Descriptor: ------------------------------ 0x09 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x0200 bcdADC 0x08 bCategory (IO_BOX) 0x002E wTotalLength (46 bytes) 0x00 bmControls AC Clock Source Descriptor: ------------------------------ 0x08 bLength 0x24 bDescriptorType 0x0A bDescriptorSubtype 0x03 bClockID 0x01 bmAttributes 0x01 bmControls Clock Frequency Control - read only 0x00 bAssocTerminal 0x06 iClockSource "48000Hz" AC Input Terminal Descriptor: ------------------------------ 0x11 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bTerminalID 0x0200 wTerminalType (Input Undefined) 0x00 bAssocTerminal 0x03 bCSourceID 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames 0x03 bmControls Copy Protect Control - host programmable 0x09 iTerminal "USBD Out" AC Output Terminal Descriptor: ------------------------------ 0x0C bLength 0x24 bDescriptorType 0x03 bDescriptorSubtype 0x02 bTerminalID 0x0101 wTerminalType (USB Streaming) 0x00 bAssocTerminal 0x01 bSourceID 0x03 bCSourceID 0x0003 bmControls Copy Protect Control - host programmable 0x0A iTerminal "USBH In" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x00 bAlternateSetting 0x00 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0E iInterface "Capture Inactive" Interface Descriptor: ------------------------------ 0x09 bLength 0x04 bDescriptorType 0x01 bInterfaceNumber 0x01 bAlternateSetting 0x01 bNumEndPoints 0x01 bInterfaceClass (Audio Device Class) 0x02 bInterfaceSubClass (Audio Streaming Interface) 0x20 bInterfaceProtocol (Audio Protocol IP version 2.00) 0x0F iInterface "Capture Active" AS Interface Descriptor: ------------------------------ 0x10 bLength 0x24 bDescriptorType 0x01 bDescriptorSubtype 0x02 bTerminalLink 0x00 bmControls 0x01 bFormatType (FORMAT_TYPE_1) 0x00000001 bmFormats PCM 0x02 bNrChannels (2 channels) 0x00000003 bmChannelConfig 0x00 iChannelNames AS Format Type 1 Descriptor: ------------------------------ 0x06 bLength 0x24 bDescriptorType 0x02 bDescriptorSubtype 0x01 bFormatType (FORMAT_TYPE_1) 0x02 bSubslotSize 0x10 bBitResolution (16 bits per sample) Endpoint Descriptor: ------------------------------ 0x07 bLength 0x05 bDescriptorType 0x81 bEndpointAddress (IN endpoint 1) 0x05 bmAttributes (Transfer: Isochronous / Synch: Asynchronous / Usage: Data) 0x00C0 wMaxPacketSize (1 x 192 bytes) 0x01 bInterval (1 frames) AS Isochronous Data Endpoint Descriptor: ------------------------------ 0x08 bLength 0x25 bDescriptorType 0x01 bDescriptorSubtype 0x00 bmAttributes 0x00 bmControls 0x00 bLockDelayUnits (undefined) 0x0000 wLockDelay Microsoft OS Descriptor is not available. Error code: 0x0000001F -------------------------------- String Descriptor Table -------------------------------- Index LANGID String 0x00 0x0000 0x0409 0x01 0x0409 "Linux 5.13.1-v8+ with fe980000.usb" 0x02 0x0409 "Linux USB Audio Gadget" 0x04 0x0409 "Source/Sink" 0x05 0x0409 "Topology Control" 0x06 0x0409 "48000Hz" 0x09 0x0409 "USBD Out" 0x0A 0x0409 "USBH In" 0x0E 0x0409 "Capture Inactive" 0x0F 0x0409 "Capture Active" ------------------------------ Connection path for device: Standard Enhanced PCI to USB Host Controller Root Hub Linux USB Audio Gadget (VID=0x1D6B PID=0x0101) Port: 1 Running on: Windows 10 or greater (Build Version 19041) Brought to you by TDD v2.17.0, Feb 23 2021, 14:04:02
Dne 13. 07. 21 v 15:16 Pavel Hofman napsal(a): > > > Dne 13. 07. 21 v 14:05 Jerome Brunet napsal(a): >> >> On Tue 13 Jul 2021 at 12:22, Pavel Hofman <pavel.hofman@ivitera.com> >> wrote: >> >>> Hi, >>> >>> I am testing the three Ruslan's async feedback patches as modified by >>> Jerome and I hit a regression in windows 10 enumeration. >>> >>> Ruslan posted an already accepted patch >>> https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 >>> >>> which allowed win10 enumeration. >>> >>> Ruslan's async feedback patchset kept the change: >>> https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ >>> >>> >>> diff --git a/drivers/usb/gadget/function/f_uac2.c >>> b/drivers/usb/gadget/function/f_uac2.c >>> index 72b42f8..91b22fb 100644 >>> --- a/drivers/usb/gadget/function/f_uac2.c >>> +++ b/drivers/usb/gadget/function/f_uac2.c >>> @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct >>> f_uac2_opts *uac2_opts, >>> >>> max_size_bw = num_channels(chmask) * ssize * >>> ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >>> + >>> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>> + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; >>> + >>> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >>> max_size_ep)); >>> >>> >>> Jerome's rebase patch which was accepted recently changed the >>> functionality >>> to the original code: >>> https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ >>> >>> >>> diff --git a/drivers/usb/gadget/function/f_uac2.c >>> b/drivers/usb/gadget/function/f_uac2.c >>> index 321e6c05ba93..ae29ff2b2b68 100644 >>> --- a/drivers/usb/gadget/function/f_uac2.c >>> +++ b/drivers/usb/gadget/function/f_uac2.c >>> @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct >>> f_uac2_opts *uac2_opts, >>> ssize = uac2_opts->c_ssize; >>> } >>> >>> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>> + srate = srate * (1000 + uac2_opts->fb_max) / 1000; >>> + >>> max_size_bw = num_channels(chmask) * ssize * >>> - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >>> + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); >>> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >>> max_size_ep)); >>> >>> With this version my Win10 does not enumerate the USB AUDIO device, >>> even if >>> it has only EP-IN capability (i.e. is_playback = true). For my setup the >>> EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, >>> causing >>> win10 reporting "The specified range could not be found in the range >>> list." >>> >> >> Maybe I am lacking USB expertize, but is there any reason why a 192bytes >> maximum packet size should be considered invalid ? Just from your >> comment, I can't figure it out. >> >> It would help if you could detail the parameters you started your gadget >> with (rate, format, channel number) >> >> IIRC, Ruslan initial patchset reserved a fixed additional bandwidth >> (around 20% I think) to deal with the explicit feedback. >> >> The idea is that, 99.9% of the time, all you need is the ability to fit >> one more sample in each packet. This is should be what the default >> setting provides (up to 192kHz). If it does not do that, I made mistake. >> >> The setting configurable because I was trying to avoid wasting USB >> bandwith but still support poor quality platforms where 1 extra sample >> is not enough (I think Ruslan mentioned having seen such system) > > I am absolutely no USB expert. What I did was testing Jerome's patchset > and win10 refused to enumerate, even with the most trivial configuration > c_srate=p_srate=48000, 16bits, capture 2ch, playback 0ch which > configures no EP-OUT and no feedback EP-IN. To find the cause I went > back one patch (HEAD^) and win10 happily enumerated this no-EP-OUT > configuration. So I compared the usb config dump - see attached files > from Theosycon USB Descriptor Dumper - see the two attached files, named > after commit IDs. > > The dumps differ in only one parameter EP-IN 1 wMaxPacketSize, for both > HS and the dumped "Other Speed Configuration Descriptor" i.e. FS: > > diff 650f7f40dc1691a8ab4d1dc411f8f327b36e8d14.txt > cb1c270600b2c6f55f55f227775aaddf2cc78bed.txt > 185c185 > < 0x00C4 wMaxPacketSize (1 x 196 bytes) > --- > > 0x00C0 wMaxPacketSize (1 x 192 bytes) > 339c339 > < 0x00C4 wMaxPacketSize (1 x 196 bytes) > --- > > 0x00C0 wMaxPacketSize (1 x 192 bytes) > > So I looked at the patch and saw the changed wMaxPacketSize calculation. > Adding +1 yielded what the original Ruslan's code yielded - one more > sample (i.e. 196 bytes instead of 192bytes). Therefore I put it in the > patch here. This value is accepted by win10. > > I do not know how windows uac2 driver verifies validity of > wMaxPacketSize but clearly 196bytes (+1 sample) is accepted while > 192bytes is refused. Linux does not care, just like Ruslan described in > his commit 789ea77310f020. > > I checked duplex with EP-OUT enabled (i.e. with the feedback EP-IN), the > "new" calculation works OK in win10 (while the Jerome's values were > refused). > > I really do not know the correct code for calculating the wMaxPacketSize > to satisfy the windows driver, but what I am posting works. I'll be > happy if someone knowledgeable fixes my layman quickfix. > The original Ruslan's patch (in the mainline branch https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a ) explains the reasoning.
On Tue 13 Jul 2021 at 15:16, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > Dne 13. 07. 21 v 14:05 Jerome Brunet napsal(a): >> >> On Tue 13 Jul 2021 at 12:22, Pavel Hofman <pavel.hofman@ivitera.com> wrote: >> >>> Hi, >>> >>> I am testing the three Ruslan's async feedback patches as modified by >>> Jerome and I hit a regression in windows 10 enumeration. >>> >>> Ruslan posted an already accepted patch >>> https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 >>> which allowed win10 enumeration. >>> >>> Ruslan's async feedback patchset kept the change: >>> https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ >>> >>> diff --git a/drivers/usb/gadget/function/f_uac2.c >>> b/drivers/usb/gadget/function/f_uac2.c >>> index 72b42f8..91b22fb 100644 >>> --- a/drivers/usb/gadget/function/f_uac2.c >>> +++ b/drivers/usb/gadget/function/f_uac2.c >>> @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct >>> f_uac2_opts *uac2_opts, >>> >>> max_size_bw = num_channels(chmask) * ssize * >>> ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >>> + >>> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>> + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; >>> + >>> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >>> max_size_ep)); >>> >>> >>> Jerome's rebase patch which was accepted recently changed the functionality >>> to the original code: >>> https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ >>> >>> diff --git a/drivers/usb/gadget/function/f_uac2.c >>> b/drivers/usb/gadget/function/f_uac2.c >>> index 321e6c05ba93..ae29ff2b2b68 100644 >>> --- a/drivers/usb/gadget/function/f_uac2.c >>> +++ b/drivers/usb/gadget/function/f_uac2.c >>> @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct >>> f_uac2_opts *uac2_opts, >>> ssize = uac2_opts->c_ssize; >>> } >>> >>> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>> + srate = srate * (1000 + uac2_opts->fb_max) / 1000; >>> + >>> max_size_bw = num_channels(chmask) * ssize * >>> - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >>> + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); >>> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >>> max_size_ep)); >>> >>> With this version my Win10 does not enumerate the USB AUDIO device, even if >>> it has only EP-IN capability (i.e. is_playback = true). For my setup the >>> EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing >>> win10 reporting "The specified range could not be found in the range list." >>> >> >> Maybe I am lacking USB expertize, but is there any reason why a 192bytes >> maximum packet size should be considered invalid ? Just from your >> comment, I can't figure it out. >> >> It would help if you could detail the parameters you started your gadget >> with (rate, format, channel number) >> >> IIRC, Ruslan initial patchset reserved a fixed additional bandwidth >> (around 20% I think) to deal with the explicit feedback. >> >> The idea is that, 99.9% of the time, all you need is the ability to fit >> one more sample in each packet. This is should be what the default >> setting provides (up to 192kHz). If it does not do that, I made mistake. >> >> The setting configurable because I was trying to avoid wasting USB >> bandwith but still support poor quality platforms where 1 extra sample >> is not enough (I think Ruslan mentioned having seen such system) > > I am absolutely no USB expert. What I did was testing Jerome's patchset > and win10 refused to enumerate, even with the most trivial configuration > c_srate=p_srate=48000, 16bits, capture 2ch, playback 0ch which > configures no EP-OUT and no feedback EP-IN. To find the cause I went > back one patch (HEAD^) and win10 happily enumerated this no-EP-OUT > configuration. So I compared the usb config dump - see attached files > from Theosycon USB Descriptor Dumper - see the two attached files, named > after commit IDs. So 48kHz / 2ch / 16bits. Let's assume USB_SPEED_FULL for example (result is the same for the other speeds). In such condition, the nominal packet size is 192B but to accomodate an extra sample, the maximum should indeed be 196B. if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) srate = srate * (1000 + uac2_opts->fb_max) / 1000; with fb_max being 5 by default, srate should be 48240 after this. max_size_bw = num_channels(chmask) * ssize * DIV_ROUND_UP(srate, factor / (1 << (bInterval - 1))); With USB_SPEED_FULL, bInterval is 1 and factor is 1000 so: => DIV_ROUND_UP(48240, 1000 / 1) should give 49; Then => max_size_bw = 2 * 2 * 49 = 196 So the end result should be 196 with current code. I tried on an ARM64 platform. Here is what I get: [ 26.241946] set_ep_max_packet_size: speed is USB_SPEED_FULL [ 26.243208] set_ep_max_packet_size: intermediate Playback srate 48000 [ 26.249758] set_ep_max_packet_size: max_size_bw 192 [ 26.254559] set_ep_max_packet_size: speed is USB_SPEED_FULL [ 26.260130] set_ep_max_packet_size: intermediate Capture srate 48240 [ 26.266401] set_ep_max_packet_size: max_size_bw 196 [ 26.271209] set_ep_max_packet_size: speed is USB_SPEED_HIGH [ 26.276873] set_ep_max_packet_size: intermediate Playback srate 48000 [ 26.283165] set_ep_max_packet_size: max_size_bw 192 [ 26.288015] set_ep_max_packet_size: speed is USB_SPEED_HIGH [ 26.293691] set_ep_max_packet_size: intermediate Capture srate 48240 [ 26.299965] set_ep_max_packet_size: max_size_bw 196 [ 26.304753] set_ep_max_packet_size: speed is USB_SPEED_SUPER [ 26.310426] set_ep_max_packet_size: intermediate Playback srate 48000 [ 26.316805] set_ep_max_packet_size: max_size_bw 192 [ 26.321625] set_ep_max_packet_size: speed is USB_SPEED_SUPER [ 26.327309] set_ep_max_packet_size: intermediate Capture srate 48240 [ 26.333613] set_ep_max_packet_size: max_size_bw 196 All seems OK and as expected with what's in mainline ATM. So I'm not quite sure why you would get a different result. It would be great if you could check further. > > The dumps differ in only one parameter EP-IN 1 wMaxPacketSize, for both > HS and the dumped "Other Speed Configuration Descriptor" i.e. FS: > > diff 650f7f40dc1691a8ab4d1dc411f8f327b36e8d14.txt > cb1c270600b2c6f55f55f227775aaddf2cc78bed.txt > 185c185 > < 0x00C4 wMaxPacketSize (1 x 196 bytes) > --- > > 0x00C0 wMaxPacketSize (1 x 192 bytes) > 339c339 > < 0x00C4 wMaxPacketSize (1 x 196 bytes) > --- > > 0x00C0 wMaxPacketSize (1 x 192 bytes) > > So I looked at the patch and saw the changed wMaxPacketSize calculation. > Adding +1 yielded what the original Ruslan's code yielded - one more > sample (i.e. 196 bytes instead of 192bytes). Therefore I put it in the > patch here. This value is accepted by win10. > > I do not know how windows uac2 driver verifies validity of > wMaxPacketSize but clearly 196bytes (+1 sample) is accepted while > 192bytes is refused. Linux does not care, just like Ruslan described in > his commit 789ea77310f020. > > I checked duplex with EP-OUT enabled (i.e. with the feedback EP-IN), the > "new" calculation works OK in win10 (while the Jerome's values were > refused). > > I really do not know the correct code for calculating the wMaxPacketSize > to satisfy the windows driver, but what I am posting works. I'll be > happy if someone knowledgeable fixes my layman quickfix. > > Best regards, > > Pavel.
Dne 15. 07. 21 v 11:39 Jerome Brunet napsal(a): > > On Tue 13 Jul 2021 at 15:16, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > >> Dne 13. 07. 21 v 14:05 Jerome Brunet napsal(a): >>> >>> On Tue 13 Jul 2021 at 12:22, Pavel Hofman <pavel.hofman@ivitera.com> wrote: >>> >>>> Hi, >>>> >>>> I am testing the three Ruslan's async feedback patches as modified by >>>> Jerome and I hit a regression in windows 10 enumeration. >>>> >>>> Ruslan posted an already accepted patch >>>> https://github.com/torvalds/linux/commit/789ea77310f0200c84002884ffd628e2baf3ad8a#diff-876615ece7fb56ce8d45fc70623bef9caa2548e810426f217fb785ffa10b33d5 >>>> which allowed win10 enumeration. >>>> >>>> Ruslan's async feedback patchset kept the change: >>>> https://patchwork.kernel.org/project/linux-usb/patch/1614603943-11668-5-git-send-email-ruslan.bilovol@gmail.com/ >>>> >>>> diff --git a/drivers/usb/gadget/function/f_uac2.c >>>> b/drivers/usb/gadget/function/f_uac2.c >>>> index 72b42f8..91b22fb 100644 >>>> --- a/drivers/usb/gadget/function/f_uac2.c >>>> +++ b/drivers/usb/gadget/function/f_uac2.c >>>> @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct >>>> f_uac2_opts *uac2_opts, >>>> >>>> max_size_bw = num_channels(chmask) * ssize * >>>> ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >>>> + >>>> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>>> + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; >>>> + >>>> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >>>> max_size_ep)); >>>> >>>> >>>> Jerome's rebase patch which was accepted recently changed the functionality >>>> to the original code: >>>> https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ >>>> >>>> diff --git a/drivers/usb/gadget/function/f_uac2.c >>>> b/drivers/usb/gadget/function/f_uac2.c >>>> index 321e6c05ba93..ae29ff2b2b68 100644 >>>> --- a/drivers/usb/gadget/function/f_uac2.c >>>> +++ b/drivers/usb/gadget/function/f_uac2.c >>>> @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct >>>> f_uac2_opts *uac2_opts, >>>> ssize = uac2_opts->c_ssize; >>>> } >>>> >>>> + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>>> + srate = srate * (1000 + uac2_opts->fb_max) / 1000; >>>> + >>>> max_size_bw = num_channels(chmask) * ssize * >>>> - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); >>>> + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); >>>> ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, >>>> max_size_ep)); >>>> >>>> With this version my Win10 does not enumerate the USB AUDIO device, even if >>>> it has only EP-IN capability (i.e. is_playback = true). For my setup the >>>> EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing >>>> win10 reporting "The specified range could not be found in the range list." >>>> >>> >>> Maybe I am lacking USB expertize, but is there any reason why a 192bytes >>> maximum packet size should be considered invalid ? Just from your >>> comment, I can't figure it out. >>> >>> It would help if you could detail the parameters you started your gadget >>> with (rate, format, channel number) >>> >>> IIRC, Ruslan initial patchset reserved a fixed additional bandwidth >>> (around 20% I think) to deal with the explicit feedback. >>> >>> The idea is that, 99.9% of the time, all you need is the ability to fit >>> one more sample in each packet. This is should be what the default >>> setting provides (up to 192kHz). If it does not do that, I made mistake. >>> >>> The setting configurable because I was trying to avoid wasting USB >>> bandwith but still support poor quality platforms where 1 extra sample >>> is not enough (I think Ruslan mentioned having seen such system) >> >> I am absolutely no USB expert. What I did was testing Jerome's patchset >> and win10 refused to enumerate, even with the most trivial configuration >> c_srate=p_srate=48000, 16bits, capture 2ch, playback 0ch which >> configures no EP-OUT and no feedback EP-IN. To find the cause I went >> back one patch (HEAD^) and win10 happily enumerated this no-EP-OUT >> configuration. So I compared the usb config dump - see attached files >> from Theosycon USB Descriptor Dumper - see the two attached files, named >> after commit IDs. > > So 48kHz / 2ch / 16bits. Let's assume USB_SPEED_FULL for example (result > is the same for the other speeds). > > In such condition, the nominal packet size is 192B but to accomodate an > extra sample, the maximum should indeed be 196B. > > if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) > srate = srate * (1000 + uac2_opts->fb_max) / 1000; > > with fb_max being 5 by default, srate should be 48240 after this. > > > max_size_bw = num_channels(chmask) * ssize * > DIV_ROUND_UP(srate, factor / (1 << (bInterval - 1))); > > With USB_SPEED_FULL, bInterval is 1 and factor is 1000 so: > => DIV_ROUND_UP(48240, 1000 / 1) should give 49; > > Then > => max_size_bw = 2 * 2 * 49 = 196 > > So the end result should be 196 with current code. I tried on an ARM64 > platform. Here is what I get: > > [ 26.241946] set_ep_max_packet_size: speed is USB_SPEED_FULL > [ 26.243208] set_ep_max_packet_size: intermediate Playback srate 48000 > [ 26.249758] set_ep_max_packet_size: max_size_bw 192 > [ 26.254559] set_ep_max_packet_size: speed is USB_SPEED_FULL > [ 26.260130] set_ep_max_packet_size: intermediate Capture srate 48240 > [ 26.266401] set_ep_max_packet_size: max_size_bw 196 > [ 26.271209] set_ep_max_packet_size: speed is USB_SPEED_HIGH > [ 26.276873] set_ep_max_packet_size: intermediate Playback srate 48000 > [ 26.283165] set_ep_max_packet_size: max_size_bw 192 > [ 26.288015] set_ep_max_packet_size: speed is USB_SPEED_HIGH > [ 26.293691] set_ep_max_packet_size: intermediate Capture srate 48240 > [ 26.299965] set_ep_max_packet_size: max_size_bw 196 > [ 26.304753] set_ep_max_packet_size: speed is USB_SPEED_SUPER > [ 26.310426] set_ep_max_packet_size: intermediate Playback srate 48000 > [ 26.316805] set_ep_max_packet_size: max_size_bw 192 > [ 26.321625] set_ep_max_packet_size: speed is USB_SPEED_SUPER > [ 26.327309] set_ep_max_packet_size: intermediate Capture srate 48240 > [ 26.333613] set_ep_max_packet_size: max_size_bw 196 > > All seems OK and as expected with what's in mainline ATM. > So I'm not quite sure why you would get a different result. It would be > great if you could check further. > The problem is max_size_bw=192 for the Playback (i.e. is_playback = true). If only capture direction is activated (p_chmask=0), only EP-OUT with max_size_bw=196 is generated and Win10 enumerates the playback-only audio device. Once the other direction with max_size_bw=192 is activated (either duplex or capture-only), Win10 refuses to enumerate. This generates 196bytes for each direction and works OK in Win10: diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index ae29ff2b2b68..f6ccc21972bf 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -584,11 +584,15 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, ssize = uac2_opts->c_ssize; } - if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) { srate = srate * (1000 + uac2_opts->fb_max) / 1000; + max_size_bw = num_channels(chmask) * ssize * + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); + } else { + max_size_bw = num_channels(chmask) * ssize * + (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))) + 1); + } - max_size_bw = num_channels(chmask) * ssize * - DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, max_size_ep)); Tested for samplerate 250kHz 2bytes each direction yielding 1008bytes for EP-OUT and 1004 bytes for EP-IN - Win10 enumerates OK. Pavel.
On Thu 15 Jul 2021 at 14:36, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > Dne 15. 07. 21 v 11:39 Jerome Brunet napsal(a): >> On Tue 13 Jul 2021 at 15:16, Pavel Hofman <pavel.hofman@ivitera.com> >> wrote: >> >> So 48kHz / 2ch / 16bits. Let's assume USB_SPEED_FULL for example (result >> is the same for the other speeds). >> In such condition, the nominal packet size is 192B but to accomodate an >> extra sample, the maximum should indeed be 196B. >> if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >> srate = srate * (1000 + uac2_opts->fb_max) / 1000; >> with fb_max being 5 by default, srate should be 48240 after this. >> >> max_size_bw = num_channels(chmask) * ssize * >> DIV_ROUND_UP(srate, factor / (1 << (bInterval - 1))); >> With USB_SPEED_FULL, bInterval is 1 and factor is 1000 so: >> => DIV_ROUND_UP(48240, 1000 / 1) should give 49; >> Then >> => max_size_bw = 2 * 2 * 49 = 196 >> So the end result should be 196 with current code. I tried on an ARM64 >> platform. Here is what I get: >> [ 26.241946] set_ep_max_packet_size: speed is USB_SPEED_FULL >> [ 26.243208] set_ep_max_packet_size: intermediate Playback srate 48000 >> [ 26.249758] set_ep_max_packet_size: max_size_bw 192 >> [ 26.254559] set_ep_max_packet_size: speed is USB_SPEED_FULL >> [ 26.260130] set_ep_max_packet_size: intermediate Capture srate 48240 >> [ 26.266401] set_ep_max_packet_size: max_size_bw 196 >> [ 26.271209] set_ep_max_packet_size: speed is USB_SPEED_HIGH >> [ 26.276873] set_ep_max_packet_size: intermediate Playback srate 48000 >> [ 26.283165] set_ep_max_packet_size: max_size_bw 192 >> [ 26.288015] set_ep_max_packet_size: speed is USB_SPEED_HIGH >> [ 26.293691] set_ep_max_packet_size: intermediate Capture srate 48240 >> [ 26.299965] set_ep_max_packet_size: max_size_bw 196 >> [ 26.304753] set_ep_max_packet_size: speed is USB_SPEED_SUPER >> [ 26.310426] set_ep_max_packet_size: intermediate Playback srate 48000 >> [ 26.316805] set_ep_max_packet_size: max_size_bw 192 >> [ 26.321625] set_ep_max_packet_size: speed is USB_SPEED_SUPER >> [ 26.327309] set_ep_max_packet_size: intermediate Capture srate 48240 >> [ 26.333613] set_ep_max_packet_size: max_size_bw 196 >> All seems OK and as expected with what's in mainline ATM. >> So I'm not quite sure why you would get a different result. It would be >> great if you could check further. >> > > The problem is max_size_bw=192 for the Playback (i.e. is_playback = > true). If only capture direction is activated (p_chmask=0), only EP-OUT > with max_size_bw=196 is generated and Win10 enumerates the playback-only > audio device. Ok, that was not clear before. > Once the other direction with max_size_bw=192 is activated > (either duplex or capture-only), Win10 refuses to enumerate. Looking further at the format specification [0] (and crawling the web to decipher it), it seems that * For isochronous links: packet size must match the nominal rate. * For async and adaptative: it must match the nominal rate +/- 1 packet. That is whether we intend on varying the packet size or not. This has several implication * In async mode, the device is running of its own clock. It has no reason to vary the playback packet size but it should still reserve bandwidth for an extra packet to satisfy the spec. This seems to be your problem and what Win10 insist on. When I tested, I had linux on both sides and apparently it is not too picky about that. * If we apply the spec strictly, like Win10 seems to insist on, calculating the maximum packet size based on explicit feedback limits is wrong too. Whatever happens, it should be +/- 1 around nominal. Funny thing, is your change puts a +2 capture compared to nominal but Win10 is not picky on that ... I'll send a fix to clean this up. Thanks reporting the problem. [0]: https://www.usb.org/sites/default/files/frmts10.pdf
Dne 15. 07. 21 v 15:53 Jerome Brunet napsal(a): > > On Thu 15 Jul 2021 at 14:36, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > >> Dne 15. 07. 21 v 11:39 Jerome Brunet napsal(a): >>> On Tue 13 Jul 2021 at 15:16, Pavel Hofman <pavel.hofman@ivitera.com> >>> wrote: >>> > >>> So 48kHz / 2ch / 16bits. Let's assume USB_SPEED_FULL for example (result >>> is the same for the other speeds). >>> In such condition, the nominal packet size is 192B but to accomodate an >>> extra sample, the maximum should indeed be 196B. >>> if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) >>> srate = srate * (1000 + uac2_opts->fb_max) / 1000; >>> with fb_max being 5 by default, srate should be 48240 after this. >>> >>> max_size_bw = num_channels(chmask) * ssize * >>> DIV_ROUND_UP(srate, factor / (1 << (bInterval - 1))); >>> With USB_SPEED_FULL, bInterval is 1 and factor is 1000 so: >>> => DIV_ROUND_UP(48240, 1000 / 1) should give 49; >>> Then >>> => max_size_bw = 2 * 2 * 49 = 196 >>> So the end result should be 196 with current code. I tried on an ARM64 >>> platform. Here is what I get: >>> [ 26.241946] set_ep_max_packet_size: speed is USB_SPEED_FULL >>> [ 26.243208] set_ep_max_packet_size: intermediate Playback srate 48000 >>> [ 26.249758] set_ep_max_packet_size: max_size_bw 192 >>> [ 26.254559] set_ep_max_packet_size: speed is USB_SPEED_FULL >>> [ 26.260130] set_ep_max_packet_size: intermediate Capture srate 48240 >>> [ 26.266401] set_ep_max_packet_size: max_size_bw 196 >>> [ 26.271209] set_ep_max_packet_size: speed is USB_SPEED_HIGH >>> [ 26.276873] set_ep_max_packet_size: intermediate Playback srate 48000 >>> [ 26.283165] set_ep_max_packet_size: max_size_bw 192 >>> [ 26.288015] set_ep_max_packet_size: speed is USB_SPEED_HIGH >>> [ 26.293691] set_ep_max_packet_size: intermediate Capture srate 48240 >>> [ 26.299965] set_ep_max_packet_size: max_size_bw 196 >>> [ 26.304753] set_ep_max_packet_size: speed is USB_SPEED_SUPER >>> [ 26.310426] set_ep_max_packet_size: intermediate Playback srate 48000 >>> [ 26.316805] set_ep_max_packet_size: max_size_bw 192 >>> [ 26.321625] set_ep_max_packet_size: speed is USB_SPEED_SUPER >>> [ 26.327309] set_ep_max_packet_size: intermediate Capture srate 48240 >>> [ 26.333613] set_ep_max_packet_size: max_size_bw 196 >>> All seems OK and as expected with what's in mainline ATM. >>> So I'm not quite sure why you would get a different result. It would be >>> great if you could check further. >>> >> >> The problem is max_size_bw=192 for the Playback (i.e. is_playback = >> true). If only capture direction is activated (p_chmask=0), only EP-OUT >> with max_size_bw=196 is generated and Win10 enumerates the playback-only >> audio device. > > Ok, that was not clear before. > >> Once the other direction with max_size_bw=192 is activated >> (either duplex or capture-only), Win10 refuses to enumerate. > > Looking further at the format specification [0] (and crawling the web to > decipher it), it seems that > > * For isochronous links: packet size must match the nominal rate. > * For async and adaptative: it must match the nominal rate +/- 1 > packet. That is whether we intend on varying the packet size or not. > > This has several implication > * In async mode, the device is running of its own clock. It has no > reason to vary the playback packet size but it should still reserve > bandwidth for an extra packet to satisfy the spec. This seems to be > your problem and what Win10 insist on. > > When I tested, I had linux on both sides and apparently it is not too > picky about that. Linux also accepts the async EP-OUT without the explicit feedback EP-IN, unlike Win10. It also supports implicit async feedback, unlike Win10. But the WASAPI usbaudio2.sys driver in Win10 seems quite OK, I just tested 1536kHz/2ch/16bits playback and works OK, also non-standard samplerates are supported (I tested 512kHz/2ch/32bit), all with overhead of the Win10 running in VMWare Player virtualization. > > * If we apply the spec strictly, like Win10 seems to insist on, > calculating the maximum packet size based on explicit feedback limits > is wrong too. Whatever happens, it should be +/- 1 around nominal. > > Funny thing, is your change puts a +2 capture compared to nominal but > Win10 is not picky on that ... IMO the Win10 driver just makes sure the max packet size is at least the maximum in the specs. If it's more, it does not care - more USB bandwidth is wasted, but the operation is safe. > > I'll send a fix to clean this up. Thanks reporting the problem. Thanks a lot, Pavel.
On Thu, Jul 15, 2021 at 12:40 PM Jerome Brunet <jbrunet@baylibre.com> wrote: > > > On Thu 15 Jul 2021 at 14:36, Pavel Hofman <pavel.hofman@ivitera.com> wrote: > > > Dne 15. 07. 21 v 11:39 Jerome Brunet napsal(a): > >> On Tue 13 Jul 2021 at 15:16, Pavel Hofman <pavel.hofman@ivitera.com> > >> wrote: > >> > > >> So 48kHz / 2ch / 16bits. Let's assume USB_SPEED_FULL for example (result > >> is the same for the other speeds). > >> In such condition, the nominal packet size is 192B but to accomodate an > >> extra sample, the maximum should indeed be 196B. > >> if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) > >> srate = srate * (1000 + uac2_opts->fb_max) / 1000; > >> with fb_max being 5 by default, srate should be 48240 after this. > >> > >> max_size_bw = num_channels(chmask) * ssize * > >> DIV_ROUND_UP(srate, factor / (1 << (bInterval - 1))); > >> With USB_SPEED_FULL, bInterval is 1 and factor is 1000 so: > >> => DIV_ROUND_UP(48240, 1000 / 1) should give 49; > >> Then > >> => max_size_bw = 2 * 2 * 49 = 196 > >> So the end result should be 196 with current code. I tried on an ARM64 > >> platform. Here is what I get: > >> [ 26.241946] set_ep_max_packet_size: speed is USB_SPEED_FULL > >> [ 26.243208] set_ep_max_packet_size: intermediate Playback srate 48000 > >> [ 26.249758] set_ep_max_packet_size: max_size_bw 192 > >> [ 26.254559] set_ep_max_packet_size: speed is USB_SPEED_FULL > >> [ 26.260130] set_ep_max_packet_size: intermediate Capture srate 48240 > >> [ 26.266401] set_ep_max_packet_size: max_size_bw 196 > >> [ 26.271209] set_ep_max_packet_size: speed is USB_SPEED_HIGH > >> [ 26.276873] set_ep_max_packet_size: intermediate Playback srate 48000 > >> [ 26.283165] set_ep_max_packet_size: max_size_bw 192 > >> [ 26.288015] set_ep_max_packet_size: speed is USB_SPEED_HIGH > >> [ 26.293691] set_ep_max_packet_size: intermediate Capture srate 48240 > >> [ 26.299965] set_ep_max_packet_size: max_size_bw 196 > >> [ 26.304753] set_ep_max_packet_size: speed is USB_SPEED_SUPER > >> [ 26.310426] set_ep_max_packet_size: intermediate Playback srate 48000 > >> [ 26.316805] set_ep_max_packet_size: max_size_bw 192 > >> [ 26.321625] set_ep_max_packet_size: speed is USB_SPEED_SUPER > >> [ 26.327309] set_ep_max_packet_size: intermediate Capture srate 48240 > >> [ 26.333613] set_ep_max_packet_size: max_size_bw 196 > >> All seems OK and as expected with what's in mainline ATM. > >> So I'm not quite sure why you would get a different result. It would be > >> great if you could check further. > >> > > > > The problem is max_size_bw=192 for the Playback (i.e. is_playback = > > true). If only capture direction is activated (p_chmask=0), only EP-OUT > > with max_size_bw=196 is generated and Win10 enumerates the playback-only > > audio device. > > Ok, that was not clear before. > > > Once the other direction with max_size_bw=192 is activated > > (either duplex or capture-only), Win10 refuses to enumerate. > > Looking further at the format specification [0] (and crawling the web to > decipher it), it seems that > > * For isochronous links: packet size must match the nominal rate. > * For async and adaptative: it must match the nominal rate +/- 1 > packet. That is whether we intend on varying the packet size or not. > > This has several implication > * In async mode, the device is running of its own clock. It has no > reason to vary the playback packet size but it should still reserve > bandwidth for an extra packet to satisfy the spec. This seems to be > your problem and what Win10 insist on. > > When I tested, I had linux on both sides and apparently it is not too > picky about that. > > * If we apply the spec strictly, like Win10 seems to insist on, > calculating the maximum packet size based on explicit feedback limits > is wrong too. Whatever happens, it should be +/- 1 around nominal. > IIRC, a couple of years ago, Alan proposed a smart scheme to keep the UAC2 byterate in exact sync with what's expected over time. You may have to dig into the alsa archives though. cheers.
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 72b42f8..91b22fb 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -506,6 +506,10 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, max_size_bw = num_channels(chmask) * ssize * ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); + + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) + max_size_bw = max_size_bw * FBACK_FREQ_MAX / 100; + ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, max_size_ep)); Jerome's rebase patch which was accepted recently changed the functionality to the original code: https://patchwork.kernel.org/project/linux-usb/patch/20210603220104.1216001-4-jbrunet@baylibre.com/ diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 321e6c05ba93..ae29ff2b2b68 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -584,8 +584,11 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, ssize = uac2_opts->c_ssize; } + if (!is_playback && (uac2_opts->c_sync == USB_ENDPOINT_SYNC_ASYNC)) + srate = srate * (1000 + uac2_opts->fb_max) / 1000; + max_size_bw = num_channels(chmask) * ssize * - ((srate / (factor / (1 << (ep_desc->bInterval - 1)))) + 1); + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw, max_size_ep)); With this version my Win10 does not enumerate the USB AUDIO device, even if it has only EP-IN capability (i.e. is_playback = true). For my setup the EP-IN wMaxPacketSize is 192bytes vs. 196bytes in Ruslan's version, causing win10 reporting "The specified range could not be found in the range list." A simple change makes Win10 enumerate both playback-only as well as duplex playback/capture async device: diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index ae29ff2b2b68..5ba778814796 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -588,7 +588,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, srate = srate * (1000 + uac2_opts->fb_max) / 1000; max_size_bw = num_channels(chmask) * ssize * - DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); + (DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))) + 1); ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,