Re: [PATCH 0/8] USB Audio Gadget part 2: Feedback endpoint, Volume/Mute support

2021-03-01 Thread Ruslan Bilovol
Hi Johannes,

On Mon, Mar 1, 2021 at 6:49 PM Johannes Freyberger
 wrote:
>
> Hi Ruslan,
>
> thanks for all your efforts to make the USB Audio Gadget work in Win10 using
> UAC2. Meanwhile I managed to apply and compile your previous modifications
> and now my Raspberry PI shows up in the Windows Device Manager as a valid
> UAC2 audio device. Unfortunately it still doesn't work to transfer any audio
> as it seems the audio endpoints or the topology is not working.

Are you testing my previous version of the patches on some older kernel?

Just for records - these two patch sets (part 1 and part 2) are based on Greg's
usb-next branch (commit b5a12546e779d4f5586f58e60e0ef5070a833a64 which
is based on v5.11-rc5 tag). I retested them today with a BBB board and it works
fine under Win 10. Also I rebased these two patchsets today against latest
Greg's usb-next branch which is now Linus's v5.12-rc1 tag and again it works
fine under Win10 - both Volume/Mute controls and audio streaming.

These patches have been tested previously on Raspberry PI 4 running v5.9
and v5.10 stable kernels. The only issues I've seen were because of
Raspberry's DWC2 DMA issue in the driver that I described in this cover letter.
However if you disable volume/mute controls, it won't affect you.

> I checked it
> with some tools and found one providing some information on the USB part
> (it's called UVCview.exe and is part of the Windows Driver Kit). Here's the
> output which I hope can give some hints on the problems still existing in
> this driver:

>From the output below I see UAC2 descriptors are completely screwed up
(or UVCview.exe doesn't show them correctly). Windows is very strict to
the descriptors and doesn't allow devices to start in case of any issues.
So if it appears as a valid UAC2 device in Device Manager, most likely
UVCview.exe doesn't decode UAC2 descriptors well.

Could you please also apply these patches to the latest kernel (v5.12-rc1)
and test?

Thanks,
Ruslan

>
>   ---===>Device Information<===---
> English product name: "Linux USB Audio Gadget"
>
> ConnectionStatus:
> Current Config Value:  0x01  -> Device Bus Speed: High
> Device Address:0x0F
> Open Pipes:   0
> *!*ERROR:  No open pipes!
>
>   ===>Device Descriptor<===
> bLength:   0x12
> bDescriptorType:   0x01
> bcdUSB:  0x0200
> bDeviceClass:  0xEF  -> This is a Multi-interface
> Function Code Device
> bDeviceSubClass:   0x02  -> This is the Common Class Sub
> Class
> bDeviceProtocol:   0x01  -> This is the Interface
> Association Descriptor protocol
> bMaxPacketSize0:   0x40 = (64) Bytes
> idVendor:0x1D6B = The Linux Foundation
> idProduct:   0x0101
> bcdDevice:   0x0510
> iManufacturer: 0x01
>  English (United States)  "Linux 5.10.17-v7l-R3LAY_TEST+ with
> fe98.usb"
> iProduct:  0x02
>  English (United States)  "Linux USB Audio Gadget"
> iSerialNumber: 0x00
> bNumConfigurations:0x01
>
>   ===>Configuration Descriptor<===
> bLength:   0x09
> bDescriptorType:   0x02
> wTotalLength:0x00E2  -> Validated
> bNumInterfaces:0x03
> bConfigurationValue:   0x01
> iConfiguration:0x00
> bmAttributes:  0xC0  -> Bus Powered
> MaxPower:  0x01 =   2 mA
>
>   ===>IAD Descriptor<===
> bLength:   0x08
> bDescriptorType:   0x0B
> bFirstInterface:   0x00
> bInterfaceCount:   0x03
> bFunctionClass:0x01  -> Audio Interface Class
> bFunctionSubClass: 0x00
> *!*CAUTION:This appears to be an invalid bFunctionSubClass
> bFunctionProtocol: 0x20
> iFunction: 0x04
>  English (United States)  "R3lay PI"
>
>   ===>Interface Descriptor<===
> bLength:   0x09
> bDescriptorType:   0x04
> bInterfaceNumber:  0x00
> bAlternateSetting: 0x00
> bNumEndpoints: 0x00
> bInterfaceClass:   0x01  -> Audio Interface Class
> bInterfaceSubClass:0x01  -> Audio Control Interface SubClass
> bInterfaceProtocol:0x20
> CAUTION:  This may be an invalid bInterfaceProtocol
> iInterface:0x05
>  English (United States)  "Topology Control"
>
>   ===>Audio Control Interface Header Descriptor<===
> bLength:   0x09
> bDescriptorType:   0x24
> bDescriptorSubtype:0x01
> bcdADC:  0x0200
> 

[PATCH 8/8] usb: gadget: f_uac1: add volume and mute support

2021-03-01 Thread Ruslan Bilovol
This adds bi-directional (host->device, device->host)
volume/mute support to the f_uac1 driver by adding
Feature Units and interrupt endpoint.

Currently only master channel is supported.

Volume and mute are configurable through configfs,
by default volume has -100..0 dB range with 1 dB step.

Similar to existing flexible endpoints configuration,
Feature Unit won't be added to the topology if both
mute and volume are not enabled, also interrupt endpoint
isn't added to the device if no feature unit is present

Signed-off-by: Ruslan Bilovol 
---
 Documentation/ABI/testing/configfs-usb-gadget-uac1 |  10 +
 Documentation/usb/gadget-testing.rst   |  26 +-
 drivers/usb/gadget/function/f_uac1.c   | 674 -
 drivers/usb/gadget/function/u_uac1.h   |  20 +
 4 files changed, 700 insertions(+), 30 deletions(-)

diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac1 
b/Documentation/ABI/testing/configfs-usb-gadget-uac1
index dc23fd7..dd647d4 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uac1
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uac1
@@ -8,9 +8,19 @@ Description:
c_chmaskcapture channel mask
c_srate capture sampling rate
c_ssize capture sample size (bytes)
+   c_mute_present  capture mute control enable
+   c_volume_presentcapture volume control enable
+   c_volume_mincapture volume control min value (in 1/256 dB)
+   c_volume_maxcapture volume control max value (in 1/256 dB)
+   c_volume_rescapture volume control resolution (in 1/256 dB)
p_chmaskplayback channel mask
p_srate playback sampling rate
p_ssize playback sample size (bytes)
+   p_mute_present  playback mute control enable
+   p_volume_presentplayback volume control enable
+   p_volume_minplayback volume control min value (in 1/256 dB)
+   p_volume_maxplayback volume control max value (in 1/256 dB)
+   p_volume_resplayback volume control resolution (in 1/256 dB)
req_number  the number of pre-allocated request
for both capture and playback
==  ===
diff --git a/Documentation/usb/gadget-testing.rst 
b/Documentation/usb/gadget-testing.rst
index 26adb0b..f078fc9 100644
--- a/Documentation/usb/gadget-testing.rst
+++ b/Documentation/usb/gadget-testing.rst
@@ -914,14 +914,24 @@ The function name to use when creating the function 
directory is "uac1".
 The uac1 function provides these attributes in its function directory:
 
== 
-   c_chmask   capture channel mask
-   c_sratecapture sampling rate
-   c_ssizecapture sample size (bytes)
-   p_chmask   playback channel mask
-   p_srateplayback sampling rate
-   p_ssizeplayback sample size (bytes)
-   req_number the number of pre-allocated request for both capture
-  and playback
+   c_chmaskcapture channel mask
+   c_srate capture sampling rate
+   c_ssize capture sample size (bytes)
+   c_mute_present  capture mute control enable
+   c_volume_presentcapture volume control enable
+   c_volume_mincapture volume control min value (in 1/256 dB)
+   c_volume_maxcapture volume control max value (in 1/256 dB)
+   c_volume_rescapture volume control resolution (in 1/256 dB)
+   p_chmaskplayback channel mask
+   p_srate playback sampling rate
+   p_ssize playback sample size (bytes)
+   p_mute_present  playback mute control enable
+   p_volume_presentplayback volume control enable
+   p_volume_minplayback volume control min value (in 1/256 dB)
+   p_volume_maxplayback volume control max value (in 1/256 dB)
+   p_volume_resplayback volume control resolution (in 1/256 dB)
+   req_number  the number of pre-allocated request for both capture
+   and playback
== 
 
 The attributes have sane default values.
diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index d047075..3b3db1a 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -22,13 +22,26 @@
 /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */
 #define UAC1_CHANNEL_MASK 0x0FFF
 
+#define USB_OUT_FU_ID  (out_feature_unit_desc->bUnitID)
+#define USB_IN_FU_ID   (in_feature_unit_desc->bUnitID)
+
 #define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
 #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+#d

[PATCH 7/8] usb: gadget: f_uac2: add volume and mute support

2021-03-01 Thread Ruslan Bilovol
This adds bi-directional (host->device, device->host)
volume/mute support to the f_uac2 driver by adding
Feature Units and interrupt endpoint.

Currently only master channel is supported.

Volume and mute are configurable through configfs,
by default volume has -100..0 dB range with 1 dB step.

Similar to existing flexible endpoints configuration,
Feature Unit won't be added to the topology if both
mute and volume are not enabled, also interrupt endpoint
isn't added to the device if no feature unit is present

Signed-off-by: Ruslan Bilovol 
---
 Documentation/ABI/testing/configfs-usb-gadget-uac2 |  10 +
 Documentation/usb/gadget-testing.rst   |  10 +
 drivers/usb/gadget/function/f_uac2.c   | 640 +++--
 drivers/usb/gadget/function/u_uac2.h   |  21 +
 4 files changed, 623 insertions(+), 58 deletions(-)

diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac2 
b/Documentation/ABI/testing/configfs-usb-gadget-uac2
index e7e59d7..9242234 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uac2
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uac2
@@ -9,7 +9,17 @@ Description:
c_sratecapture sampling rate
c_ssizecapture sample size (bytes)
c_sync capture synchronization type (async/adaptive)
+   c_mute_present  capture mute control enable
+   c_volume_presentcapture volume control enable
+   c_volume_mincapture volume control min value (in 1/256 dB)
+   c_volume_maxcapture volume control max value (in 1/256 dB)
+   c_volume_rescapture volume control resolution (in 1/256 dB)
p_chmask   playback channel mask
p_srateplayback sampling rate
p_ssizeplayback sample size (bytes)
+   p_mute_present  playback mute control enable
+   p_volume_presentplayback volume control enable
+   p_volume_minplayback volume control min value (in 1/256 dB)
+   p_volume_maxplayback volume control max value (in 1/256 dB)
+   p_volume_resplayback volume control resolution (in 1/256 dB)
=  
diff --git a/Documentation/usb/gadget-testing.rst 
b/Documentation/usb/gadget-testing.rst
index f5a1266..26adb0b 100644
--- a/Documentation/usb/gadget-testing.rst
+++ b/Documentation/usb/gadget-testing.rst
@@ -729,9 +729,19 @@ The uac2 function provides these attributes in its 
function directory:
c_srate capture sampling rate
c_ssize capture sample size (bytes)
c_sync  capture synchronization type (async/adaptive)
+   c_mute_present  capture mute control enable
+   c_volume_presentcapture volume control enable
+   c_volume_mincapture volume control min value (in 1/256 dB)
+   c_volume_maxcapture volume control max value (in 1/256 dB)
+   c_volume_rescapture volume control resolution (in 1/256 dB)
p_chmaskplayback channel mask
p_srate playback sampling rate
p_ssize playback sample size (bytes)
+   p_mute_present  playback mute control enable
+   p_volume_presentplayback volume control enable
+   p_volume_minplayback volume control min value (in 1/256 dB)
+   p_volume_maxplayback volume control max value (in 1/256 dB)
+   p_volume_resplayback volume control resolution (in 1/256 dB)
req_number  the number of pre-allocated request for both capture
and playback
=== 
diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index 91b22fb..57f6bcb6 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -5,6 +5,9 @@
  * Copyright (C) 2011
  *Yadwinder Singh (yadi.bra...@gmail.com)
  *Jaswinder Singh (jaswinder.si...@linaro.org)
+ *
+ * Copyright (C) 2020
+ *Ruslan Bilovol (ruslan.bilo...@gmail.com)
  */
 
 #include 
@@ -19,14 +22,16 @@
 
 /*
  * The driver implements a simple UAC_2 topology.
- * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
- * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN
+ * USB-OUT -> IT_1 -> FU -> OT_3 -> ALSA_Capture
+ * ALSA_Playback -> IT_2 -> FU -> OT_4 -> USB-IN
  * Capture and Playback sampling rates are independently
  *  controlled by two clock sources :
  *CLK_5 := c_srate, and CLK_6 := p_srate
  */
 #define USB_OUT_CLK_ID (out_clk_src_desc.bClockID)
 #define USB_IN_CLK_ID  (in_clk_src_desc.bClockID)
+#define USB_OUT_FU_ID  (out_feature_unit_desc->bUnitID)
+#define USB_IN_FU_ID   (in_feature_unit_desc->bUnitID)
 
 #define CONTROL_ABSENT 0
 #define CONTROL_RDONLY 1
@@ -34,6 +39,8 @@
 
 #define CLK_FREQ_CTRL  0
 #define CLK_VLD_CTRL  

[PATCH 4/8] usb: gadget: u_audio: add real feedback implementation

2021-03-01 Thread Ruslan Bilovol
This adds interface between userspace and feedback
endpoint to report real feedback frequency to the Host.

Current implementation adds new userspace interface
ALSA mixer control "PCM Feedback Frequency Hz" (similar
to aloop driver's "PCM Rate Shift 10" mixer control)

We allow +/-20% deviation of nominal sampling frequency,
that usually is more than enough in real-world usecases

Usage of this new control is easy to implement in
existing userspace tools like alsaloop from alsa-utils.

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac2.c  |  4 ++
 drivers/usb/gadget/function/u_audio.c | 93 +++
 drivers/usb/gadget/function/u_audio.h |  7 +++
 3 files changed, 104 insertions(+)

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));
 
diff --git a/drivers/usb/gadget/function/u_audio.c 
b/drivers/usb/gadget/function/u_audio.c
index 8e74b54..b434e70 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "u_audio.h"
 
@@ -598,12 +599,87 @@ void u_audio_stop_playback(struct g_audio *audio_dev)
 }
 EXPORT_SYMBOL_GPL(u_audio_stop_playback);
 
+static int u_audio_rate_shift_info(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_info *uinfo)
+{
+   struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+   struct snd_uac_chip *uac = prm->uac;
+   struct g_audio *audio_dev = uac->audio_dev;
+   struct uac_params *params = _dev->params;
+   unsigned int ffback_min, ffback_max;
+
+   ffback_min = params->c_srate * FBACK_FREQ_MIN / 100;
+   ffback_max = params->c_srate * FBACK_FREQ_MAX / 100;
+
+   uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+   uinfo->count = 1;
+   uinfo->value.integer.min = ffback_min;
+   uinfo->value.integer.max = ffback_max;
+   uinfo->value.integer.step = 1;
+   return 0;
+}
+
+static int u_audio_rate_shift_get(struct snd_kcontrol *kcontrol,
+  struct snd_ctl_elem_value *ucontrol)
+{
+   struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+   unsigned long flags;
+
+   spin_lock_irqsave(>lock, flags);
+   ucontrol->value.integer.value[0] = prm->ffback;
+   spin_unlock_irqrestore(>lock, flags);
+
+   return 0;
+}
+
+static int u_audio_rate_shift_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+   struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
+   struct snd_uac_chip *uac = prm->uac;
+   struct g_audio *audio_dev = uac->audio_dev;
+   struct uac_params *params = _dev->params;
+   unsigned int val;
+   unsigned int ffback_min, ffback_max;
+   unsigned long flags;
+   int change = 0;
+
+   ffback_min = params->c_srate * FBACK_FREQ_MIN / 100;
+   ffback_max = params->c_srate * FBACK_FREQ_MAX / 100;
+
+   val = ucontrol->value.integer.value[0];
+   if (val < ffback_min)
+   val = ffback_min;
+   if (val > ffback_max)
+   val = ffback_max;
+
+   spin_lock_irqsave(>lock, flags);
+   if (prm->ffback != val) {
+   prm->ffback = val;
+   change = 1;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   return change;
+}
+
+static const struct snd_kcontrol_new u_audio_controls[]  = {
+{
+   .iface =SNDRV_CTL_ELEM_IFACE_PCM,
+   .name = "PCM Feedback Frequency Hz",
+   .info = u_audio_rate_shift_info,
+   .get =  u_audio_rate_shift_get,
+   .put =  u_audio_rate_shift_put,
+},
+};
+
 int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
const char *card_name)
 {
struct snd_uac_chip *uac;
struct snd_card *card;
struct snd_pcm *pcm;
+   struct snd_kcontrol *kctl;
struct uac_params *params;
int p_chmask, c_chmask;
int err;
@@ -693,6 +769,23 @@ int g_audio_setup(struct g_audio *g_audio, const char 
*pcm_name,
snd_pcm_set_ops(pcm, SNDRV_PCM

[PATCH 6/8] usb: gadget: u_audio: add bi-directional volume and mute support

2021-03-01 Thread Ruslan Bilovol
USB Audio Class 1/2 have ability to change device's
volume and mute by USB Host through class-specific control
requests. Device also can notify Host about volume/mute
change on its side through optional interrupt endpoint.

This patch adds Volume and Mute ALSA controls which can be
used by user to send and receive notifications to/from
the USB Host about Volume and Mute change.

These params come from f_uac* so volume and mute controls
will be created only if the function support and enable
each explicitly

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/u_audio.c | 360 +-
 drivers/usb/gadget/function/u_audio.h |  22 +++
 2 files changed, 372 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/gadget/function/u_audio.c 
b/drivers/usb/gadget/function/u_audio.c
index b434e70..f4b850b 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -12,11 +12,14 @@
  *Jaswinder Singh (jaswinder.si...@linaro.org)
  */
 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include "u_audio.h"
 
@@ -24,6 +27,12 @@
 #define PRD_SIZE_MAX   PAGE_SIZE
 #define MIN_PERIODS4
 
+enum {
+   UAC_FBACK_CTRL,
+   UAC_MUTE_CTRL,
+   UAC_VOLUME_CTRL,
+};
+
 /* Runtime data params for one stream */
 struct uac_rtd_params {
struct snd_uac_chip *uac; /* parent chip */
@@ -44,6 +53,14 @@ struct uac_rtd_params {
unsigned int ffback; /* Real frequency reported by feedback endpoint */
bool fb_ep_enabled; /* if the ep is enabled */
 
+   /* Volume/Mute controls and their state */
+   int fu_id; /* Feature Unit ID */
+   struct snd_kcontrol *snd_kctl_volume;
+   struct snd_kcontrol *snd_kctl_mute;
+   s16 volume_min, volume_max, volume_res;
+   s16 volume;
+   int mute;
+
spinlock_t lock; /* lock for feedback and control transfers */
 };
 
@@ -599,6 +616,102 @@ void u_audio_stop_playback(struct g_audio *audio_dev)
 }
 EXPORT_SYMBOL_GPL(u_audio_stop_playback);
 
+int u_audio_get_volume(struct g_audio *audio_dev, int playback, s16 *val)
+{
+   struct snd_uac_chip *uac = audio_dev->uac;
+   struct uac_rtd_params *prm;
+   unsigned long flags;
+
+   if (playback)
+   prm = >p_prm;
+   else
+   prm = >c_prm;
+
+   spin_lock_irqsave(>lock, flags);
+   *val = prm->volume;
+   spin_unlock_irqrestore(>lock, flags);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(u_audio_get_volume);
+
+int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val)
+{
+   struct snd_uac_chip *uac = audio_dev->uac;
+   struct uac_rtd_params *prm;
+   unsigned long flags;
+   int change = 0;
+
+   if (playback)
+   prm = >p_prm;
+   else
+   prm = >c_prm;
+
+   spin_lock_irqsave(>lock, flags);
+   val = clamp(val, prm->volume_min, prm->volume_max);
+   if (prm->volume != val) {
+   prm->volume = val;
+   change = 1;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   if (change)
+   snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
+   >snd_kctl_volume->id);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(u_audio_set_volume);
+
+int u_audio_get_mute(struct g_audio *audio_dev, int playback, int *val)
+{
+   struct snd_uac_chip *uac = audio_dev->uac;
+   struct uac_rtd_params *prm;
+   unsigned long flags;
+
+   if (playback)
+   prm = >p_prm;
+   else
+   prm = >c_prm;
+
+   spin_lock_irqsave(>lock, flags);
+   *val = prm->mute;
+   spin_unlock_irqrestore(>lock, flags);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(u_audio_get_mute);
+
+int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val)
+{
+   struct snd_uac_chip *uac = audio_dev->uac;
+   struct uac_rtd_params *prm;
+   unsigned long flags;
+   int change = 0;
+   int mute;
+
+   if (playback)
+   prm = >p_prm;
+   else
+   prm = >c_prm;
+
+   mute = val ? 1 : 0;
+
+   spin_lock_irqsave(>lock, flags);
+   if (prm->mute != mute) {
+   prm->mute = mute;
+   change = 1;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   if (change)
+   snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
+  >snd_kctl_mute->id);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(u_audio_set_mute);
+
 static int u_audio_rate_shift_info(struct snd_kcontrol *kcontrol,
   struct snd_ctl_elem_info *uinfo)
 {
@@ -663,14 +776,157 @@ static int u_audio_rate_shift_put(struct snd_kcontrol 
*kcontrol,
return change;
 }
 
-static const struct snd_kcontrol_new u_audio_controls[]  = {
+static int u_a

[PATCH 5/8] usb: audio-v2: add ability to define feature unit descriptor

2021-03-01 Thread Ruslan Bilovol
Similar to UAC1 spec, UAC2 feature unit descriptor
has variable size.

Current audio-v2 feature unit descriptor structure
is used for parsing descriptors, but can't be used
to define your own descriptor.

Add a new macro similar to what audio v1 already has.

Signed-off-by: Ruslan Bilovol 
---
 include/linux/usb/audio-v2.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index ead8c9a..8fc2abd 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -156,6 +156,20 @@ struct uac2_feature_unit_descriptor {
__u8 bmaControls[]; /* variable length */
 } __attribute__((packed));
 
+#define UAC2_DT_FEATURE_UNIT_SIZE(ch)  (6 + ((ch) + 1) * 4)
+
+/* As above, but more useful for defining your own descriptors: */
+#define DECLARE_UAC2_FEATURE_UNIT_DESCRIPTOR(ch)   \
+struct uac2_feature_unit_descriptor_##ch { \
+   __u8  bLength;  \
+   __u8  bDescriptorType;  \
+   __u8  bDescriptorSubtype;   \
+   __u8  bUnitID;  \
+   __u8  bSourceID;\
+   __le32 bmaControls[ch + 1]; \
+   __u8  iFeature; \
+} __packed
+
 /* 4.7.2.10 Effect Unit Descriptor */
 
 struct uac2_effect_unit_descriptor {
-- 
1.9.1



[PATCH 2/8] usb: gadget: f_uac2/u_audio: add feedback endpoint support

2021-03-01 Thread Ruslan Bilovol
As per USB and UAC2 specs, asynchronous audio sink endpoint
requires explicit synchronization mechanism (Isochronous
Feedback Endpoint)

Implement feedback companion endpoint for ISO OUT endpoint

This patch adds all required infrastructure and USB requests
handling for feedback endpoint. Syncrhonization itself is
still dummy (feedback ep always reports 'nomimal frequency'
 e.g. no adjustement is needed). This satisfies hosts that
require feedback endpoint (like Win10) and poll it periodically

Actual synchronization mechanism should be implemented
separately

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac2.c  |  34 +++-
 drivers/usb/gadget/function/u_audio.c | 141 +-
 drivers/usb/gadget/function/u_audio.h |   3 +
 3 files changed, 175 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index f868e38..6f7b7c1 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -240,7 +240,7 @@ enum {
.bDescriptorType = USB_DT_INTERFACE,
 
.bAlternateSetting = 1,
-   .bNumEndpoints = 1,
+   .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
.bInterfaceProtocol = UAC_VERSION_2,
@@ -299,6 +299,27 @@ enum {
.wLockDelay = 0,
 };
 
+/* STD AS ISO IN Feedback Endpoint */
+static struct usb_endpoint_descriptor fs_epin_fback_desc = {
+   .bLength = USB_DT_ENDPOINT_SIZE,
+   .bDescriptorType = USB_DT_ENDPOINT,
+
+   .bEndpointAddress = USB_DIR_IN,
+   .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+   .wMaxPacketSize = cpu_to_le16(3),
+   .bInterval = 1,
+};
+
+static struct usb_endpoint_descriptor hs_epin_fback_desc = {
+   .bLength = USB_DT_ENDPOINT_SIZE,
+   .bDescriptorType = USB_DT_ENDPOINT,
+
+   .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_USAGE_FEEDBACK,
+   .wMaxPacketSize = cpu_to_le16(4),
+   .bInterval = 4,
+};
+
+
 /* Audio Streaming IN Interface - Alt0 */
 static struct usb_interface_descriptor std_as_in_if0_desc = {
.bLength = sizeof std_as_in_if0_desc,
@@ -395,6 +416,7 @@ enum {
(struct usb_descriptor_header *)_out_fmt1_desc,
(struct usb_descriptor_header *)_epout_desc,
(struct usb_descriptor_header *)_iso_out_desc,
+   (struct usb_descriptor_header *)_epin_fback_desc,
 
(struct usb_descriptor_header *)_as_in_if0_desc,
(struct usb_descriptor_header *)_as_in_if1_desc,
@@ -425,6 +447,7 @@ enum {
(struct usb_descriptor_header *)_out_fmt1_desc,
(struct usb_descriptor_header *)_epout_desc,
(struct usb_descriptor_header *)_iso_out_desc,
+   (struct usb_descriptor_header *)_epin_fback_desc,
 
(struct usb_descriptor_header *)_as_in_if0_desc,
(struct usb_descriptor_header *)_as_in_if1_desc,
@@ -562,6 +585,7 @@ static void setup_descriptor(struct f_uac2_opts *opts)
fs_audio_desc[i++] = USBDHDR(_out_fmt1_desc);
fs_audio_desc[i++] = USBDHDR(_epout_desc);
fs_audio_desc[i++] = USBDHDR(_iso_out_desc);
+   fs_audio_desc[i++] = USBDHDR(_epin_fback_desc);
}
if (EPIN_EN(opts)) {
fs_audio_desc[i++] = USBDHDR(_as_in_if0_desc);
@@ -595,6 +619,7 @@ static void setup_descriptor(struct f_uac2_opts *opts)
hs_audio_desc[i++] = USBDHDR(_out_fmt1_desc);
hs_audio_desc[i++] = USBDHDR(_epout_desc);
hs_audio_desc[i++] = USBDHDR(_iso_out_desc);
+   hs_audio_desc[i++] = USBDHDR(_epin_fback_desc);
}
if (EPIN_EN(opts)) {
hs_audio_desc[i++] = USBDHDR(_as_in_if0_desc);
@@ -757,6 +782,12 @@ static int afunc_validate_opts(struct g_audio *agdev, 
struct device *dev)
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
return -ENODEV;
}
+   agdev->in_ep_fback = usb_ep_autoconfig(gadget,
+  _epin_fback_desc);
+   if (!agdev->in_ep_fback) {
+   dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
+   return -ENODEV;
+   }
}
 
if (EPIN_EN(uac2_opts)) {
@@ -775,6 +806,7 @@ static int afunc_validate_opts(struct g_audio *agdev, 
struct device *dev)
le16_to_cpu(hs_epout_desc.wMaxPacketSize));
 
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+   hs_epin_fback_desc.bEndpointAddress = 
fs_epin_fback_desc.bEndpointAddress;
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
 
setup_descriptor(uac2_opts);
diff --git a/drivers/usb/gadget/function/u_audio.c 
b/drivers/usb/gadget/function/u_audio.c
index 5fbceee..8e74b54 10064

[PATCH 1/8] usb: gadget: u_audio: convert to strscpy

2021-03-01 Thread Ruslan Bilovol
Usage of strlcpy in Linux Kernel has been recently
deprecated [1], convert driver to strscpy

[1] 
https://lore.kernel.org/lkml/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=v6a6g1ouzcprm...@mail.gmail.com/

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/u_audio.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/function/u_audio.c 
b/drivers/usb/gadget/function/u_audio.c
index 265c4d8..5fbceee 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -549,15 +549,15 @@ int g_audio_setup(struct g_audio *g_audio, const char 
*pcm_name,
if (err < 0)
goto snd_fail;
 
-   strlcpy(pcm->name, pcm_name, sizeof(pcm->name));
+   strscpy(pcm->name, pcm_name, sizeof(pcm->name));
pcm->private_data = uac;
uac->pcm = pcm;
 
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, _pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, _pcm_ops);
 
-   strlcpy(card->driver, card_name, sizeof(card->driver));
-   strlcpy(card->shortname, card_name, sizeof(card->shortname));
+   strscpy(card->driver, card_name, sizeof(card->driver));
+   strscpy(card->shortname, card_name, sizeof(card->shortname));
sprintf(card->longname, "%s %i", card_name, card->dev->id);
 
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-- 
1.9.1



[PATCH 3/8] usb: gadget: f_uac2: add adaptive sync support for capture

2021-03-01 Thread Ruslan Bilovol
Current f_uac2 USB OUT (aka 'capture') synchronization
implements 'ASYNC' scenario which means USB Gadget has
it's own freerunning clock and can update Host about
real clock frequency through feedback endpoint so Host
can align number of samples sent to the USB gadget to
prevent overruns/underruns

In case if Gadget can has no it's internal clock and
can consume audio samples at any rate (for example,
on the Gadget side someone records audio directly to
a file, or audio samples are played through an
external DAC as soon as they arrive), UAC2 spec
suggests 'ADAPTIVE' synchronization type.

Change UAC2 driver to make it configurable through
additional 'c_sync' configfs file.

Default remains 'asynchronous' with possibility to
switch it to 'adaptive'

Signed-off-by: Ruslan Bilovol 
---
 Documentation/ABI/testing/configfs-usb-gadget-uac2 |   1 +
 Documentation/usb/gadget-testing.rst   |   1 +
 drivers/usb/gadget/function/f_uac2.c   | 102 ++---
 drivers/usb/gadget/function/u_uac2.h   |   2 +
 4 files changed, 95 insertions(+), 11 deletions(-)

diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uac2 
b/Documentation/ABI/testing/configfs-usb-gadget-uac2
index d4356c8..e7e59d7 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget-uac2
+++ b/Documentation/ABI/testing/configfs-usb-gadget-uac2
@@ -8,6 +8,7 @@ Description:
c_chmask   capture channel mask
c_sratecapture sampling rate
c_ssizecapture sample size (bytes)
+   c_sync capture synchronization type (async/adaptive)
p_chmask   playback channel mask
p_srateplayback sampling rate
p_ssizeplayback sample size (bytes)
diff --git a/Documentation/usb/gadget-testing.rst 
b/Documentation/usb/gadget-testing.rst
index 2085e7b..f5a1266 100644
--- a/Documentation/usb/gadget-testing.rst
+++ b/Documentation/usb/gadget-testing.rst
@@ -728,6 +728,7 @@ The uac2 function provides these attributes in its function 
directory:
c_chmaskcapture channel mask
c_srate capture sampling rate
c_ssize capture sample size (bytes)
+   c_sync  capture synchronization type (async/adaptive)
p_chmaskplayback channel mask
p_srate playback sampling rate
p_ssize playback sample size (bytes)
diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index 6f7b7c1..72b42f8 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -44,6 +44,7 @@
 
 #define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
 #define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+#define EPOUT_FBACK_IN_EN(_opts) ((_opts)->c_sync == USB_ENDPOINT_SYNC_ASYNC)
 
 struct f_uac2 {
struct g_audio g_audio;
@@ -240,7 +241,7 @@ enum {
.bDescriptorType = USB_DT_INTERFACE,
 
.bAlternateSetting = 1,
-   .bNumEndpoints = 2,
+   /* .bNumEndpoints = DYNAMIC */
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
.bInterfaceProtocol = UAC_VERSION_2,
@@ -273,7 +274,7 @@ enum {
.bDescriptorType = USB_DT_ENDPOINT,
 
.bEndpointAddress = USB_DIR_OUT,
-   .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+   /* .bmAttributes = = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 1,
 };
@@ -282,7 +283,7 @@ enum {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
 
-   .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+   /* .bmAttributes = = DYNAMIC */
/* .wMaxPacketSize = DYNAMIC */
.bInterval = 1,
 };
@@ -544,6 +545,8 @@ static void setup_descriptor(struct f_uac2_opts *opts)
iad_desc.bInterfaceCount = 1;
ac_hdr_desc.wTotalLength = cpu_to_le16(sizeof(ac_hdr_desc));
 
+   std_as_out_if1_desc.bNumEndpoints = 1;
+
if (EPIN_EN(opts)) {
u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength);
 
@@ -561,6 +564,19 @@ static void setup_descriptor(struct f_uac2_opts *opts)
len += sizeof(io_out_ot_desc);
ac_hdr_desc.wTotalLength = cpu_to_le16(len);
iad_desc.bInterfaceCount++;
+
+   fs_epout_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
+   hs_epout_desc.bmAttributes = USB_ENDPOINT_XFER_ISOC;
+   if (EPOUT_FBACK_IN_EN(opts)) {
+   fs_epout_desc.bmAttributes |= USB_ENDPOINT_SYNC_ASYNC;
+   hs_epout_desc.bmAttributes |= USB_ENDPOINT_SYNC_ASYNC;
+   std_as_out_if1_desc.bNumEndpoints++;
+   } else {
+   fs_epout_desc.bmAttributes |=
+   USB_ENDPOINT_SYNC_ADAPTIVE;
+   hs_epout_desc.bmA

[PATCH 0/8] USB Audio Gadget part 2: Feedback endpoint, Volume/Mute support

2021-03-01 Thread Ruslan Bilovol
This is extendend version of "UAC2 Feedback endpoint" patch set
I've sent back in 2020 [1]. It is extended with
bi-directional Volume/Mute controls support for both UAC1
and UAC2 gadgets.

It fixes issues with enumeration in various operation systems
because of Feedback endpoint implementation, yet also adds
new Volume/Mute support which allows developers to control
UAC1/2 Gadget's Volume/Mute from the Host and in the same way
UAC1/2 Gadget can control Volume/Mute of the Host making it
closer to a real USB Audio card.

This patch set should be applied on top of USB Audio Gadget
part 1 fixes/improvements that I've sent previously to the
mailing list [2]

 UAC2 Feedback Endpoint support 

Current UAC2 gadget implements capture/sync paths
as two USB ISO ASYNC endpoints (IN and OUT).

This violates USB spec which says that ISO ASYNC OUT endpoint
should have feedback companion endpoint.
See USB2.0 spec  "5.12.4.1 Synchronization Type": asynchronous
sink provides explicit feedback (isochronous pipe).
Interesting that for ISO ASYNC *IN* endpoint respective
feedback isn't required since source provides implicit
feedforward (data stream).

While it's not an issue if UAC2 Gadget is connected to
Linux host (Linux ignores missing feedback endpoint),
with other hosts like Windows or MacOS the UAC2 Gadget
isn't enumerated due to missing feedback endpoint.

This patch series adds feedback endpoint support to
UAC2 function, new control to UAC2 mixer which can
be used by userspace tools (like alsaloop from alsa-utils)
for updating feedback frequency reported to the host.
This is useful for usecases when UAC2 Gadget's audio
samples are played to another codec or audio card
with its own internal freerunning clock so host can
be notified that more/less samples are required.

The alsaloop tool requires some (relatively small)
modifications in order to start support driving
feedback frequency through UAC2 mixer control.
That change have been sent as a separate patch
to ALSA community [3].

Also added ability to switch ISO ASYNC OUT endpoint into
adaptive endpoint which doesn't require feedback endpoint
(as per USB spec).

 UAC1/2 Volume/Mute controls support ==

Volume and Mute controls are traditionally presented in
USB Audio cards that are available on the market,
and Hosts usually expect they exist in the attached devices.

However, Linux UAC gadget previosly didn't have such
functinality which (depending on Host's operation system)
was causing different behaviour: Linux hosts (usually) in
this case can adjust volume by changing audio sample's
amplitude that are sent to the gadget. Other hosts may
stuck with maximum volume and can't adjust it for the
Linux UAC gadget device.

Volume/Mute controls support is quite useful feature.
If implemented according to UAC1/2 spec, it allows to
control volume in both directions: from the Host to Gadget
and from Gadget to the Host. To do it, it's required to add
new Feature Unit descriptor to existing UAC1/2 Gadget
topology and add new interrupt endpoint so Volume/Mute
changes can be reported to the Host.

This has been tested with Linux/MacOS/Windows(7,10) hosts,
by attaching alsamixer to the UAC1/2 ALSA card on Gadget
side, and using available Volume/Mute control applications
on the Hosts.

An user can adjust Volume/Mute on the Host and see respective
changes on the Gadget side. In the same way, an user can adjust
Volume/Mute on the Gadget side and observe respective changes
on the Host

There is a known issue with Win7 which for some reason doesn't
poll UAC1 interrupt endpoint causing Volume/Mute control not
working in Gadget->Host direction



Both features have been tested on BeagleBone Black and
Raspberry PI 4 boards with Linux/MacOS/Windows(7,10) hosts.

While on BeagleBone Black it works fine, Raspberry PI 4 DWC2
controller is affected by the DMA issue for control trasfers
which I reported a while back in [4]. It is causing incorrect
data provided by DWC2 UDC to UAC1/2 gadgets screwing up
volume and mute control messages in the Host->Gadget direction.
The hack is available (see [4]) but it leads to traces/issues
with audio streaming.

Patches reviews and testing on your HW is welcome as usual!

[1] 
https://lore.kernel.org/linux-usb/1604794711-8661-1-git-send-email-ruslan.bilo...@gmail.com/
[2] 
https://lore.kernel.org/linux-usb/1614599375-8803-1-git-send-email-ruslan.bilo...@gmail.com/
[3] 
https://lore.kernel.org/linux-usb/1605220482-28487-1-git-send-email-ruslan.bilo...@gmail.com/
[4] 
https://lore.kernel.org/linux-usb/CAB=otbTVxa=ngwf4k1aycyypceyyrkc_1hysb_nhu6c9rmz...@mail.gmail.com/

Ruslan Bilovol (8):
  usb: gadget: u_audio: convert to strscpy
  usb: gadget: f_uac2/u_audio: add feedback endpoint support
  usb: gadget: f_uac2: add adaptive sync support for capture
  usb: gadget: u_audio: add real feedback implementation
  usb: audio-v2: add abil

[PATCH v2 4/5] usb: gadget: f_uac1: validate input parameters

2021-03-01 Thread Ruslan Bilovol
Currently user can configure UAC1 function with
parameters that violate UAC1 spec or are not supported
by UAC1 gadget implementation.

This can lead to incorrect behavior if such gadget
is connected to the host - like enumeration failure
or other issues depending on host's UAC1 driver
implementation, bringing user to a long hours
of debugging the issue.

Instead of silently accept these parameters, throw
an error if they are not valid.

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac1.c | 43 
 1 file changed, 43 insertions(+)

diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index 560382e..e65f474 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -19,6 +19,9 @@
 #include "u_audio.h"
 #include "u_uac1.h"
 
+/* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */
+#define UAC1_CHANNEL_MASK 0x0FFF
+
 struct f_uac1 {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
@@ -30,6 +33,11 @@ static inline struct f_uac1 *func_to_uac1(struct 
usb_function *f)
return container_of(f, struct f_uac1, g_audio.func);
 }
 
+static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio)
+{
+   return container_of(audio->func.fi, struct f_uac1_opts, func_inst);
+}
+
 /*
  * DESCRIPTORS ... most are static, but strings and full
  * configuration descriptors are built on demand.
@@ -505,11 +513,42 @@ static void f_audio_disable(struct usb_function *f)
 
 /*-*/
 
+static int f_audio_validate_opts(struct g_audio *audio, struct device *dev)
+{
+   struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio);
+
+   if (!opts->p_chmask && !opts->c_chmask) {
+   dev_err(dev, "Error: no playback and capture channels\n");
+   return -EINVAL;
+   } else if (opts->p_chmask & ~UAC1_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported playback channels mask\n");
+   return -EINVAL;
+   } else if (opts->c_chmask & ~UAC1_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported capture channels mask\n");
+   return -EINVAL;
+   } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
+   dev_err(dev, "Error: incorrect playback sample size\n");
+   return -EINVAL;
+   } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
+   dev_err(dev, "Error: incorrect capture sample size\n");
+   return -EINVAL;
+   } else if (!opts->p_srate) {
+   dev_err(dev, "Error: incorrect playback sampling rate\n");
+   return -EINVAL;
+   } else if (!opts->c_srate) {
+   dev_err(dev, "Error: incorrect capture sampling rate\n");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 /* audio function driver setup/binding */
 static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 {
struct usb_composite_dev*cdev = c->cdev;
struct usb_gadget   *gadget = cdev->gadget;
+   struct device   *dev = >dev;
struct f_uac1   *uac1 = func_to_uac1(f);
struct g_audio  *audio = func_to_g_audio(f);
struct f_uac1_opts  *audio_opts;
@@ -519,6 +558,10 @@ static int f_audio_bind(struct usb_configuration *c, 
struct usb_function *f)
int rate;
int status;
 
+   status = f_audio_validate_opts(audio, dev);
+   if (status)
+   return status;
+
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
 
us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1));
-- 
1.9.1



[PATCH v2 5/5] usb: gadget: f_uac1: disable IN/OUT ep if unused

2021-03-01 Thread Ruslan Bilovol
User can configure f_uac1 function via p_chmask/c_chmask
whether uac1 shall support playback and/or capture,
but it has only effect on the created ALSA device,
but not on the USB descriptor.

This patch adds playback/capture descriptors
dependent on that parameter. It is similar to
the same conversion done earlier for f_uac2

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac1.c | 229 +--
 1 file changed, 163 insertions(+), 66 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index e65f474..d047075 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -22,6 +22,9 @@
 /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */
 #define UAC1_CHANNEL_MASK 0x0FFF
 
+#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
+#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+
 struct f_uac1 {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
@@ -50,11 +53,6 @@ static inline struct f_uac1_opts 
*g_audio_to_uac1_opts(struct g_audio *audio)
  * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture
  * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN
  */
-#define F_AUDIO_AC_INTERFACE   0
-#define F_AUDIO_AS_OUT_INTERFACE   1
-#define F_AUDIO_AS_IN_INTERFACE2
-/* Number of streaming interfaces */
-#define F_AUDIO_NUM_INTERFACES 2
 
 /* B.3.1  Standard AC Interface Descriptor */
 static struct usb_interface_descriptor ac_interface_desc = {
@@ -65,73 +63,47 @@ static inline struct f_uac1_opts 
*g_audio_to_uac1_opts(struct g_audio *audio)
.bInterfaceSubClass =   USB_SUBCLASS_AUDIOCONTROL,
 };
 
-/*
- * The number of AudioStreaming and MIDIStreaming interfaces
- * in the Audio Interface Collection
- */
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
-
-#define UAC_DT_AC_HEADER_LENGTH
UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
-/* 2 input terminals and 2 output terminals */
-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
-   + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE)
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
-   .bLength =  UAC_DT_AC_HEADER_LENGTH,
-   .bDescriptorType =  USB_DT_CS_INTERFACE,
-   .bDescriptorSubtype =   UAC_HEADER,
-   .bcdADC =   cpu_to_le16(0x0100),
-   .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH),
-   .bInCollection =F_AUDIO_NUM_INTERFACES,
-   .baInterfaceNr = {
-   /* Interface number of the AudioStream interfaces */
-   [0] =   1,
-   [1] =   2,
-   }
-};
+static struct uac1_ac_header_descriptor *ac_header_desc;
 
-#define USB_OUT_IT_ID  1
 static struct uac_input_terminal_descriptor usb_out_it_desc = {
.bLength =  UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType =  USB_DT_CS_INTERFACE,
.bDescriptorSubtype =   UAC_INPUT_TERMINAL,
-   .bTerminalID =  USB_OUT_IT_ID,
+   /* .bTerminalID =   DYNAMIC */
.wTerminalType =cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal =   0,
.wChannelConfig =   cpu_to_le16(0x3),
 };
 
-#define IO_OUT_OT_ID   2
 static struct uac1_output_terminal_descriptor io_out_ot_desc = {
.bLength= UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType= USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
-   .bTerminalID= IO_OUT_OT_ID,
+   /* .bTerminalID =   DYNAMIC */
.wTerminalType  = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
.bAssocTerminal = 0,
-   .bSourceID  = USB_OUT_IT_ID,
+   /* .bSourceID = DYNAMIC */
 };
 
-#define IO_IN_IT_ID3
 static struct uac_input_terminal_descriptor io_in_it_desc = {
.bLength= UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType= USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
-   .bTerminalID= IO_IN_IT_ID,
+   /* .bTerminalID = DYNAMIC */
.wTerminalType  = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
.bAssocTerminal = 0,
.wChannelConfig = cpu_to_le16(0x3),
 };
 
-#define USB_IN_OT_ID   4
 static struct uac1_output_terminal_descriptor usb_in_ot_desc = {
.bLength =  UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType =  USB_DT_CS_INTERFACE,
.bDescriptorSubtype =   UAC_OUTPUT_TERMINAL,
-   .bTerminalID =  USB_IN_OT_ID,
+   /* .bTerminalID =   DYNAMIC */
.wTerminalType =cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal =   0,
-   .bSourceID =IO_IN_IT_ID,
+   /* .bSourceID = DYNAMIC */
 };
 
 /* B.4.1  Standard AS Interface Descriptor */
@@ -176,7

[PATCH v2 3/5] usb: gadget: f_uac2: validate input parameters

2021-03-01 Thread Ruslan Bilovol
Currently user can configure UAC2 function with
parameters that violate UAC2 spec or are not supported
by UAC2 gadget implementation.

This can lead to incorrect behavior if such gadget
is connected to the host - like enumeration failure
or other issues depending on host's UAC2 driver
implementation, bringing user to a long hours
of debugging the issue.

Instead of silently accept these parameters, throw
an error if they are not valid.

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac2.c | 39 ++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index c62cccb..f868e38 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -14,6 +14,9 @@
 #include "u_audio.h"
 #include "u_uac2.h"
 
+/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */
+#define UAC2_CHANNEL_MASK 0x07FF
+
 /*
  * The driver implements a simple UAC_2 topology.
  * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
@@ -604,6 +607,36 @@ static void setup_descriptor(struct f_uac2_opts *opts)
hs_audio_desc[i] = NULL;
 }
 
+static int afunc_validate_opts(struct g_audio *agdev, struct device *dev)
+{
+   struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev);
+
+   if (!opts->p_chmask && !opts->c_chmask) {
+   dev_err(dev, "Error: no playback and capture channels\n");
+   return -EINVAL;
+   } else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported playback channels mask\n");
+   return -EINVAL;
+   } else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported capture channels mask\n");
+   return -EINVAL;
+   } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
+   dev_err(dev, "Error: incorrect playback sample size\n");
+   return -EINVAL;
+   } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
+   dev_err(dev, "Error: incorrect capture sample size\n");
+   return -EINVAL;
+   } else if (!opts->p_srate) {
+   dev_err(dev, "Error: incorrect playback sampling rate\n");
+   return -EINVAL;
+   } else if (!opts->c_srate) {
+   dev_err(dev, "Error: incorrect capture sampling rate\n");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int
 afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 {
@@ -612,11 +645,13 @@ static void setup_descriptor(struct f_uac2_opts *opts)
struct usb_composite_dev *cdev = cfg->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct device *dev = >dev;
-   struct f_uac2_opts *uac2_opts;
+   struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev);
struct usb_string *us;
int ret;
 
-   uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
+   ret = afunc_validate_opts(agdev, dev);
+   if (ret)
+   return ret;
 
us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
if (IS_ERR(us))
-- 
1.9.1



[PATCH v2 2/5] usb: gadget: f_uac1: stop playback on function disable

2021-03-01 Thread Ruslan Bilovol
There is missing playback stop/cleanup in case of
gadget's ->disable callback that happens on
events like USB host resetting or gadget disconnection

Fixes: 0591bc236015 ("usb: gadget: add f_uac1 variant based on a new u_audio 
api")

Cc:  # 4.13+
Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac1.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index 00d3469..560382e 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -499,6 +499,7 @@ static void f_audio_disable(struct usb_function *f)
uac1->as_out_alt = 0;
uac1->as_in_alt = 0;
 
+   u_audio_stop_playback(>g_audio);
u_audio_stop_capture(>g_audio);
 }
 
-- 
1.9.1



[PATCH v2 0/5] USB Audio Gadget part 1: misc fixes and improvements

2021-03-01 Thread Ruslan Bilovol
Here are some bug fixes and improvements to
USB Audio Gadget drivers which I made during
my work on a new UAC features like feedback endpoint
implementation and Volume/Mute controls.

That's nice bugfixes/improvements that I expect get
applied faster than coming new features thus sent them
as 'part 1'

The new UAC features will be sent as a separate
patch set (aka 'part 2')

v2: fixed possible NULL-ptr issue with input parameters
validation

Ruslan Bilovol (5):
  usb: gadget: f_uac2: always increase endpoint max_packet_size by one
audio slot
  usb: gadget: f_uac1: stop playback on function disable
  usb: gadget: f_uac2: validate input parameters
  usb: gadget: f_uac1: validate input parameters
  usb: gadget: f_uac1: disable IN/OUT ep if unused

 drivers/usb/gadget/function/f_uac1.c | 273 ++-
 drivers/usb/gadget/function/f_uac2.c |  41 +-
 2 files changed, 245 insertions(+), 69 deletions(-)

-- 
1.9.1



[PATCH v2 1/5] usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio slot

2021-03-01 Thread Ruslan Bilovol
As per UAC2 Audio Data Formats spec (2.3.1.1 USB Packets),
if the sampling rate is a constant, the allowable variation
of number of audio slots per virtual frame is +/- 1 audio slot.

It means that endpoint should be able to accept/send +1 audio
slot.

Previous endpoint max_packet_size calculation code
was adding sometimes +1 audio slot due to DIV_ROUND_UP
behaviour which was rounding up to closest integer.
However this doesn't work if the numbers are divisible.

It had no any impact with Linux hosts which ignore
this issue, but in case of more strict Windows it
caused rejected enumeration

Thus always add +1 audio slot to endpoint's max packet size

Fixes: 913e4a90b6f9 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to 
bandwidth")
Cc: Peter Chen 
Cc:  #v4.3+
Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index 740cb64..c62cccb 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -478,7 +478,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts 
*uac2_opts,
}
 
max_size_bw = num_channels(chmask) * ssize *
-   DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
+   ((srate / (factor / (1 << (ep_desc->bInterval - 1 + 1);
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
max_size_ep));
 
-- 
1.9.1



[PATCH 5/5] usb: gadget: f_uac1: disable IN/OUT ep if unused

2021-02-16 Thread Ruslan Bilovol
User can configure f_uac1 function via p_chmask/c_chmask
whether uac1 shall support playback and/or capture,
but it has only effect on the created ALSA device,
but not on the USB descriptor.

This patch adds playback/capture descriptors
dependent on that parameter. It is similar to
the same conversion done earlier for f_uac2

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac1.c | 229 +--
 1 file changed, 163 insertions(+), 66 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index cce9478f..b535407 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -22,6 +22,9 @@
 /* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */
 #define UAC1_CHANNEL_MASK 0x0FFF
 
+#define EPIN_EN(_opts) ((_opts)->p_chmask != 0)
+#define EPOUT_EN(_opts) ((_opts)->c_chmask != 0)
+
 struct f_uac1 {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
@@ -50,11 +53,6 @@ static inline struct f_uac1_opts 
*g_audio_to_uac1_opts(struct g_audio *audio)
  * USB-OUT -> IT_1 -> OT_2 -> ALSA_Capture
  * ALSA_Playback -> IT_3 -> OT_4 -> USB-IN
  */
-#define F_AUDIO_AC_INTERFACE   0
-#define F_AUDIO_AS_OUT_INTERFACE   1
-#define F_AUDIO_AS_IN_INTERFACE2
-/* Number of streaming interfaces */
-#define F_AUDIO_NUM_INTERFACES 2
 
 /* B.3.1  Standard AC Interface Descriptor */
 static struct usb_interface_descriptor ac_interface_desc = {
@@ -65,73 +63,47 @@ static inline struct f_uac1_opts 
*g_audio_to_uac1_opts(struct g_audio *audio)
.bInterfaceSubClass =   USB_SUBCLASS_AUDIOCONTROL,
 };
 
-/*
- * The number of AudioStreaming and MIDIStreaming interfaces
- * in the Audio Interface Collection
- */
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
-
-#define UAC_DT_AC_HEADER_LENGTH
UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
-/* 2 input terminals and 2 output terminals */
-#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
-   + 2*UAC_DT_INPUT_TERMINAL_SIZE + 2*UAC_DT_OUTPUT_TERMINAL_SIZE)
 /* B.3.2  Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
-   .bLength =  UAC_DT_AC_HEADER_LENGTH,
-   .bDescriptorType =  USB_DT_CS_INTERFACE,
-   .bDescriptorSubtype =   UAC_HEADER,
-   .bcdADC =   cpu_to_le16(0x0100),
-   .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH),
-   .bInCollection =F_AUDIO_NUM_INTERFACES,
-   .baInterfaceNr = {
-   /* Interface number of the AudioStream interfaces */
-   [0] =   1,
-   [1] =   2,
-   }
-};
+static struct uac1_ac_header_descriptor *ac_header_desc;
 
-#define USB_OUT_IT_ID  1
 static struct uac_input_terminal_descriptor usb_out_it_desc = {
.bLength =  UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType =  USB_DT_CS_INTERFACE,
.bDescriptorSubtype =   UAC_INPUT_TERMINAL,
-   .bTerminalID =  USB_OUT_IT_ID,
+   /* .bTerminalID =   DYNAMIC */
.wTerminalType =cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal =   0,
.wChannelConfig =   cpu_to_le16(0x3),
 };
 
-#define IO_OUT_OT_ID   2
 static struct uac1_output_terminal_descriptor io_out_ot_desc = {
.bLength= UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType= USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
-   .bTerminalID= IO_OUT_OT_ID,
+   /* .bTerminalID =   DYNAMIC */
.wTerminalType  = cpu_to_le16(UAC_OUTPUT_TERMINAL_SPEAKER),
.bAssocTerminal = 0,
-   .bSourceID  = USB_OUT_IT_ID,
+   /* .bSourceID = DYNAMIC */
 };
 
-#define IO_IN_IT_ID3
 static struct uac_input_terminal_descriptor io_in_it_desc = {
.bLength= UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType= USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
-   .bTerminalID= IO_IN_IT_ID,
+   /* .bTerminalID = DYNAMIC */
.wTerminalType  = cpu_to_le16(UAC_INPUT_TERMINAL_MICROPHONE),
.bAssocTerminal = 0,
.wChannelConfig = cpu_to_le16(0x3),
 };
 
-#define USB_IN_OT_ID   4
 static struct uac1_output_terminal_descriptor usb_in_ot_desc = {
.bLength =  UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType =  USB_DT_CS_INTERFACE,
.bDescriptorSubtype =   UAC_OUTPUT_TERMINAL,
-   .bTerminalID =  USB_IN_OT_ID,
+   /* .bTerminalID =   DYNAMIC */
.wTerminalType =cpu_to_le16(UAC_TERMINAL_STREAMING),
.bAssocTerminal =   0,
-   .bSourceID =IO_IN_IT_ID,
+   /* .bSourceID = DYNAMIC */
 };
 
 /* B.4.1  Standard AS Interface Descriptor */
@@

[PATCH 1/5] usb: gadget: f_uac2: always increase endpoint max_packet_size by one audio slot

2021-02-16 Thread Ruslan Bilovol
As per UAC2 Audio Data Formats spec (2.3.1.1 USB Packets),
if the sampling rate is a constant, the allowable variation
of number of audio slots per virtual frame is +/- 1 audio slot.

It means that endpoint should be able to accept/send +1 audio
slot.

Previous endpoint max_packet_size calculation code
was adding sometimes +1 audio slot due to DIV_ROUND_UP
behaviour which was rounding up to closest integer.
However this doesn't work if the numbers are divisible.

It had no any impact with Linux hosts which ignore
this issue, but in case of more strict Windows it
caused rejected enumeration

Thus always add +1 audio slot to endpoint's max packet size

Fixes: 913e4a90b6f9 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to 
bandwidth")
Cc: Peter Chen 
Cc:  #v4.3+
Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index 740cb64..c62cccb 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -478,7 +478,7 @@ static int set_ep_max_packet_size(const struct f_uac2_opts 
*uac2_opts,
}
 
max_size_bw = num_channels(chmask) * ssize *
-   DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
+   ((srate / (factor / (1 << (ep_desc->bInterval - 1 + 1);
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
max_size_ep));
 
-- 
1.9.1



[PATCH 0/5] USB Audio Gadget part 1: misc fixes and improvements

2021-02-16 Thread Ruslan Bilovol
Here are some bug fixes and improvements to
USB Audio Gadget drivers which I made during
my work on a new UAC features like feedback endpoint
implementation and Volume/Mute controls.

The new UAC features will be sent as a separate
patch set (aka 'part 2') on top of these changes
later this week

Ruslan Bilovol (5):
  usb: gadget: f_uac2: always increase endpoint max_packet_size by one
audio slot
  usb: gadget: f_uac1: stop playback on function disable
  usb: gadget: f_uac2: validate input parameters
  usb: gadget: f_uac1: validate input parameters
  usb: gadget: f_uac1: disable IN/OUT ep if unused

 drivers/usb/gadget/function/f_uac1.c | 273 ++-
 drivers/usb/gadget/function/f_uac2.c |  42 +-
 2 files changed, 246 insertions(+), 69 deletions(-)

-- 
1.9.1



[PATCH 4/5] usb: gadget: f_uac1: validate input parameters

2021-02-16 Thread Ruslan Bilovol
Currently user can configure UAC1 function with
parameters that violate UAC1 spec or are not supported
by UAC1 gadget implementation.

This can lead to incorrect behavior if such gadget
is connected to the host - like enumeration failure
or other issues depending on host's UAC1 driver
implementation, bringing user to a long hours
of debugging the issue.

Instead of silently accept these parameters, throw
an error if they are not valid.

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac1.c | 43 
 1 file changed, 43 insertions(+)

diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index 560382e..cce9478f 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -19,6 +19,9 @@
 #include "u_audio.h"
 #include "u_uac1.h"
 
+/* UAC1 spec: 3.7.2.3 Audio Channel Cluster Format */
+#define UAC1_CHANNEL_MASK 0x0FFF
+
 struct f_uac1 {
struct g_audio g_audio;
u8 ac_intf, as_in_intf, as_out_intf;
@@ -30,6 +33,11 @@ static inline struct f_uac1 *func_to_uac1(struct 
usb_function *f)
return container_of(f, struct f_uac1, g_audio.func);
 }
 
+static inline struct f_uac1_opts *g_audio_to_uac1_opts(struct g_audio *audio)
+{
+   return container_of(audio->func.fi, struct f_uac1_opts, func_inst);
+}
+
 /*
  * DESCRIPTORS ... most are static, but strings and full
  * configuration descriptors are built on demand.
@@ -505,6 +513,37 @@ static void f_audio_disable(struct usb_function *f)
 
 /*-*/
 
+static int f_audio_validate_opts(struct g_audio *audio)
+{
+   struct f_uac1_opts *opts = g_audio_to_uac1_opts(audio);
+   struct device *dev = >gadget->dev;
+
+   if (!opts->p_chmask && !opts->c_chmask) {
+   dev_err(dev, "Error: no playback and capture channels\n");
+   return -EINVAL;
+   } else if (opts->p_chmask & ~UAC1_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported playback channels mask\n");
+   return -EINVAL;
+   } else if (opts->c_chmask & ~UAC1_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported capture channels mask\n");
+   return -EINVAL;
+   } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
+   dev_err(dev, "Error: incorrect playback sample size\n");
+   return -EINVAL;
+   } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
+   dev_err(dev, "Error: incorrect capture sample size\n");
+   return -EINVAL;
+   } else if (!opts->p_srate) {
+   dev_err(dev, "Error: incorrect playback sampling rate\n");
+   return -EINVAL;
+   } else if (!opts->c_srate) {
+   dev_err(dev, "Error: incorrect capture sampling rate\n");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 /* audio function driver setup/binding */
 static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 {
@@ -519,6 +558,10 @@ static int f_audio_bind(struct usb_configuration *c, 
struct usb_function *f)
int rate;
int status;
 
+   status = f_audio_validate_opts(audio);
+   if (status)
+   return status;
+
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
 
us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1));
-- 
1.9.1



[PATCH 3/5] usb: gadget: f_uac2: validate input parameters

2021-02-16 Thread Ruslan Bilovol
Currently user can configure UAC2 function with
parameters that violate UAC2 spec or are not supported
by UAC2 gadget implementation.

This can lead to incorrect behavior if such gadget
is connected to the host - like enumeration failure
or other issues depending on host's UAC2 driver
implementation, bringing user to a long hours
of debugging the issue.

Instead of silently accept these parameters, throw
an error if they are not valid.

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac2.c | 40 ++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uac2.c 
b/drivers/usb/gadget/function/f_uac2.c
index c62cccb..d0e50fc 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -14,6 +14,9 @@
 #include "u_audio.h"
 #include "u_uac2.h"
 
+/* UAC2 spec: 4.1 Audio Channel Cluster Descriptor */
+#define UAC2_CHANNEL_MASK 0x07FF
+
 /*
  * The driver implements a simple UAC_2 topology.
  * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
@@ -604,6 +607,37 @@ static void setup_descriptor(struct f_uac2_opts *opts)
hs_audio_desc[i] = NULL;
 }
 
+static int afunc_validate_opts(struct g_audio *agdev)
+{
+   struct f_uac2_opts *opts = g_audio_to_uac2_opts(agdev);
+   struct device *dev = >gadget->dev;
+
+   if (!opts->p_chmask && !opts->c_chmask) {
+   dev_err(dev, "Error: no playback and capture channels\n");
+   return -EINVAL;
+   } else if (opts->p_chmask & ~UAC2_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported playback channels mask\n");
+   return -EINVAL;
+   } else if (opts->c_chmask & ~UAC2_CHANNEL_MASK) {
+   dev_err(dev, "Error: unsupported capture channels mask\n");
+   return -EINVAL;
+   } else if ((opts->p_ssize < 1) || (opts->p_ssize > 4)) {
+   dev_err(dev, "Error: incorrect playback sample size\n");
+   return -EINVAL;
+   } else if ((opts->c_ssize < 1) || (opts->c_ssize > 4)) {
+   dev_err(dev, "Error: incorrect capture sample size\n");
+   return -EINVAL;
+   } else if (!opts->p_srate) {
+   dev_err(dev, "Error: incorrect playback sampling rate\n");
+   return -EINVAL;
+   } else if (!opts->c_srate) {
+   dev_err(dev, "Error: incorrect capture sampling rate\n");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int
 afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 {
@@ -612,11 +646,13 @@ static void setup_descriptor(struct f_uac2_opts *opts)
struct usb_composite_dev *cdev = cfg->cdev;
struct usb_gadget *gadget = cdev->gadget;
struct device *dev = >dev;
-   struct f_uac2_opts *uac2_opts;
+   struct f_uac2_opts *uac2_opts = g_audio_to_uac2_opts(agdev);
struct usb_string *us;
int ret;
 
-   uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
+   ret = afunc_validate_opts(agdev);
+   if (ret)
+   return ret;
 
us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
if (IS_ERR(us))
-- 
1.9.1



[PATCH 2/5] usb: gadget: f_uac1: stop playback on function disable

2021-02-16 Thread Ruslan Bilovol
There is missing playback stop/cleanup in case of
gadget's ->disable callback that happens on
events like USB host resetting or gadget disconnection

Fixes: 0591bc236015 ("usb: gadget: add f_uac1 variant based on a new u_audio 
api")

Cc:  # 4.13+
Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/function/f_uac1.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/gadget/function/f_uac1.c 
b/drivers/usb/gadget/function/f_uac1.c
index 00d3469..560382e 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -499,6 +499,7 @@ static void f_audio_disable(struct usb_function *f)
uac1->as_out_alt = 0;
uac1->as_in_alt = 0;
 
+   u_audio_stop_playback(>g_audio);
u_audio_stop_capture(>g_audio);
 }
 
-- 
1.9.1



RPi4 DWC2 gadget doesn't copy data to a buffer in ep0 SETUP + DATA OUT transaction

2021-01-31 Thread Ruslan Bilovol
Hi Minas and other USB experts,

I'm currently developing new features for UAC1/UAC2 audio gadgets
like Volume/Mute controls which use Control SETUP + DATA OUT
transactions through ep0.

While it works fine on BeagleBone black board with MUSB UDC,
on Raspberry Pi 4 with DWC2 UDC there is an issue.

I found that when DWC2 receives ep0 SETUP + DATA OUT transaction,
it doesn't copy data transferred from the host to EP0 in DATA OUT stage
to the usb_request->buf buffer. This buffer contains unchanged data from
previous transactions.

However, when I disable DMA for DWC2 controller (see the patch below)
it starts to work as expected and correctly copies data transferred from
the host in the DATA OUT stage, to the usb_request->buf buffer.

So far I tested it on v5.9 kernel and v5.10.10 stable kernel both have
the same issue.

This issue is easily reproducible with RNDIS gadget which also
uses ep0 SETUP + DATA OUT transactions for transferring
RNDIS control messages.

During enumeration of RNDIS gadget attached to Linux host,
I see next messages for RPi4 DWC2 with DMA enabled:

| ## RPi4 DWC2 DMA
| [   91.029881] rndis_msg_parser: unknown RNDIS message 0x0052033A len 4456526
| [   91.029889] RNDIS command error -524, 24/24

In this case rndis_msg_parser can't parse messages from the host
because they are sent through SETUP + DATA OUT transaction and
DWC2 didn't copy that messages to the buffer, so buffer contains
some garbage from previous transactions which can't be parsed.

In case of BBB black or DWC2 with disabled DMA, it looks like:

| ## BBB black
| [   32.867751] rndis_msg_parser: RNDIS_MSG_INIT

| ## RPi4 DWC2 no DMA
| [  151.080724] rndis_msg_parser: RNDIS_MSG_INIT

I also did a quick googling and found that same issue was
recently reported for Raspberry pi OS:
https://github.com/raspberrypi/Raspberry-Pi-OS-64bit/issues/127

I spent some time on debugging this issue, but without having
DWC2 documentation and experience with DWC2 internals
that's all that I found so far.

Is this a known issue? Anybody debugging it? Any ideas?

Thanks,
Ruslan

-8<
>From ced7a3631d9800d04bcbcd756dac4583459fe48c Mon Sep 17 00:00:00 2001
From: Ruslan Bilovol 
Date: Wed, 20 Jan 2021 00:27:52 +0200
Subject: [PATCH] usb: dwc2: workaround: disable DMA for gadget

On Raspberry PI 4 it was observer that in case of control
transfers with DATA phase from a host, the driver for some
reason doesn't copy transferred data to the buffer, leaving
previous data in it.

With disabled DMA the issue isn't reproducible, thus
temporarily disable it

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/dwc2/params.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 267543c..46c18af 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -357,7 +357,11 @@ static void dwc2_set_default_params(struct
dwc2_hsotg *hsotg)
 {
  struct dwc2_hw_params *hw = >hw_params;
  struct dwc2_core_params *p = >params;
+#if 0
  bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH);
+#else
+ bool dma_capable = 0;
+#endif

  dwc2_set_param_otg_cap(hsotg);
  dwc2_set_param_phy_type(hsotg);
@@ -651,7 +655,11 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
 {
  struct dwc2_hw_params *hw = >hw_params;
  struct dwc2_core_params *p = >params;
+#if 0
  bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH);
+#else
+ bool dma_capable = 0;
+#endif

  dwc2_check_param_otg_cap(hsotg);
  dwc2_check_param_phy_type(hsotg);
-- 
1.9.1


Re: [PATCH v2] usb: gadget: epautoconf: claim smallest endpoints first

2020-07-03 Thread Ruslan Bilovol
On Tue, Jun 30, 2020 at 4:58 AM Peter Chen  wrote:
>
> On 20-06-29 23:18:45, Ruslan Bilovol wrote:
> > UDC hardware may have endpoints with different maxpacket
> > size. Current endpoint matching code takes first matching
> > endpoint from the list.
> >
> > It's always possible that gadget allocates endpoints for
> > small transfers (maxpacket size) first, then larger ones.
> > That works fine if all matching UDC endpoints have same
> > maxpacket size or are big enough to serve that allocation.
> >
> > However, some UDCs have first endpoints in the list with
> > bigger maxpacket size, whereas last endpoints are much
> > smaller. In this case endpoint allocation will fail for
> > the gadget (which allocates smaller endpoints first) on
> > final endpoint allocations.
> >
> > To make endpoint allocation fair, pick up smallest
> > matching endpoints first, leaving bigger ones for
> > heavier applications.
> >
> > Signed-off-by: Ruslan Bilovol 
> > ---
> >
> > v2: rebased onto latest balbi/next branch
> >
> >  drivers/usb/gadget/epautoconf.c | 23 ++-
> >  1 file changed, 18 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/usb/gadget/epautoconf.c 
> > b/drivers/usb/gadget/epautoconf.c
> > index 1eb4fa2e623f..6c453b5d87bb 100644
> > --- a/drivers/usb/gadget/epautoconf.c
> > +++ b/drivers/usb/gadget/epautoconf.c
> > @@ -66,7 +66,7 @@ struct usb_ep *usb_ep_autoconfig_ss(
> >   struct usb_ss_ep_comp_descriptor *ep_comp
> >  )
> >  {
> > - struct usb_ep   *ep;
> > + struct usb_ep   *ep, *ep_min = NULL;
> >
> >   if (gadget->ops->match_ep) {
> >   ep = gadget->ops->match_ep(gadget, desc, ep_comp);
> > @@ -74,14 +74,27 @@ struct usb_ep *usb_ep_autoconfig_ss(
> >   goto found_ep;
> >   }
> >
> > - /* Second, look at endpoints until an unclaimed one looks usable */
> > + /*
> > +  * Second, look at endpoints until an unclaimed one looks usable.
> > +  * Try to find one with smallest maxpacket limit, leaving larger
> > +  * endpoints for heavier applications
> > +  */
> >   list_for_each_entry (ep, >ep_list, ep_list) {
> > - if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
> > - goto found_ep;
> > + if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) {
> > + if (desc->wMaxPacketSize == 0)
> > + goto found_ep;
>
> Why you do special handling for this? You still could give the smallest
> maxpacket_limit EP for it, right?

Of course it's technically possible. However in case "wMaxPacketSize == 0"
gadget driver wants to get maximum possible wMaxPacketSize from endpoint
configuration and I was thinking about avoiding regressions if we always provide
smaller endpoints.

As I can see, providing smallest endpoint that matches requested wMaxPacketSize
is OK, but if gadget driver just wants autoconf core to use it with
maximum possible
value, I'm thinking now if we can even change this part and if wMaxPacketSize
is zero, find endpoint with maximum possible wMaxPacketSize

Does it make sense?

Thanks
Ruslan

>
> Peter
>
> > + else if (!ep_min)
> > + ep_min = ep;
> > + else if (ep->maxpacket_limit < 
> > ep_min->maxpacket_limit)
> > + ep_min = ep;
> > + }
> >   }
> >
> >   /* Fail */
> > - return NULL;
> > + if (!ep_min)
> > + return NULL;
> > +
> > + ep = ep_min;
> >  found_ep:
> >
> >   /*
> > --
> > 2.17.1
> >
>
> --
>
> Thanks,
> Peter Chen


[PATCH v2] usb: gadget: epautoconf: claim smallest endpoints first

2020-06-29 Thread Ruslan Bilovol
UDC hardware may have endpoints with different maxpacket
size. Current endpoint matching code takes first matching
endpoint from the list.

It's always possible that gadget allocates endpoints for
small transfers (maxpacket size) first, then larger ones.
That works fine if all matching UDC endpoints have same
maxpacket size or are big enough to serve that allocation.

However, some UDCs have first endpoints in the list with
bigger maxpacket size, whereas last endpoints are much
smaller. In this case endpoint allocation will fail for
the gadget (which allocates smaller endpoints first) on
final endpoint allocations.

To make endpoint allocation fair, pick up smallest
matching endpoints first, leaving bigger ones for
heavier applications.

Signed-off-by: Ruslan Bilovol 
---

v2: rebased onto latest balbi/next branch

 drivers/usb/gadget/epautoconf.c | 23 ++-
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 1eb4fa2e623f..6c453b5d87bb 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -66,7 +66,7 @@ struct usb_ep *usb_ep_autoconfig_ss(
struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
-   struct usb_ep   *ep;
+   struct usb_ep   *ep, *ep_min = NULL;
 
if (gadget->ops->match_ep) {
ep = gadget->ops->match_ep(gadget, desc, ep_comp);
@@ -74,14 +74,27 @@ struct usb_ep *usb_ep_autoconfig_ss(
goto found_ep;
}
 
-   /* Second, look at endpoints until an unclaimed one looks usable */
+   /*
+* Second, look at endpoints until an unclaimed one looks usable.
+* Try to find one with smallest maxpacket limit, leaving larger
+* endpoints for heavier applications
+*/
list_for_each_entry (ep, >ep_list, ep_list) {
-   if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
-   goto found_ep;
+   if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) {
+   if (desc->wMaxPacketSize == 0)
+   goto found_ep;
+   else if (!ep_min)
+   ep_min = ep;
+   else if (ep->maxpacket_limit < ep_min->maxpacket_limit)
+   ep_min = ep;
+   }
}
 
/* Fail */
-   return NULL;
+   if (!ep_min)
+   return NULL;
+
+   ep = ep_min;
 found_ep:
 
/*
-- 
2.17.1



[PATCH] usb: gadget: epautoconf: claim smallest endpoints first

2020-06-29 Thread Ruslan Bilovol
UDC hardware may have endpoints with different maxpacket
size. Current endpoint matching code takes first matching
endpoint from the list.

It's always possible that gadget allocates endpoints for
small transfers (maxpacket size) first, then larger ones.
That works fine if all matching UDC endpoints have same
maxpacket size or are big enough to serve that allocation.

However, some UDCs have first endpoints in the list with
bigger maxpacket size, whereas last endpoints are much
smaller. In this case endpoint allocation will fail for
the gadget (which allocates smaller endpoints first) on
final endpoint allocations.

To make endpoint allocation fair, pick up smallest
matching endpoints first, leaving bigger ones for
heavier applications.

Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/gadget/epautoconf.c | 23 ++-
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 71b15c65b90f..1814a760ce48 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -66,7 +66,7 @@ struct usb_ep *usb_ep_autoconfig_ss(
struct usb_ss_ep_comp_descriptor *ep_comp
 )
 {
-   struct usb_ep   *ep;
+   struct usb_ep   *ep, *ep_min = NULL;
u8  type;
 
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
@@ -77,14 +77,27 @@ struct usb_ep *usb_ep_autoconfig_ss(
goto found_ep;
}
 
-   /* Second, look at endpoints until an unclaimed one looks usable */
+   /*
+* Second, look at endpoints until an unclaimed one looks usable.
+* Try to find one with smallest maxpacket limit, leaving larger
+* endpoints for heavier applications
+*/
list_for_each_entry (ep, >ep_list, ep_list) {
-   if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
-   goto found_ep;
+   if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) {
+   if (desc->wMaxPacketSize == 0)
+   goto found_ep;
+   else if (!ep_min)
+   ep_min = ep;
+   else if (ep->maxpacket_limit < ep_min->maxpacket_limit)
+   ep_min = ep;
+   }
}
 
/* Fail */
-   return NULL;
+   if (!ep_min)
+   return NULL;
+
+   ep = ep_min;
 found_ep:
 
/*
-- 
2.17.1



Re: [PATCH v8 0/5] arm64: ftrace with regs

2019-07-10 Thread Ruslan Bilovol
On Tue, Apr 9, 2019 at 8:52 PM Will Deacon  wrote:
>
> On Mon, Apr 08, 2019 at 04:36:28PM +0100, Mark Rutland wrote:
> > On Mon, Mar 11, 2019 at 12:49:46PM +0100, Torsten Duwe wrote:
> > > On Wed, Feb 13, 2019 at 11:11:04AM +, Julien Thierry wrote:
> > > > Hi Torsten,
> > > >
> > > > On 08/02/2019 15:08, Torsten Duwe wrote:
> > > > > Patch series v8, as discussed.
> > > > > The whole series applies cleanly on 5.0-rc5
> > >
> > > So what's the status now? Besides debatable minor style
> > > issues there were no more objections to v8. Would this
> > > go through the ARM repo or via the ftrace repo?
> >
> > Sorry agains for the delay on this. I'm now back in the office and in
> > front of a computer daily, so I can spend a bit more time on this.
> >
> > Regardless of anything else, I think that we should queue the first
> > three patches now. I've poked the relevant maintainers for their acks so
> > that those can be taken via the arm64 tree.
> >
> > I'm happy to do the trivial cleanups on the last couple of patches (e.g.
> > s/lr/x30), and I'm actively looking at the API rework I requested.
>
> Ok, I've picked up patches 1-3 and I'll wait for you to spin updates to the
> last two.

Ok, I see that patches 1-3 are picked up and are already present in recent
kernels.

Is there any progress on remaining two patches?
Any help required?

Thanks,
Ruslan


[PATCH] usb: host: xhci-hub: fix extra endianness conversion

2019-07-07 Thread Ruslan Bilovol
Don't do extra cpu_to_le32 conversion for
put_unaligned_le32 because it is already implemented
in this function.

Fixes sparse error:
xhci-hub.c:1152:44: warning: incorrect type in argument 1 (different base types)
xhci-hub.c:1152:44:expected unsigned int [usertype] val
xhci-hub.c:1152:44:got restricted __le32 [usertype]

Fixes: 395f540 "xhci: support new USB 3.1 hub request to get extended port 
status"
Cc: Mathias Nyman 
Signed-off-by: Ruslan Bilovol 
---
 drivers/usb/host/xhci-hub.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 3abe70f..b7d23c4 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1149,7 +1149,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, 
u16 wValue,
}
port_li = readl(ports[wIndex]->addr + PORTLI);
status = xhci_get_ext_port_status(temp, port_li);
-   put_unaligned_le32(cpu_to_le32(status), [4]);
+   put_unaligned_le32(status, [4]);
}
break;
case SetPortFeature:
-- 
1.9.1



Re: [PATCH v2 0/4] ALSA: usb-audio: Insertion Control for BADD Adaptors.

2018-06-14 Thread Ruslan Bilovol
On Thu, Jun 14, 2018 at 7:07 PM, Takashi Iwai  wrote:
> On Thu, 14 Jun 2018 16:05:54 +0200,
> Jorge Sanjuan wrote:
>>
>> Thanks for review!
>>
>> Here is what's new in this V2:
>>  - Split the patchset into a more sensible series.
>>
>> This patchset adds support for the Insertion Control for BADD devices
>> (subset of UAC3).
>>
>> This control is only pressent in the HEADSET ADAPTER BADD profile. The USB
>> interrupt pipe shall be present for this profile so the status pipe
>> creation should also happen for BADD devices.
>>
>> Also, the bi-directional type codes have been defined so they can be used
>> as inferred values for the Input and Output terminals for this adapter
>> profile.
>>
>> Based on tag: next-20180612
>>
>> Jorge Sanjuan (4):
>>   ALSA: usb-audio: Add bi-directional terminal types.
>>   ALSA: usb-audio: Change in connectors control creation interface
>>   ALSA: usb-audio: UAC3. Add insertion control for BADD.
>>   ALSA: usb-audio: Always create the interrupt pipe for the mixer
>
> Thanks, this looks nicer, each of changes is smaller and clearer.
> Although it's a bit too late for the merge window, this is a change
> that is fairly safe for the existing UAC1/UAC2, I merged it now.
>

It's too late probably, but I just finished reviewing these patches
and don't have any objections.

Thanks,
Ruslan


Re: [PATCH v2 0/4] ALSA: usb-audio: Insertion Control for BADD Adaptors.

2018-06-14 Thread Ruslan Bilovol
On Thu, Jun 14, 2018 at 7:07 PM, Takashi Iwai  wrote:
> On Thu, 14 Jun 2018 16:05:54 +0200,
> Jorge Sanjuan wrote:
>>
>> Thanks for review!
>>
>> Here is what's new in this V2:
>>  - Split the patchset into a more sensible series.
>>
>> This patchset adds support for the Insertion Control for BADD devices
>> (subset of UAC3).
>>
>> This control is only pressent in the HEADSET ADAPTER BADD profile. The USB
>> interrupt pipe shall be present for this profile so the status pipe
>> creation should also happen for BADD devices.
>>
>> Also, the bi-directional type codes have been defined so they can be used
>> as inferred values for the Input and Output terminals for this adapter
>> profile.
>>
>> Based on tag: next-20180612
>>
>> Jorge Sanjuan (4):
>>   ALSA: usb-audio: Add bi-directional terminal types.
>>   ALSA: usb-audio: Change in connectors control creation interface
>>   ALSA: usb-audio: UAC3. Add insertion control for BADD.
>>   ALSA: usb-audio: Always create the interrupt pipe for the mixer
>
> Thanks, this looks nicer, each of changes is smaller and clearer.
> Although it's a bit too late for the merge window, this is a change
> that is fairly safe for the existing UAC1/UAC2, I merged it now.
>

It's too late probably, but I just finished reviewing these patches
and don't have any objections.

Thanks,
Ruslan


[PATCH] ALSA: usb: stream: fix potential memory leak during uac3 interface parsing

2018-05-17 Thread Ruslan Bilovol
UAC3 channel map is created during interface parsing,
and in some cases was not freed in failure paths.

Reported-by: Dan Carpenter <dan.carpen...@oracle.com>
Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/stream.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index bce3152..d16e1c2 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -982,13 +982,16 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
 
dev_err(>dev, "%u:%d : bogus bTerminalLink %d\n",
iface_no, altno, as->bTerminalLink);
+   kfree(chmap);
return NULL;
 
 found_clock:
fp = audio_format_alloc_init(chip, alts, UAC_VERSION_3, iface_no,
 altset_idx, altno, num_channels, clock);
-   if (!fp)
+   if (!fp) {
+   kfree(chmap);
return ERR_PTR(-ENOMEM);
+   }
 
fp->chmap = chmap;
 
@@ -1009,6 +1012,7 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
   iface_no);
/* ok, let's parse further... */
if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
+   kfree(fp->chmap);
kfree(fp->rate_table);
kfree(fp);
return NULL;
-- 
1.9.1



[PATCH] ALSA: usb: stream: fix potential memory leak during uac3 interface parsing

2018-05-17 Thread Ruslan Bilovol
UAC3 channel map is created during interface parsing,
and in some cases was not freed in failure paths.

Reported-by: Dan Carpenter 
Signed-off-by: Ruslan Bilovol 
---
 sound/usb/stream.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index bce3152..d16e1c2 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -982,13 +982,16 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
 
dev_err(>dev, "%u:%d : bogus bTerminalLink %d\n",
iface_no, altno, as->bTerminalLink);
+   kfree(chmap);
return NULL;
 
 found_clock:
fp = audio_format_alloc_init(chip, alts, UAC_VERSION_3, iface_no,
 altset_idx, altno, num_channels, clock);
-   if (!fp)
+   if (!fp) {
+   kfree(chmap);
return ERR_PTR(-ENOMEM);
+   }
 
fp->chmap = chmap;
 
@@ -1009,6 +1012,7 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
   iface_no);
/* ok, let's parse further... */
if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
+   kfree(fp->chmap);
kfree(fp->rate_table);
kfree(fp);
return NULL;
-- 
1.9.1



Re: [RESEND PATCH v4 4/4] ALSA: usb-audio: UAC3: Parse Input Terminal number of channels.

2018-05-14 Thread Ruslan Bilovol
On Mon, May 14, 2018 at 2:03 PM, Jorge Sanjuan
<jorge.sanj...@codethink.co.uk> wrote:
> Obtain the number of channels for the Input Terminal from the
> Logical Cluster Descriptor. This achieves a useful minimal parsing
> of this unit so it can be used in other units in the topology.

Usually 'patch resend' means resend without any changes, and if there
are updates in the patch - it's a new version.

By the way, as I already said in comments to patch 1/4 [1], I verified
this patch successfully.

Reviewed-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
Tested-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>

[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-May/136044.html

>
> Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>
> ---
>  sound/usb/mixer.c | 8 ++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 431f3c319839..99804cd4aed6 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -904,8 +904,12 @@ static int check_input_term(struct mixer_build *state, 
> int id,
> term->id = id;
> term->type = le16_to_cpu(d->wTerminalType);
>
> -   /* REVISIT: UAC3 IT doesn't have channels/cfg 
> */
> -   term->channels = 0;
> +   err = get_cluster_channels_v3(state, 
> le16_to_cpu(d->wClusterDescrID));
> +   if (err < 0)
> +   return err;
> +   term->channels = err;
> +
> +   /* REVISIT: UAC3 IT doesn't have channels cfg 
> */
> term->chconfig = 0;
>
> term->name = 
> le16_to_cpu(d->wTerminalDescrStr);
> --
> 2.11.0
>


Re: [RESEND PATCH v4 4/4] ALSA: usb-audio: UAC3: Parse Input Terminal number of channels.

2018-05-14 Thread Ruslan Bilovol
On Mon, May 14, 2018 at 2:03 PM, Jorge Sanjuan
 wrote:
> Obtain the number of channels for the Input Terminal from the
> Logical Cluster Descriptor. This achieves a useful minimal parsing
> of this unit so it can be used in other units in the topology.

Usually 'patch resend' means resend without any changes, and if there
are updates in the patch - it's a new version.

By the way, as I already said in comments to patch 1/4 [1], I verified
this patch successfully.

Reviewed-by: Ruslan Bilovol 
Tested-by: Ruslan Bilovol 

[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-May/136044.html

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  sound/usb/mixer.c | 8 ++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 431f3c319839..99804cd4aed6 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -904,8 +904,12 @@ static int check_input_term(struct mixer_build *state, 
> int id,
> term->id = id;
> term->type = le16_to_cpu(d->wTerminalType);
>
> -   /* REVISIT: UAC3 IT doesn't have channels/cfg 
> */
> -   term->channels = 0;
> +   err = get_cluster_channels_v3(state, 
> le16_to_cpu(d->wClusterDescrID));
> +   if (err < 0)
> +   return err;
> +   term->channels = err;
> +
> +   /* REVISIT: UAC3 IT doesn't have channels cfg 
> */
> term->chconfig = 0;
>
> term->name = 
> le16_to_cpu(d->wTerminalDescrStr);
> --
> 2.11.0
>


Re: [PATCH v4 2/4] ALSA: usb-audio: Use Class Specific EP for UAC3 devices.

2018-05-14 Thread Ruslan Bilovol
On Fri, May 11, 2018 at 6:25 PM, Jorge Sanjuan
<jorge.sanj...@codethink.co.uk> wrote:
> bmAtributes offset doesn't exist in the UAC3 CS_EP descriptor.
> Hence, checking for pitch control as if it was UAC2 doesn't make
> any sense. Use the defined UAC3 offsets instead.

This one I already reviewed in v2 and there is no changes in v4,
so still:
Reviewed-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>

By the way, this patch is an independent change and can go
into v4.17-rcXX, if it's not too late for it.

Thanks,
Ruslan

>
> Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>
> ---
>  sound/usb/stream.c | 9 -
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/sound/usb/stream.c b/sound/usb/stream.c
> index 764be07474a8..6b2924533d8d 100644
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -576,7 +576,7 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
>
> if (protocol == UAC_VERSION_1) {
> attributes = csep->bmAttributes;
> -   } else {
> +   } else if (protocol == UAC_VERSION_2) {
> struct uac2_iso_endpoint_descriptor *csep2 =
> (struct uac2_iso_endpoint_descriptor *) csep;
>
> @@ -585,6 +585,13 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
> /* emulate the endpoint attributes of a v1 device */
> if (csep2->bmControls & UAC2_CONTROL_PITCH)
> attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> +   } else { /* UAC_VERSION_3 */
> +   struct uac3_iso_endpoint_descriptor *csep3 =
> +   (struct uac3_iso_endpoint_descriptor *) csep;
> +
> +   /* emulate the endpoint attributes of a v1 device */
> +   if (le32_to_cpu(csep3->bmControls) & UAC2_CONTROL_PITCH)
> +   attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> }
>
> return attributes;
> --
> 2.11.0
>


Re: [PATCH v4 2/4] ALSA: usb-audio: Use Class Specific EP for UAC3 devices.

2018-05-14 Thread Ruslan Bilovol
On Fri, May 11, 2018 at 6:25 PM, Jorge Sanjuan
 wrote:
> bmAtributes offset doesn't exist in the UAC3 CS_EP descriptor.
> Hence, checking for pitch control as if it was UAC2 doesn't make
> any sense. Use the defined UAC3 offsets instead.

This one I already reviewed in v2 and there is no changes in v4,
so still:
Reviewed-by: Ruslan Bilovol 

By the way, this patch is an independent change and can go
into v4.17-rcXX, if it's not too late for it.

Thanks,
Ruslan

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  sound/usb/stream.c | 9 -
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/sound/usb/stream.c b/sound/usb/stream.c
> index 764be07474a8..6b2924533d8d 100644
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -576,7 +576,7 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
>
> if (protocol == UAC_VERSION_1) {
> attributes = csep->bmAttributes;
> -   } else {
> +   } else if (protocol == UAC_VERSION_2) {
> struct uac2_iso_endpoint_descriptor *csep2 =
> (struct uac2_iso_endpoint_descriptor *) csep;
>
> @@ -585,6 +585,13 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
> /* emulate the endpoint attributes of a v1 device */
> if (csep2->bmControls & UAC2_CONTROL_PITCH)
> attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> +   } else { /* UAC_VERSION_3 */
> +   struct uac3_iso_endpoint_descriptor *csep3 =
> +   (struct uac3_iso_endpoint_descriptor *) csep;
> +
> +   /* emulate the endpoint attributes of a v1 device */
> +   if (le32_to_cpu(csep3->bmControls) & UAC2_CONTROL_PITCH)
> +   attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> }
>
> return attributes;
> --
> 2.11.0
>


Re: [PATCH v4 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-05-14 Thread Ruslan Bilovol
On Fri, May 11, 2018 at 6:25 PM, Jorge Sanjuan
<jorge.sanj...@codethink.co.uk> wrote:
> This adds support for the MIXER UNIT in UAC3. All the information
> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
> read the rest of the logical cluster to obtain the channel config
> as that wont make any difference in the current mixer behaviour.
>
> The name of the mixer unit is not yet requested as there is not
> support for the UAC3 Class Specific String requests.
>
> Tested in an UAC3 device working as a HEADSET with a basic mixer
> unit (same as the one in the BADD spec) with no controls.

I tested this patch in a similar use-case (with a simple mixer unit),
but _with_ controls and along with patch [1] from this series, which
added parsing input terminal's channels.
So everything works fine, I see all needed requests handling and
mixer unit creation on ALSA side, which I can use now.

So, as a bottom line:
Reviewed-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
Tested-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>

[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-May/136030.html

>
> Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>
> ---
>  include/uapi/linux/usb/audio.h | 19 +++--
>  sound/usb/mixer.c  | 88 
> ++
>  2 files changed, 97 insertions(+), 10 deletions(-)
>
> diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
> index 3a78e7145689..13d98e6e0db1 100644
> --- a/include/uapi/linux/usb/audio.h
> +++ b/include/uapi/linux/usb/audio.h
> @@ -285,9 +285,22 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct 
> uac_mixer_unit_descriptor
>  static inline __u8 *uac_mixer_unit_bmControls(struct 
> uac_mixer_unit_descriptor *desc,
>   int protocol)
>  {
> -   return (protocol == UAC_VERSION_1) ?
> -   >baSourceID[desc->bNrInPins + 4] :
> -   >baSourceID[desc->bNrInPins + 6];
> +   switch (protocol) {
> +   case UAC_VERSION_1:
> +   return >baSourceID[desc->bNrInPins + 4];
> +   case UAC_VERSION_2:
> +   return >baSourceID[desc->bNrInPins + 6];
> +   case UAC_VERSION_3:
> +   return >baSourceID[desc->bNrInPins + 2];
> +   default:
> +   return NULL;
> +   }
> +}
> +
> +static inline __u16 uac3_mixer_unit_wClusterDescrID(struct 
> uac_mixer_unit_descriptor *desc)
> +{
> +   return (desc->baSourceID[desc->bNrInPins + 1] << 8) |
> +   desc->baSourceID[desc->bNrInPins];
>  }
>
>  static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor 
> *desc)
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 76417943ff85..129c1397f0cb 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -719,6 +719,66 @@ static int get_term_name(struct snd_usb_audio *chip, 
> struct usb_audio_term *iter
>  }
>
>  /*
> + * Get logical cluster information for UAC3 devices.
> + */
> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int 
> cluster_id)
> +{
> +   struct uac3_cluster_header_descriptor c_header;
> +   int err;
> +
> +   err = snd_usb_ctl_msg(state->chip->dev,
> +   usb_rcvctrlpipe(state->chip->dev, 0),
> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +   cluster_id,
> +   snd_usb_ctrl_intf(state->chip),
> +   _header, sizeof(c_header));
> +   if (err < 0)
> +   goto error;
> +   if (err != sizeof(c_header)) {
> +   err = -EIO;
> +   goto error;
> +   }
> +
> +   return c_header.bNrChannels;
> +
> +error:
> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d 
> (err: %d)\n", cluster_id, err);
> +   return err;
> +}
> +
> +/*
> + * Get number of channels for a Mixer Unit.
> + */
> +static int uac_mixer_unit_get_channels(struct mixer_build *state,
> +  struct uac_mixer_unit_descriptor *desc)
> +{
> +   int mu_channels;
> +
> +   if (desc->bLength < 11)
> +   return -EINVAL;
> +   if (!desc->bNrInPins)
> +   return -EINVAL;
> +
> +   switch (state->mixer->protocol) {
> +   case UAC_VERSION_1:
> +   case UAC_VERSION_2:
> +   default:
> +   mu_channels = uac_mixer_unit_bNrChannels(desc);
> +

Re: [PATCH v4 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-05-14 Thread Ruslan Bilovol
On Fri, May 11, 2018 at 6:25 PM, Jorge Sanjuan
 wrote:
> This adds support for the MIXER UNIT in UAC3. All the information
> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
> read the rest of the logical cluster to obtain the channel config
> as that wont make any difference in the current mixer behaviour.
>
> The name of the mixer unit is not yet requested as there is not
> support for the UAC3 Class Specific String requests.
>
> Tested in an UAC3 device working as a HEADSET with a basic mixer
> unit (same as the one in the BADD spec) with no controls.

I tested this patch in a similar use-case (with a simple mixer unit),
but _with_ controls and along with patch [1] from this series, which
added parsing input terminal's channels.
So everything works fine, I see all needed requests handling and
mixer unit creation on ALSA side, which I can use now.

So, as a bottom line:
Reviewed-by: Ruslan Bilovol 
Tested-by: Ruslan Bilovol 

[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-May/136030.html

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  include/uapi/linux/usb/audio.h | 19 +++--
>  sound/usb/mixer.c  | 88 
> ++
>  2 files changed, 97 insertions(+), 10 deletions(-)
>
> diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
> index 3a78e7145689..13d98e6e0db1 100644
> --- a/include/uapi/linux/usb/audio.h
> +++ b/include/uapi/linux/usb/audio.h
> @@ -285,9 +285,22 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct 
> uac_mixer_unit_descriptor
>  static inline __u8 *uac_mixer_unit_bmControls(struct 
> uac_mixer_unit_descriptor *desc,
>   int protocol)
>  {
> -   return (protocol == UAC_VERSION_1) ?
> -   >baSourceID[desc->bNrInPins + 4] :
> -   >baSourceID[desc->bNrInPins + 6];
> +   switch (protocol) {
> +   case UAC_VERSION_1:
> +   return >baSourceID[desc->bNrInPins + 4];
> +   case UAC_VERSION_2:
> +   return >baSourceID[desc->bNrInPins + 6];
> +   case UAC_VERSION_3:
> +   return >baSourceID[desc->bNrInPins + 2];
> +   default:
> +   return NULL;
> +   }
> +}
> +
> +static inline __u16 uac3_mixer_unit_wClusterDescrID(struct 
> uac_mixer_unit_descriptor *desc)
> +{
> +   return (desc->baSourceID[desc->bNrInPins + 1] << 8) |
> +   desc->baSourceID[desc->bNrInPins];
>  }
>
>  static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor 
> *desc)
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 76417943ff85..129c1397f0cb 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -719,6 +719,66 @@ static int get_term_name(struct snd_usb_audio *chip, 
> struct usb_audio_term *iter
>  }
>
>  /*
> + * Get logical cluster information for UAC3 devices.
> + */
> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int 
> cluster_id)
> +{
> +   struct uac3_cluster_header_descriptor c_header;
> +   int err;
> +
> +   err = snd_usb_ctl_msg(state->chip->dev,
> +   usb_rcvctrlpipe(state->chip->dev, 0),
> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +   cluster_id,
> +   snd_usb_ctrl_intf(state->chip),
> +   _header, sizeof(c_header));
> +   if (err < 0)
> +   goto error;
> +   if (err != sizeof(c_header)) {
> +   err = -EIO;
> +   goto error;
> +   }
> +
> +   return c_header.bNrChannels;
> +
> +error:
> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d 
> (err: %d)\n", cluster_id, err);
> +   return err;
> +}
> +
> +/*
> + * Get number of channels for a Mixer Unit.
> + */
> +static int uac_mixer_unit_get_channels(struct mixer_build *state,
> +  struct uac_mixer_unit_descriptor *desc)
> +{
> +   int mu_channels;
> +
> +   if (desc->bLength < 11)
> +   return -EINVAL;
> +   if (!desc->bNrInPins)
> +   return -EINVAL;
> +
> +   switch (state->mixer->protocol) {
> +   case UAC_VERSION_1:
> +   case UAC_VERSION_2:
> +   default:
> +   mu_channels = uac_mixer_unit_bNrChannels(desc);
> +   break;
> +   case UAC_VERSION_3:
> +   mu_channels = get_cluster_channels_v3(state,
> + 

Re: [PATCH v4 4/4] ALSA: usb-audio: UAC3: Parse Input Terminal number of channels.

2018-05-14 Thread Ruslan Bilovol
On Mon, May 14, 2018 at 11:54 AM, Jorge  wrote:
>
>
> On 11/05/18 16:25, Jorge Sanjuan wrote:
>>
>> Obtain the number of channels for the Input Terminal from the
>> Logical Cluster Descriptor. This achieves a useful minimal parsing
>> of this unit so it can be used in other units in the topology.
>>
>> Signed-off-by: Jorge Sanjuan 
>> ---
>>   sound/usb/mixer.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
>> index 431f3c319839..19b25fbc7437 100644
>> --- a/sound/usb/mixer.c
>> +++ b/sound/usb/mixer.c
>> @@ -903,9 +903,9 @@ static int check_input_term(struct mixer_build *state,
>> int id,
>>  * recursion calls */
>> term->id = id;
>> term->type =
>> le16_to_cpu(d->wTerminalType);
>> +   term->channels =
>> get_cluster_channels_v3(state, d->wClusterDescrID);
>
>
>
> Sorry about this. I just spotted that I should have used the helper function
> I added to access d->wClusterDescrID `uac3_mixer_unit_wClusterDescrID`.
>
> I got the sparse warning for the endianess and realized that. I'll resend
> this one patch.

While here, please add checking output of get_cluster_channels_v3() as
it can return negative errno.

BTW, I've just tested your Mixer patches and this is the only comment I have
so far.

Thanks,
Ruslan

>
>>   - /* REVISIT: UAC3 IT doesn't have
>> channels/cfg */
>> -   term->channels = 0;
>> +   /* REVISIT: UAC3 IT doesn't have channels
>> cfg */
>> term->chconfig = 0;
>> term->name =
>> le16_to_cpu(d->wTerminalDescrStr);
>>
>


Re: [PATCH v4 4/4] ALSA: usb-audio: UAC3: Parse Input Terminal number of channels.

2018-05-14 Thread Ruslan Bilovol
On Mon, May 14, 2018 at 11:54 AM, Jorge  wrote:
>
>
> On 11/05/18 16:25, Jorge Sanjuan wrote:
>>
>> Obtain the number of channels for the Input Terminal from the
>> Logical Cluster Descriptor. This achieves a useful minimal parsing
>> of this unit so it can be used in other units in the topology.
>>
>> Signed-off-by: Jorge Sanjuan 
>> ---
>>   sound/usb/mixer.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
>> index 431f3c319839..19b25fbc7437 100644
>> --- a/sound/usb/mixer.c
>> +++ b/sound/usb/mixer.c
>> @@ -903,9 +903,9 @@ static int check_input_term(struct mixer_build *state,
>> int id,
>>  * recursion calls */
>> term->id = id;
>> term->type =
>> le16_to_cpu(d->wTerminalType);
>> +   term->channels =
>> get_cluster_channels_v3(state, d->wClusterDescrID);
>
>
>
> Sorry about this. I just spotted that I should have used the helper function
> I added to access d->wClusterDescrID `uac3_mixer_unit_wClusterDescrID`.
>
> I got the sparse warning for the endianess and realized that. I'll resend
> this one patch.

While here, please add checking output of get_cluster_channels_v3() as
it can return negative errno.

BTW, I've just tested your Mixer patches and this is the only comment I have
so far.

Thanks,
Ruslan

>
>>   - /* REVISIT: UAC3 IT doesn't have
>> channels/cfg */
>> -   term->channels = 0;
>> +   /* REVISIT: UAC3 IT doesn't have channels
>> cfg */
>> term->chconfig = 0;
>> term->name =
>> le16_to_cpu(d->wTerminalDescrStr);
>>
>


Re: [PATCH v3 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-05-09 Thread Ruslan Bilovol
On Tue, May 8, 2018 at 12:43 PM, Jorge <jorge.sanj...@codethink.co.uk> wrote:
>
>
> On 04/05/18 01:57, Ruslan Bilovol wrote:
>>
>> On Fri, Apr 27, 2018 at 8:06 PM, Jorge Sanjuan
>> <jorge.sanj...@codethink.co.uk> wrote:
>>>
>>> This adds support for the MIXER UNIT in UAC3. All the information
>>> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
>>> read the rest of the logical cluster to obtain the channel config
>>> as that wont make any difference in the current mixer behaviour.
>>>
>>> The name of the mixer unit is not yet requested as there is not
>>> support for the UAC3 Class Specific String requests.
>>>
>>> Tested in an UAC3 device working as a HEADSET with a basic mixer
>>> unit (same as the one in the BADD spec) with no controls.
>>
>>
>> So, after deeper looking into the code and after testing this patch,
>> in your usecase (mixer with no controls) you'll never execute
>> build_mixer_unit_ctl(), correct? So did you try to just fix issues with
>> incorrect parsing of mixer unit descriptor?
>>
>>>
>>> Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>
>>> ---
>>>   include/uapi/linux/usb/audio.h | 19 +++--
>>>   sound/usb/mixer.c  | 88
>>> ++
>>>   2 files changed, 97 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/include/uapi/linux/usb/audio.h
>>> b/include/uapi/linux/usb/audio.h
>>> index 3a78e7145689..13d98e6e0db1 100644
>>> --- a/include/uapi/linux/usb/audio.h
>>> +++ b/include/uapi/linux/usb/audio.h
>>> @@ -285,9 +285,22 @@ static inline __u8
>>> uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor
>>>   static inline __u8 *uac_mixer_unit_bmControls(struct
>>> uac_mixer_unit_descriptor *desc,
>>>int protocol)
>>>   {
>>> -   return (protocol == UAC_VERSION_1) ?
>>> -   >baSourceID[desc->bNrInPins + 4] :
>>> -   >baSourceID[desc->bNrInPins + 6];
>>> +   switch (protocol) {
>>> +   case UAC_VERSION_1:
>>> +   return >baSourceID[desc->bNrInPins + 4];
>>> +   case UAC_VERSION_2:
>>> +   return >baSourceID[desc->bNrInPins + 6];
>>> +   case UAC_VERSION_3:
>>> +   return >baSourceID[desc->bNrInPins + 2];
>>> +   default:
>>> +   return NULL;
>>> +   }
>>> +}
>>> +
>>> +static inline __u16 uac3_mixer_unit_wClusterDescrID(struct
>>> uac_mixer_unit_descriptor *desc)
>>> +{
>>> +   return (desc->baSourceID[desc->bNrInPins + 1] << 8) |
>>> +   desc->baSourceID[desc->bNrInPins];
>>>   }
>>>
>>>   static inline __u8 uac_mixer_unit_iMixer(struct
>>> uac_mixer_unit_descriptor *desc)
>>> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
>>> index 301ad61ed426..3503f4840ec3 100644
>>> --- a/sound/usb/mixer.c
>>> +++ b/sound/usb/mixer.c
>>> @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state,
>>> struct usb_audio_term *iterm
>>>   }
>>>
>>>   /*
>>> + * Get logical cluster information for UAC3 devices.
>>> + */
>>> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned
>>> int cluster_id)
>>> +{
>>> +   struct uac3_cluster_header_descriptor c_header;
>>> +   int err;
>>> +
>>> +   err = snd_usb_ctl_msg(state->chip->dev,
>>> +   usb_rcvctrlpipe(state->chip->dev, 0),
>>> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
>>> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS |
>>> USB_DIR_IN,
>>> +   cluster_id,
>>> +   snd_usb_ctrl_intf(state->chip),
>>> +   _header, sizeof(c_header));
>>> +   if (err < 0)
>>> +   goto error;
>>> +   if (err != sizeof(c_header)) {
>>> +   err = -EIO;
>>> +   goto error;
>>> +   }
>>> +
>>> +   return c_header.bNrChannels;
>>> +
>>> +error:
>>> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d
>>> (err: %d)\n", cluster_id, err);
&g

Re: [PATCH v3 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-05-09 Thread Ruslan Bilovol
On Tue, May 8, 2018 at 12:43 PM, Jorge  wrote:
>
>
> On 04/05/18 01:57, Ruslan Bilovol wrote:
>>
>> On Fri, Apr 27, 2018 at 8:06 PM, Jorge Sanjuan
>>  wrote:
>>>
>>> This adds support for the MIXER UNIT in UAC3. All the information
>>> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
>>> read the rest of the logical cluster to obtain the channel config
>>> as that wont make any difference in the current mixer behaviour.
>>>
>>> The name of the mixer unit is not yet requested as there is not
>>> support for the UAC3 Class Specific String requests.
>>>
>>> Tested in an UAC3 device working as a HEADSET with a basic mixer
>>> unit (same as the one in the BADD spec) with no controls.
>>
>>
>> So, after deeper looking into the code and after testing this patch,
>> in your usecase (mixer with no controls) you'll never execute
>> build_mixer_unit_ctl(), correct? So did you try to just fix issues with
>> incorrect parsing of mixer unit descriptor?
>>
>>>
>>> Signed-off-by: Jorge Sanjuan 
>>> ---
>>>   include/uapi/linux/usb/audio.h | 19 +++--
>>>   sound/usb/mixer.c  | 88
>>> ++
>>>   2 files changed, 97 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/include/uapi/linux/usb/audio.h
>>> b/include/uapi/linux/usb/audio.h
>>> index 3a78e7145689..13d98e6e0db1 100644
>>> --- a/include/uapi/linux/usb/audio.h
>>> +++ b/include/uapi/linux/usb/audio.h
>>> @@ -285,9 +285,22 @@ static inline __u8
>>> uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor
>>>   static inline __u8 *uac_mixer_unit_bmControls(struct
>>> uac_mixer_unit_descriptor *desc,
>>>int protocol)
>>>   {
>>> -   return (protocol == UAC_VERSION_1) ?
>>> -   >baSourceID[desc->bNrInPins + 4] :
>>> -   >baSourceID[desc->bNrInPins + 6];
>>> +   switch (protocol) {
>>> +   case UAC_VERSION_1:
>>> +   return >baSourceID[desc->bNrInPins + 4];
>>> +   case UAC_VERSION_2:
>>> +   return >baSourceID[desc->bNrInPins + 6];
>>> +   case UAC_VERSION_3:
>>> +   return >baSourceID[desc->bNrInPins + 2];
>>> +   default:
>>> +   return NULL;
>>> +   }
>>> +}
>>> +
>>> +static inline __u16 uac3_mixer_unit_wClusterDescrID(struct
>>> uac_mixer_unit_descriptor *desc)
>>> +{
>>> +   return (desc->baSourceID[desc->bNrInPins + 1] << 8) |
>>> +   desc->baSourceID[desc->bNrInPins];
>>>   }
>>>
>>>   static inline __u8 uac_mixer_unit_iMixer(struct
>>> uac_mixer_unit_descriptor *desc)
>>> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
>>> index 301ad61ed426..3503f4840ec3 100644
>>> --- a/sound/usb/mixer.c
>>> +++ b/sound/usb/mixer.c
>>> @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state,
>>> struct usb_audio_term *iterm
>>>   }
>>>
>>>   /*
>>> + * Get logical cluster information for UAC3 devices.
>>> + */
>>> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned
>>> int cluster_id)
>>> +{
>>> +   struct uac3_cluster_header_descriptor c_header;
>>> +   int err;
>>> +
>>> +   err = snd_usb_ctl_msg(state->chip->dev,
>>> +   usb_rcvctrlpipe(state->chip->dev, 0),
>>> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
>>> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS |
>>> USB_DIR_IN,
>>> +   cluster_id,
>>> +   snd_usb_ctrl_intf(state->chip),
>>> +   _header, sizeof(c_header));
>>> +   if (err < 0)
>>> +   goto error;
>>> +   if (err != sizeof(c_header)) {
>>> +   err = -EIO;
>>> +   goto error;
>>> +   }
>>> +
>>> +   return c_header.bNrChannels;
>>> +
>>> +error:
>>> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d
>>> (err: %d)\n", cluster_id, err);
>>> +   return err;
>>> +}
>>> +
>>> +/*
>>> + * Get n

[PATCH v2 2/7] ALSA: usb: stream: refactor uac1/2 audio interface parsing

2018-05-03 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function
which became quite long after adding UAC3 spec support.

Move class-specific parts of uac1/2 parsing to separate
function which now produce audioformat structure that
is ready to be fed to snd_usb_add_audio_stream().

This also broke Blue Microphones workaround (which
relies on audioformat decoded from previous altsetting)
into two parts: prepare quirk flag analyzing previous
altsetting then use it with current altsetting.

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/stream.c | 333 +
 1 file changed, 185 insertions(+), 148 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 8ec0a52..3369226 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -656,6 +656,156 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return fp;
 }
 
+static struct audioformat *
+snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int protocol, int iface_no, int altset_idx,
+ int altno, int stream, int bm_quirk)
+{
+   struct usb_device *dev = chip->dev;
+   struct uac_format_type_i_continuous_descriptor *fmt;
+   unsigned int num_channels = 0, chconfig = 0;
+   struct audioformat *fp;
+   int clock = 0;
+   u64 format;
+
+   /* get audio formats */
+   if (protocol == UAC_VERSION_1) {
+   struct uac1_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+   struct uac_input_terminal_descriptor *iterm;
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   format = le16_to_cpu(as->wFormatTag); /* remember the format 
value */
+
+   iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+as->bTerminalLink);
+   if (iterm) {
+   num_channels = iterm->bNrChannels;
+   chconfig = le16_to_cpu(iterm->wChannelConfig);
+   }
+   } else { /* UAC_VERSION_2 */
+   struct uac2_input_terminal_descriptor *input_term;
+   struct uac2_output_terminal_descriptor *output_term;
+   struct uac2_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   num_channels = as->bNrChannels;
+   format = le32_to_cpu(as->bmFormats);
+   chconfig = le32_to_cpu(as->bmChannelConfig);
+
+   /*
+* lookup the terminal associated to this interface
+* to extract the clock
+*/
+   input_term = 
snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+   
as->bTerminalLink);
+   if (input_term) {
+   clock = input_term->bCSourceID;
+   if (!chconfig && (num_channels == 
input_term->bNrChannels))
+   chconfig = 
le32_to_cpu(input_term->bmChannelConfig);
+   goto found_clock;
+   }
+
+   output_term = 
snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+ 
as->bTerminalLink);
+   if (output_term) {
+   clock = output_term->bCSourceID;
+   goto found_clock;
+   }
+
+   dev_err(>dev,
+   "%u:%d : bogus bT

[PATCH v2 3/7] ALSA: usb: stream: refactor uac3 audio interface parsing

2018-05-03 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function
which became quite long after adding UAC3 spec support.

Move class-specific parts of uac3 parsing to separate
function which now produce audioformat structure that
is ready to be fed to snd_usb_add_audio_stream().

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/stream.c | 289 +++--
 1 file changed, 146 insertions(+), 143 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 3369226..764be07 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -807,19 +807,154 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return fp;
 }
 
+static struct audioformat *
+snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+struct usb_host_interface *alts,
+int iface_no, int altset_idx,
+int altno, int stream)
+{
+   struct usb_device *dev = chip->dev;
+   struct uac3_input_terminal_descriptor *input_term;
+   struct uac3_output_terminal_descriptor *output_term;
+   struct uac3_cluster_header_descriptor *cluster;
+   struct uac3_as_header_descriptor *as;
+   struct uac3_hc_descriptor_header hc_header;
+   struct snd_pcm_chmap_elem *chmap;
+   unsigned int num_channels;
+   struct audioformat *fp;
+   u16 cluster_id, wLength;
+   int clock = 0;
+   int err;
+
+   as = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+NULL, UAC_AS_GENERAL);
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   cluster_id = le16_to_cpu(as->wClusterDescrID);
+   if (!cluster_id) {
+   dev_err(>dev,
+   "%u:%d : no cluster descriptor\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   /*
+* Get number of channels and channel map through
+* High Capability Cluster Descriptor
+*
+* First step: get High Capability header and
+* read size of Cluster Descriptor
+*/
+   err = snd_usb_ctl_msg(chip->dev,
+   usb_rcvctrlpipe(chip->dev, 0),
+   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+   cluster_id,
+   snd_usb_ctrl_intf(chip),
+   _header, sizeof(hc_header));
+   if (err < 0)
+   return ERR_PTR(err);
+   else if (err != sizeof(hc_header)) {
+   dev_err(>dev,
+   "%u:%d : can't get High Capability descriptor\n",
+   iface_no, altno);
+   return ERR_PTR(-EIO);
+   }
+
+   /*
+* Second step: allocate needed amount of memory
+* and request Cluster Descriptor
+*/
+   wLength = le16_to_cpu(hc_header.wLength);
+   cluster = kzalloc(wLength, GFP_KERNEL);
+   if (!cluster)
+   return ERR_PTR(-ENOMEM);
+   err = snd_usb_ctl_msg(chip->dev,
+   usb_rcvctrlpipe(chip->dev, 0),
+   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+   cluster_id,
+   snd_usb_ctrl_intf(chip),
+   cluster, wLength);
+   if (err < 0) {
+   kfree(cluster);
+   return ERR_PTR(err);
+   } else if (err != wLength) {
+   dev_err(>dev,
+   "%u:%d : can't get Cluster Descriptor\n",
+   iface_no, altno);
+   kfree(cluster);
+   return ERR_PTR(-EIO);
+   }
+
+   num_channels = cluster->bNrChannels;
+   chmap = convert_chmap_v3(cluster);
+   kfree(cluster);
+
+   /*
+* lookup the terminal associated to this interface
+* to extract the clock
+*/
+   input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+   as->bTerminalLink);
+   if (input_term) {
+   clock = input_term->bCSourceID;
+   goto found_clock;
+   }
+
+   output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+as->bTerminalLink);
+   if (output_term) 

[PATCH v2 2/7] ALSA: usb: stream: refactor uac1/2 audio interface parsing

2018-05-03 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function
which became quite long after adding UAC3 spec support.

Move class-specific parts of uac1/2 parsing to separate
function which now produce audioformat structure that
is ready to be fed to snd_usb_add_audio_stream().

This also broke Blue Microphones workaround (which
relies on audioformat decoded from previous altsetting)
into two parts: prepare quirk flag analyzing previous
altsetting then use it with current altsetting.

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/stream.c | 333 +
 1 file changed, 185 insertions(+), 148 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 8ec0a52..3369226 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -656,6 +656,156 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return fp;
 }
 
+static struct audioformat *
+snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int protocol, int iface_no, int altset_idx,
+ int altno, int stream, int bm_quirk)
+{
+   struct usb_device *dev = chip->dev;
+   struct uac_format_type_i_continuous_descriptor *fmt;
+   unsigned int num_channels = 0, chconfig = 0;
+   struct audioformat *fp;
+   int clock = 0;
+   u64 format;
+
+   /* get audio formats */
+   if (protocol == UAC_VERSION_1) {
+   struct uac1_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+   struct uac_input_terminal_descriptor *iterm;
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   format = le16_to_cpu(as->wFormatTag); /* remember the format 
value */
+
+   iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+as->bTerminalLink);
+   if (iterm) {
+   num_channels = iterm->bNrChannels;
+   chconfig = le16_to_cpu(iterm->wChannelConfig);
+   }
+   } else { /* UAC_VERSION_2 */
+   struct uac2_input_terminal_descriptor *input_term;
+   struct uac2_output_terminal_descriptor *output_term;
+   struct uac2_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   num_channels = as->bNrChannels;
+   format = le32_to_cpu(as->bmFormats);
+   chconfig = le32_to_cpu(as->bmChannelConfig);
+
+   /*
+* lookup the terminal associated to this interface
+* to extract the clock
+*/
+   input_term = 
snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+   
as->bTerminalLink);
+   if (input_term) {
+   clock = input_term->bCSourceID;
+   if (!chconfig && (num_channels == 
input_term->bNrChannels))
+   chconfig = 
le32_to_cpu(input_term->bmChannelConfig);
+   goto found_clock;
+   }
+
+   output_term = 
snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+ 
as->bTerminalLink);
+   if (output_term) {
+   clock = output_term->bCSourceID;
+   goto found_clock;
+   }
+
+   dev_err(>dev,
+   "%u:%d : bogus bTerminalLink %d\n",
+

[PATCH v2 3/7] ALSA: usb: stream: refactor uac3 audio interface parsing

2018-05-03 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function
which became quite long after adding UAC3 spec support.

Move class-specific parts of uac3 parsing to separate
function which now produce audioformat structure that
is ready to be fed to snd_usb_add_audio_stream().

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/stream.c | 289 +++--
 1 file changed, 146 insertions(+), 143 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 3369226..764be07 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -807,19 +807,154 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return fp;
 }
 
+static struct audioformat *
+snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
+struct usb_host_interface *alts,
+int iface_no, int altset_idx,
+int altno, int stream)
+{
+   struct usb_device *dev = chip->dev;
+   struct uac3_input_terminal_descriptor *input_term;
+   struct uac3_output_terminal_descriptor *output_term;
+   struct uac3_cluster_header_descriptor *cluster;
+   struct uac3_as_header_descriptor *as;
+   struct uac3_hc_descriptor_header hc_header;
+   struct snd_pcm_chmap_elem *chmap;
+   unsigned int num_channels;
+   struct audioformat *fp;
+   u16 cluster_id, wLength;
+   int clock = 0;
+   int err;
+
+   as = snd_usb_find_csint_desc(alts->extra, alts->extralen,
+NULL, UAC_AS_GENERAL);
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   cluster_id = le16_to_cpu(as->wClusterDescrID);
+   if (!cluster_id) {
+   dev_err(>dev,
+   "%u:%d : no cluster descriptor\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   /*
+* Get number of channels and channel map through
+* High Capability Cluster Descriptor
+*
+* First step: get High Capability header and
+* read size of Cluster Descriptor
+*/
+   err = snd_usb_ctl_msg(chip->dev,
+   usb_rcvctrlpipe(chip->dev, 0),
+   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+   cluster_id,
+   snd_usb_ctrl_intf(chip),
+   _header, sizeof(hc_header));
+   if (err < 0)
+   return ERR_PTR(err);
+   else if (err != sizeof(hc_header)) {
+   dev_err(>dev,
+   "%u:%d : can't get High Capability descriptor\n",
+   iface_no, altno);
+   return ERR_PTR(-EIO);
+   }
+
+   /*
+* Second step: allocate needed amount of memory
+* and request Cluster Descriptor
+*/
+   wLength = le16_to_cpu(hc_header.wLength);
+   cluster = kzalloc(wLength, GFP_KERNEL);
+   if (!cluster)
+   return ERR_PTR(-ENOMEM);
+   err = snd_usb_ctl_msg(chip->dev,
+   usb_rcvctrlpipe(chip->dev, 0),
+   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
+   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+   cluster_id,
+   snd_usb_ctrl_intf(chip),
+   cluster, wLength);
+   if (err < 0) {
+   kfree(cluster);
+   return ERR_PTR(err);
+   } else if (err != wLength) {
+   dev_err(>dev,
+   "%u:%d : can't get Cluster Descriptor\n",
+   iface_no, altno);
+   kfree(cluster);
+   return ERR_PTR(-EIO);
+   }
+
+   num_channels = cluster->bNrChannels;
+   chmap = convert_chmap_v3(cluster);
+   kfree(cluster);
+
+   /*
+* lookup the terminal associated to this interface
+* to extract the clock
+*/
+   input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+   as->bTerminalLink);
+   if (input_term) {
+   clock = input_term->bCSourceID;
+   goto found_clock;
+   }
+
+   output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+as->bTerminalLink);
+   if (output_term) {
+   clock = output_

[PATCH v2 1/7] ALSA: usb: stream: move audioformat alloc/init into separate function

2018-05-03 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function which
became quite long after adding UAC3 spec support.

Move audioformat allocation and initialization
into separate function, this will make easier
future refactoring.
Attributes left in the original func because it'll
be used for UAC3 BADD profiles suport in the future

There is no functional change.

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/stream.c | 52 
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 956be9f..8ec0a52 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -626,6 +626,37 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return NULL;
 }
 
+static struct audioformat *
+audio_format_alloc_init(struct snd_usb_audio *chip,
+  struct usb_host_interface *alts,
+  int protocol, int iface_no, int altset_idx,
+  int altno, int num_channels, int clock)
+{
+   struct audioformat *fp;
+
+   fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+   if (!fp)
+   return NULL;
+
+   fp->iface = iface_no;
+   fp->altsetting = altno;
+   fp->altset_idx = altset_idx;
+   fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+   fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+   fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+   fp->protocol = protocol;
+   fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+   fp->channels = num_channels;
+   if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH)
+   fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
+   * (fp->maxpacksize & 0x7ff);
+   fp->clock = clock;
+   INIT_LIST_HEAD(>list);
+
+   return fp;
+}
+
+
 int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
 {
struct usb_device *dev;
@@ -928,25 +959,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio 
*chip, int iface_no)
continue;
}
 
-   fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+   fp = audio_format_alloc_init(chip, alts, protocol, iface_no, i,
+altno, num_channels, clock);
if (!fp)
return -ENOMEM;
 
-   fp->iface = iface_no;
-   fp->altsetting = altno;
-   fp->altset_idx = i;
-   fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
-   fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
-   fp->datainterval = snd_usb_parse_datainterval(chip, alts);
-   fp->protocol = protocol;
-   fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 
0)->wMaxPacketSize);
-   fp->channels = num_channels;
-   if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
-   fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
-   * (fp->maxpacksize & 0x7ff);
-   fp->attributes = parse_uac_endpoint_attributes(chip, alts, 
protocol, iface_no);
-   fp->clock = clock;
-   INIT_LIST_HEAD(>list);
+   fp->attributes = parse_uac_endpoint_attributes(chip, alts,
+  protocol,
+  iface_no);
 
/* some quirks for attributes here */
snd_usb_audioformat_attributes_quirk(chip, fp, stream);
-- 
1.9.1



[PATCH v2 1/7] ALSA: usb: stream: move audioformat alloc/init into separate function

2018-05-03 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function which
became quite long after adding UAC3 spec support.

Move audioformat allocation and initialization
into separate function, this will make easier
future refactoring.
Attributes left in the original func because it'll
be used for UAC3 BADD profiles suport in the future

There is no functional change.

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/stream.c | 52 
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 956be9f..8ec0a52 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -626,6 +626,37 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return NULL;
 }
 
+static struct audioformat *
+audio_format_alloc_init(struct snd_usb_audio *chip,
+  struct usb_host_interface *alts,
+  int protocol, int iface_no, int altset_idx,
+  int altno, int num_channels, int clock)
+{
+   struct audioformat *fp;
+
+   fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+   if (!fp)
+   return NULL;
+
+   fp->iface = iface_no;
+   fp->altsetting = altno;
+   fp->altset_idx = altset_idx;
+   fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+   fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+   fp->datainterval = snd_usb_parse_datainterval(chip, alts);
+   fp->protocol = protocol;
+   fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+   fp->channels = num_channels;
+   if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH)
+   fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
+   * (fp->maxpacksize & 0x7ff);
+   fp->clock = clock;
+   INIT_LIST_HEAD(>list);
+
+   return fp;
+}
+
+
 int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
 {
struct usb_device *dev;
@@ -928,25 +959,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio 
*chip, int iface_no)
continue;
}
 
-   fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+   fp = audio_format_alloc_init(chip, alts, protocol, iface_no, i,
+altno, num_channels, clock);
if (!fp)
return -ENOMEM;
 
-   fp->iface = iface_no;
-   fp->altsetting = altno;
-   fp->altset_idx = i;
-   fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
-   fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
-   fp->datainterval = snd_usb_parse_datainterval(chip, alts);
-   fp->protocol = protocol;
-   fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 
0)->wMaxPacketSize);
-   fp->channels = num_channels;
-   if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
-   fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
-   * (fp->maxpacksize & 0x7ff);
-   fp->attributes = parse_uac_endpoint_attributes(chip, alts, 
protocol, iface_no);
-   fp->clock = clock;
-   INIT_LIST_HEAD(>list);
+   fp->attributes = parse_uac_endpoint_attributes(chip, alts,
+  protocol,
+  iface_no);
 
/* some quirks for attributes here */
snd_usb_audioformat_attributes_quirk(chip, fp, stream);
-- 
1.9.1



[PATCH v2 5/7] ALSA: usb: mixer: make string parsing independent of mixer_build state

2018-05-03 Thread Ruslan Bilovol
Functions like snd_usb_copy_string_desc() or
get_term_name() don't actually need mixer_build
state but can use snd_usb_audio structure instead
to get usb device.

This patch has no functional change but prepares
to future UAC3 BADD profiles support which don't
have class-specific descriptors so won't have
mixer_build state.

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/mixer.c | 30 --
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index bb203b3..e280354 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -201,10 +201,10 @@ static void *find_audio_control_unit(struct mixer_build 
*state,
 /*
  * copy a string with the given id
  */
-static int snd_usb_copy_string_desc(struct mixer_build *state,
+static int snd_usb_copy_string_desc(struct snd_usb_audio *chip,
int index, char *buf, int maxlen)
 {
-   int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
+   int len = usb_string(chip->dev, index, buf, maxlen - 1);
 
if (len < 0)
return 0;
@@ -658,14 +658,14 @@ int snd_usb_mixer_add_control(struct usb_mixer_elem_list 
*list,
{ 0 },
 };
 
-static int get_term_name(struct mixer_build *state, struct usb_audio_term 
*iterm,
+static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term 
*iterm,
 unsigned char *name, int maxlen, int term_only)
 {
struct iterm_name_combo *names;
int len;
 
if (iterm->name) {
-   len = snd_usb_copy_string_desc(state, iterm->name,
+   len = snd_usb_copy_string_desc(chip, iterm->name,
name, maxlen);
if (len)
return len;
@@ -1407,7 +1407,7 @@ static void build_feature_ctl(struct mixer_build *state, 
void *raw_desc,
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
mapped_name = len != 0;
if (!len && nameid)
-   len = snd_usb_copy_string_desc(state, nameid,
+   len = snd_usb_copy_string_desc(state->chip, nameid,
kctl->id.name, sizeof(kctl->id.name));
 
switch (control) {
@@ -1422,10 +1422,10 @@ static void build_feature_ctl(struct mixer_build 
*state, void *raw_desc,
 * - otherwise, anonymous name.
 */
if (!len) {
-   len = get_term_name(state, iterm, kctl->id.name,
+   len = get_term_name(state->chip, iterm, kctl->id.name,
sizeof(kctl->id.name), 1);
if (!len)
-   len = get_term_name(state, >oterm,
+   len = get_term_name(state->chip, >oterm,
kctl->id.name,
sizeof(kctl->id.name), 1);
if (!len)
@@ -1498,7 +1498,7 @@ static void get_connector_control_name(struct mixer_build 
*state,
   struct usb_audio_term *term,
   bool is_input, char *name, int name_size)
 {
-   int name_len = get_term_name(state, term, name, name_size, 0);
+   int name_len = get_term_name(state->chip, term, name, name_size, 0);
 
if (name_len == 0)
strlcpy(name, "Unknown", name_size);
@@ -1597,7 +1597,7 @@ static int parse_clock_source_unit(struct mixer_build 
*state, int unitid,
}
 
kctl->private_free = snd_usb_mixer_elem_free;
-   ret = snd_usb_copy_string_desc(state, hdr->iClockSource,
+   ret = snd_usb_copy_string_desc(state->chip, hdr->iClockSource,
   name, sizeof(name));
if (ret > 0)
snprintf(kctl->id.name, sizeof(kctl->id.name),
@@ -1840,7 +1840,7 @@ static void build_mixer_unit_ctl(struct mixer_build 
*state,
 
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (!len)
-   len = get_term_name(state, iterm, kctl->id.name,
+   len = get_term_name(state->chip, iterm, kctl->id.name,
sizeof(kctl->id.name), 0);
if (!len)
len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
@@ -2154,7 +2154,8 @@ static int build_audio_procunit(struct mixer_build 
*state, int unitid,
nameid = uac_processing_unit_iProcessing(desc, 
state->mixer->protocol);
len = 0;
if (nameid)
-   len = snd_usb_copy_string_desc(state, namei

[PATCH v2 5/7] ALSA: usb: mixer: make string parsing independent of mixer_build state

2018-05-03 Thread Ruslan Bilovol
Functions like snd_usb_copy_string_desc() or
get_term_name() don't actually need mixer_build
state but can use snd_usb_audio structure instead
to get usb device.

This patch has no functional change but prepares
to future UAC3 BADD profiles support which don't
have class-specific descriptors so won't have
mixer_build state.

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/mixer.c | 30 --
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index bb203b3..e280354 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -201,10 +201,10 @@ static void *find_audio_control_unit(struct mixer_build 
*state,
 /*
  * copy a string with the given id
  */
-static int snd_usb_copy_string_desc(struct mixer_build *state,
+static int snd_usb_copy_string_desc(struct snd_usb_audio *chip,
int index, char *buf, int maxlen)
 {
-   int len = usb_string(state->chip->dev, index, buf, maxlen - 1);
+   int len = usb_string(chip->dev, index, buf, maxlen - 1);
 
if (len < 0)
return 0;
@@ -658,14 +658,14 @@ int snd_usb_mixer_add_control(struct usb_mixer_elem_list 
*list,
{ 0 },
 };
 
-static int get_term_name(struct mixer_build *state, struct usb_audio_term 
*iterm,
+static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term 
*iterm,
 unsigned char *name, int maxlen, int term_only)
 {
struct iterm_name_combo *names;
int len;
 
if (iterm->name) {
-   len = snd_usb_copy_string_desc(state, iterm->name,
+   len = snd_usb_copy_string_desc(chip, iterm->name,
name, maxlen);
if (len)
return len;
@@ -1407,7 +1407,7 @@ static void build_feature_ctl(struct mixer_build *state, 
void *raw_desc,
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
mapped_name = len != 0;
if (!len && nameid)
-   len = snd_usb_copy_string_desc(state, nameid,
+   len = snd_usb_copy_string_desc(state->chip, nameid,
kctl->id.name, sizeof(kctl->id.name));
 
switch (control) {
@@ -1422,10 +1422,10 @@ static void build_feature_ctl(struct mixer_build 
*state, void *raw_desc,
 * - otherwise, anonymous name.
 */
if (!len) {
-   len = get_term_name(state, iterm, kctl->id.name,
+   len = get_term_name(state->chip, iterm, kctl->id.name,
sizeof(kctl->id.name), 1);
if (!len)
-   len = get_term_name(state, >oterm,
+   len = get_term_name(state->chip, >oterm,
kctl->id.name,
sizeof(kctl->id.name), 1);
if (!len)
@@ -1498,7 +1498,7 @@ static void get_connector_control_name(struct mixer_build 
*state,
   struct usb_audio_term *term,
   bool is_input, char *name, int name_size)
 {
-   int name_len = get_term_name(state, term, name, name_size, 0);
+   int name_len = get_term_name(state->chip, term, name, name_size, 0);
 
if (name_len == 0)
strlcpy(name, "Unknown", name_size);
@@ -1597,7 +1597,7 @@ static int parse_clock_source_unit(struct mixer_build 
*state, int unitid,
}
 
kctl->private_free = snd_usb_mixer_elem_free;
-   ret = snd_usb_copy_string_desc(state, hdr->iClockSource,
+   ret = snd_usb_copy_string_desc(state->chip, hdr->iClockSource,
   name, sizeof(name));
if (ret > 0)
snprintf(kctl->id.name, sizeof(kctl->id.name),
@@ -1840,7 +1840,7 @@ static void build_mixer_unit_ctl(struct mixer_build 
*state,
 
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (!len)
-   len = get_term_name(state, iterm, kctl->id.name,
+   len = get_term_name(state->chip, iterm, kctl->id.name,
sizeof(kctl->id.name), 0);
if (!len)
len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
@@ -2154,7 +2154,8 @@ static int build_audio_procunit(struct mixer_build 
*state, int unitid,
nameid = uac_processing_unit_iProcessing(desc, 
state->mixer->protocol);
len = 0;
if (nameid)
-   len = snd_usb_copy_string_desc(state, nameid,
+   len = snd_usb_copy_string_desc(state->chip,
+ 

[PATCH v2 7/7] ALSA: usb: add UAC3 BADD profiles support

2018-05-03 Thread Ruslan Bilovol
Recently released USB Audio Class 3.0 specification
contains BADD (Basic Audio Device Definition) document
which describes pre-defined UAC3 configurations.

BADD support is mandatory for UAC3 devices, it should be
implemented as a separate USB device configuration.
As per BADD document, class-specific descriptors
shall not be included in the Device’s Configuration
descriptor ("inferred"), but host can guess them
from BADD profile number, number of endpoints and
their max packed sizes.

This patch adds support of all BADD profiles from the spec

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/card.c   |  14 +++
 sound/usb/clock.c  |   9 +-
 sound/usb/mixer.c  | 327 -
 sound/usb/mixer_maps.c |  65 ++
 sound/usb/stream.c |  83 +++--
 sound/usb/usbaudio.h   |   2 +
 6 files changed, 459 insertions(+), 41 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 0d7a5d7..f6c3c1c 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
return -EINVAL;
}
 
+   if (protocol == UAC_VERSION_3) {
+   int badd = assoc->bFunctionSubClass;
+
+   if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 &&
+   (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO ||
+badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) {
+   dev_err(>dev,
+   "Unsupported UAC3 BADD profile\n");
+   return -EINVAL;
+   }
+
+   chip->badd_profile = badd;
+   }
+
for (i = 0; i < assoc->bInterfaceCount; i++) {
int intf = assoc->bFirstInterface + i;
 
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 0b030d8..17673f3 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, 
int iface,
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
 
-   case UAC_VERSION_2:
case UAC_VERSION_3:
+   if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
+   if (rate != UAC3_BADD_SAMPLING_RATE)
+   return -ENXIO;
+   else
+   return 0;
+   }
+   /* fall through */
+   case UAC_VERSION_2:
return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
}
 }
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e280354..d98bc3f 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -112,14 +112,12 @@ enum {
 #include "mixer_maps.c"
 
 static const struct usbmix_name_map *
-find_map(struct mixer_build *state, int unitid, int control)
+find_map(const struct usbmix_name_map *p, int unitid, int control)
 {
-   const struct usbmix_name_map *p = state->map;
-
if (!p)
return NULL;
 
-   for (p = state->map; p->id; p++) {
+   for (; p->id; p++) {
if (p->id == unitid &&
(!control || !p->control || control == p->control))
return p;
@@ -1333,16 +1331,16 @@ static struct usb_feature_control_info 
*get_feature_control_info(int control)
return NULL;
 }
 
-static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
- unsigned int ctl_mask, int control,
- struct usb_audio_term *iterm, int unitid,
- int readonly_mask)
+static void __build_feature_ctl(struct usb_mixer_interface *mixer,
+   const struct usbmix_name_map *imap,
+   unsigned int ctl_mask, int control,
+   struct usb_audio_term *iterm,
+   struct usb_audio_term *oterm,
+   int unitid, int nameid, int readonly_mask)
 {
-   struct uac_feature_unit_descriptor *desc = raw_desc;
struct usb_feature_control_info *ctl_info;
unsigned int len = 0;
int mapped_name = 0;
-   int nameid = uac_feature_unit_iFeature(desc);
struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
@@ -1353,14 +1351,14 @@ static void build_feature_ctl(struct mixer_build 
*state, void *raw_desc,
return;
}
 
-   map = find_map(state, unitid, control);
+   map = find_map(imap, unitid, control);
if (check_ignored_ctl(map))
return;
 
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
   

[PATCH v2 7/7] ALSA: usb: add UAC3 BADD profiles support

2018-05-03 Thread Ruslan Bilovol
Recently released USB Audio Class 3.0 specification
contains BADD (Basic Audio Device Definition) document
which describes pre-defined UAC3 configurations.

BADD support is mandatory for UAC3 devices, it should be
implemented as a separate USB device configuration.
As per BADD document, class-specific descriptors
shall not be included in the Device’s Configuration
descriptor ("inferred"), but host can guess them
from BADD profile number, number of endpoints and
their max packed sizes.

This patch adds support of all BADD profiles from the spec

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/card.c   |  14 +++
 sound/usb/clock.c  |   9 +-
 sound/usb/mixer.c  | 327 -
 sound/usb/mixer_maps.c |  65 ++
 sound/usb/stream.c |  83 +++--
 sound/usb/usbaudio.h   |   2 +
 6 files changed, 459 insertions(+), 41 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 0d7a5d7..f6c3c1c 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
return -EINVAL;
}
 
+   if (protocol == UAC_VERSION_3) {
+   int badd = assoc->bFunctionSubClass;
+
+   if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 &&
+   (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO ||
+badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) {
+   dev_err(>dev,
+   "Unsupported UAC3 BADD profile\n");
+   return -EINVAL;
+   }
+
+   chip->badd_profile = badd;
+   }
+
for (i = 0; i < assoc->bInterfaceCount; i++) {
int intf = assoc->bFirstInterface + i;
 
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 0b030d8..17673f3 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, 
int iface,
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
 
-   case UAC_VERSION_2:
case UAC_VERSION_3:
+   if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
+   if (rate != UAC3_BADD_SAMPLING_RATE)
+   return -ENXIO;
+   else
+   return 0;
+   }
+   /* fall through */
+   case UAC_VERSION_2:
return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
}
 }
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e280354..d98bc3f 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -112,14 +112,12 @@ enum {
 #include "mixer_maps.c"
 
 static const struct usbmix_name_map *
-find_map(struct mixer_build *state, int unitid, int control)
+find_map(const struct usbmix_name_map *p, int unitid, int control)
 {
-   const struct usbmix_name_map *p = state->map;
-
if (!p)
return NULL;
 
-   for (p = state->map; p->id; p++) {
+   for (; p->id; p++) {
if (p->id == unitid &&
(!control || !p->control || control == p->control))
return p;
@@ -1333,16 +1331,16 @@ static struct usb_feature_control_info 
*get_feature_control_info(int control)
return NULL;
 }
 
-static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
- unsigned int ctl_mask, int control,
- struct usb_audio_term *iterm, int unitid,
- int readonly_mask)
+static void __build_feature_ctl(struct usb_mixer_interface *mixer,
+   const struct usbmix_name_map *imap,
+   unsigned int ctl_mask, int control,
+   struct usb_audio_term *iterm,
+   struct usb_audio_term *oterm,
+   int unitid, int nameid, int readonly_mask)
 {
-   struct uac_feature_unit_descriptor *desc = raw_desc;
struct usb_feature_control_info *ctl_info;
unsigned int len = 0;
int mapped_name = 0;
-   int nameid = uac_feature_unit_iFeature(desc);
struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
@@ -1353,14 +1351,14 @@ static void build_feature_ctl(struct mixer_build 
*state, void *raw_desc,
return;
}
 
-   map = find_map(state, unitid, control);
+   map = find_map(imap, unitid, control);
if (check_ignored_ctl(map))
return;
 
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
i

[PATCH v2 4/7] ALSA: usb: Only get AudioControl header for UAC1 class.

2018-05-03 Thread Ruslan Bilovol
From: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>

The control header needs to be read from buffer at this point only
in the case of UAC1 protocol. Move it inside the switch case as other
protocols such as the Basic Audio Device spec will have an empty buffer
that is latter filled as inferred.

Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>
[Ruslan: updated with recently added sanity checks]
Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/card.c | 39 +++
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 36c289b..0d7a5d7 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -221,32 +221,13 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
struct usb_device *dev = chip->dev;
struct usb_host_interface *host_iface;
struct usb_interface_descriptor *altsd;
-   void *control_header;
int i, protocol;
-   int rest_bytes;
 
/* find audiocontrol interface */
host_iface = _ifnum_to_if(dev, ctrlif)->altsetting[0];
-   control_header = snd_usb_find_csint_desc(host_iface->extra,
-host_iface->extralen,
-NULL, UAC_HEADER);
altsd = get_iface_desc(host_iface);
protocol = altsd->bInterfaceProtocol;
 
-   if (!control_header) {
-   dev_err(>dev, "cannot find UAC_HEADER\n");
-   return -EINVAL;
-   }
-
-   rest_bytes = (void *)(host_iface->extra + host_iface->extralen) -
-   control_header;
-
-   /* just to be sure -- this shouldn't hit at all */
-   if (rest_bytes <= 0) {
-   dev_err(>dev, "invalid control header\n");
-   return -EINVAL;
-   }
-
switch (protocol) {
default:
dev_warn(>dev,
@@ -255,7 +236,25 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
/* fall through */
 
case UAC_VERSION_1: {
-   struct uac1_ac_header_descriptor *h1 = control_header;
+   struct uac1_ac_header_descriptor *h1;
+   int rest_bytes;
+
+   h1 = snd_usb_find_csint_desc(host_iface->extra,
+host_iface->extralen,
+NULL, UAC_HEADER);
+   if (!h1) {
+   dev_err(>dev, "cannot find UAC_HEADER\n");
+   return -EINVAL;
+   }
+
+   rest_bytes = (void *)(host_iface->extra +
+   host_iface->extralen) - (void *)h1;
+
+   /* just to be sure -- this shouldn't hit at all */
+   if (rest_bytes <= 0) {
+   dev_err(>dev, "invalid control header\n");
+   return -EINVAL;
+   }
 
if (rest_bytes < sizeof(*h1)) {
dev_err(>dev, "too short v1 buffer descriptor\n");
-- 
1.9.1



[PATCH v2 6/7] include: usb: audio-v3: add BADD-specific values

2018-05-03 Thread Ruslan Bilovol
Add BADD-specific predefined values to audio-v3
so usb-audio in ALSA and UAC3 gadget can use them

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 include/linux/usb/audio-v3.h | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
index a8959aa..38add1d 100644
--- a/include/linux/usb/audio-v3.h
+++ b/include/linux/usb/audio-v3.h
@@ -392,4 +392,30 @@ struct uac3_interrupt_data_msg {
 #define UAC3_AC_ACTIVE_INTERFACE_CONTROL   0x01
 #define UAC3_AC_POWER_DOMAIN_CONTROL   0x02
 
+/* BADD predefined Unit/Terminal values */
+#define UAC3_BADD_IT_ID1   1  /* Input Terminal ID1: bTerminalID = 1 */
+#define UAC3_BADD_FU_ID2   2  /* Feature Unit ID2: bUnitID = 2 */
+#define UAC3_BADD_OT_ID3   3  /* Output Terminal ID3: bTerminalID = 3 */
+#define UAC3_BADD_IT_ID4   4  /* Input Terminal ID4: bTerminalID = 4 */
+#define UAC3_BADD_FU_ID5   5  /* Feature Unit ID5: bUnitID = 5 */
+#define UAC3_BADD_OT_ID6   6  /* Output Terminal ID6: bTerminalID = 6 */
+#define UAC3_BADD_FU_ID7   7  /* Feature Unit ID7: bUnitID = 7 */
+#define UAC3_BADD_MU_ID8   8  /* Mixer Unit ID8: bUnitID = 8 */
+#define UAC3_BADD_CS_ID9   9  /* Clock Source Entity ID9: bClockID = 9 */
+#define UAC3_BADD_PD_ID10  10 /* Power Domain ID10: bPowerDomainID = 10 */
+#define UAC3_BADD_PD_ID11  11 /* Power Domain ID11: bPowerDomainID = 11 */
+
+/* BADD wMaxPacketSize of AS endpoints */
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16 0x0060
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_160x0062
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24 0x0090
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_240x0093
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16   0x00C0
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16  0x00C4
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24   0x0120
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24  0x0126
+
+/* BADD sample rate is always fixed to 48kHz */
+#define UAC3_BADD_SAMPLING_RATE48000
+
 #endif /* __LINUX_USB_AUDIO_V3_H */
-- 
1.9.1



[PATCH v2 4/7] ALSA: usb: Only get AudioControl header for UAC1 class.

2018-05-03 Thread Ruslan Bilovol
From: Jorge Sanjuan 

The control header needs to be read from buffer at this point only
in the case of UAC1 protocol. Move it inside the switch case as other
protocols such as the Basic Audio Device spec will have an empty buffer
that is latter filled as inferred.

Signed-off-by: Jorge Sanjuan 
[Ruslan: updated with recently added sanity checks]
Signed-off-by: Ruslan Bilovol 
---
 sound/usb/card.c | 39 +++
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 36c289b..0d7a5d7 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -221,32 +221,13 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
struct usb_device *dev = chip->dev;
struct usb_host_interface *host_iface;
struct usb_interface_descriptor *altsd;
-   void *control_header;
int i, protocol;
-   int rest_bytes;
 
/* find audiocontrol interface */
host_iface = _ifnum_to_if(dev, ctrlif)->altsetting[0];
-   control_header = snd_usb_find_csint_desc(host_iface->extra,
-host_iface->extralen,
-NULL, UAC_HEADER);
altsd = get_iface_desc(host_iface);
protocol = altsd->bInterfaceProtocol;
 
-   if (!control_header) {
-   dev_err(>dev, "cannot find UAC_HEADER\n");
-   return -EINVAL;
-   }
-
-   rest_bytes = (void *)(host_iface->extra + host_iface->extralen) -
-   control_header;
-
-   /* just to be sure -- this shouldn't hit at all */
-   if (rest_bytes <= 0) {
-   dev_err(>dev, "invalid control header\n");
-   return -EINVAL;
-   }
-
switch (protocol) {
default:
dev_warn(>dev,
@@ -255,7 +236,25 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
/* fall through */
 
case UAC_VERSION_1: {
-   struct uac1_ac_header_descriptor *h1 = control_header;
+   struct uac1_ac_header_descriptor *h1;
+   int rest_bytes;
+
+   h1 = snd_usb_find_csint_desc(host_iface->extra,
+host_iface->extralen,
+NULL, UAC_HEADER);
+   if (!h1) {
+   dev_err(>dev, "cannot find UAC_HEADER\n");
+   return -EINVAL;
+   }
+
+   rest_bytes = (void *)(host_iface->extra +
+   host_iface->extralen) - (void *)h1;
+
+   /* just to be sure -- this shouldn't hit at all */
+   if (rest_bytes <= 0) {
+   dev_err(>dev, "invalid control header\n");
+   return -EINVAL;
+   }
 
if (rest_bytes < sizeof(*h1)) {
dev_err(>dev, "too short v1 buffer descriptor\n");
-- 
1.9.1



[PATCH v2 6/7] include: usb: audio-v3: add BADD-specific values

2018-05-03 Thread Ruslan Bilovol
Add BADD-specific predefined values to audio-v3
so usb-audio in ALSA and UAC3 gadget can use them

Signed-off-by: Ruslan Bilovol 
---
 include/linux/usb/audio-v3.h | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
index a8959aa..38add1d 100644
--- a/include/linux/usb/audio-v3.h
+++ b/include/linux/usb/audio-v3.h
@@ -392,4 +392,30 @@ struct uac3_interrupt_data_msg {
 #define UAC3_AC_ACTIVE_INTERFACE_CONTROL   0x01
 #define UAC3_AC_POWER_DOMAIN_CONTROL   0x02
 
+/* BADD predefined Unit/Terminal values */
+#define UAC3_BADD_IT_ID1   1  /* Input Terminal ID1: bTerminalID = 1 */
+#define UAC3_BADD_FU_ID2   2  /* Feature Unit ID2: bUnitID = 2 */
+#define UAC3_BADD_OT_ID3   3  /* Output Terminal ID3: bTerminalID = 3 */
+#define UAC3_BADD_IT_ID4   4  /* Input Terminal ID4: bTerminalID = 4 */
+#define UAC3_BADD_FU_ID5   5  /* Feature Unit ID5: bUnitID = 5 */
+#define UAC3_BADD_OT_ID6   6  /* Output Terminal ID6: bTerminalID = 6 */
+#define UAC3_BADD_FU_ID7   7  /* Feature Unit ID7: bUnitID = 7 */
+#define UAC3_BADD_MU_ID8   8  /* Mixer Unit ID8: bUnitID = 8 */
+#define UAC3_BADD_CS_ID9   9  /* Clock Source Entity ID9: bClockID = 9 */
+#define UAC3_BADD_PD_ID10  10 /* Power Domain ID10: bPowerDomainID = 10 */
+#define UAC3_BADD_PD_ID11  11 /* Power Domain ID11: bPowerDomainID = 11 */
+
+/* BADD wMaxPacketSize of AS endpoints */
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16 0x0060
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_160x0062
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24 0x0090
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_240x0093
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16   0x00C0
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16  0x00C4
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24   0x0120
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24  0x0126
+
+/* BADD sample rate is always fixed to 48kHz */
+#define UAC3_BADD_SAMPLING_RATE48000
+
 #endif /* __LINUX_USB_AUDIO_V3_H */
-- 
1.9.1



[PATCH v2 0/7] USB Audio Device Class 3.0 BADD profiles support

2018-05-03 Thread Ruslan Bilovol
This patchset adds BADD profiles support from the USB Audio
Device Class 3.0 spec [1].

BADD profile support is defined as mandatory feature of
UAC3-compliant device, it should be implemented as a separate
USB configuration.

Notable issue with BADD configuration is that it misses
class-specific descriptors (and it's mandatory as per spec),
so host should guess them from BADD profile number and
parameters of endpoints (type, number of endpoints and
max packet size)

This patchset adds support of all known/existing BADD profiles
from the UAC3 specification.

First 5 patches are refactoring and improvements, and last 2
patches actually implement UAC3 BADD profiles support.

It's an alternative implementation comparing to [2],
and doesn't build usb descriptors on the host but instead
initializes alsa-usb structures with known parameters,
so we don't need to keep whole class-specific descriptors
in the driver since we anyway need to have BADD-specific
logic.

I've picked one Jorge's UAC1 patch-improvement and
updated it to v4.17 wich contais recently introduced
header's sanity checks.

Remaining part is to add interrupt endpoint support
so we will be able to detect jack insertion in
the Headset Adapter profile.

This has been tested on ARM and x86-64 machines with
custom UAC3 gadget which I'll post later to linux-usb

Comments and testing are welcome.

v2:
  - split refactoring patch to more atomic and bisectable
changes as suggested by Takashi
  - renamed "Side Tone"->"Sidetone" as suggested by Andrew
  - revorked main BADD patch to have table lookup for
checking BADD channels validity and to reduce identation
as suggested by Takashi
  - also removed code duplication in BADD patch by reusing
common part of build_feature_ctl() func

v1: http://mailman.alsa-project.org/pipermail/alsa-devel/2018-April/134412.html


[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] https://www.spinics.net/lists/alsa-devel/msg71614.html

Jorge Sanjuan (1):
  ALSA: usb: Only get AudioControl header for UAC1 class.

Ruslan Bilovol (6):
  ALSA: usb: stream: move audioformat alloc/init into separate function
  ALSA: usb: stream: refactor uac1/2 audio interface parsing
  ALSA: usb: stream: refactor uac3 audio interface parsing
  ALSA: usb: mixer: make string parsing independent of mixer_build state
  include: usb: audio-v3: add BADD-specific values
  ALSA: usb: add UAC3 BADD profiles support

 include/linux/usb/audio-v3.h |  26 ++
 sound/usb/card.c |  53 ++--
 sound/usb/clock.c|   9 +-
 sound/usb/mixer.c| 351 +++---
 sound/usb/mixer_maps.c   |  65 
 sound/usb/stream.c   | 687 +--
 sound/usb/usbaudio.h |   2 +
 7 files changed, 849 insertions(+), 344 deletions(-)

-- 
1.9.1



[PATCH v2 0/7] USB Audio Device Class 3.0 BADD profiles support

2018-05-03 Thread Ruslan Bilovol
This patchset adds BADD profiles support from the USB Audio
Device Class 3.0 spec [1].

BADD profile support is defined as mandatory feature of
UAC3-compliant device, it should be implemented as a separate
USB configuration.

Notable issue with BADD configuration is that it misses
class-specific descriptors (and it's mandatory as per spec),
so host should guess them from BADD profile number and
parameters of endpoints (type, number of endpoints and
max packet size)

This patchset adds support of all known/existing BADD profiles
from the UAC3 specification.

First 5 patches are refactoring and improvements, and last 2
patches actually implement UAC3 BADD profiles support.

It's an alternative implementation comparing to [2],
and doesn't build usb descriptors on the host but instead
initializes alsa-usb structures with known parameters,
so we don't need to keep whole class-specific descriptors
in the driver since we anyway need to have BADD-specific
logic.

I've picked one Jorge's UAC1 patch-improvement and
updated it to v4.17 wich contais recently introduced
header's sanity checks.

Remaining part is to add interrupt endpoint support
so we will be able to detect jack insertion in
the Headset Adapter profile.

This has been tested on ARM and x86-64 machines with
custom UAC3 gadget which I'll post later to linux-usb

Comments and testing are welcome.

v2:
  - split refactoring patch to more atomic and bisectable
changes as suggested by Takashi
  - renamed "Side Tone"->"Sidetone" as suggested by Andrew
  - revorked main BADD patch to have table lookup for
checking BADD channels validity and to reduce identation
as suggested by Takashi
  - also removed code duplication in BADD patch by reusing
common part of build_feature_ctl() func

v1: http://mailman.alsa-project.org/pipermail/alsa-devel/2018-April/134412.html


[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] https://www.spinics.net/lists/alsa-devel/msg71614.html

Jorge Sanjuan (1):
  ALSA: usb: Only get AudioControl header for UAC1 class.

Ruslan Bilovol (6):
  ALSA: usb: stream: move audioformat alloc/init into separate function
  ALSA: usb: stream: refactor uac1/2 audio interface parsing
  ALSA: usb: stream: refactor uac3 audio interface parsing
  ALSA: usb: mixer: make string parsing independent of mixer_build state
  include: usb: audio-v3: add BADD-specific values
  ALSA: usb: add UAC3 BADD profiles support

 include/linux/usb/audio-v3.h |  26 ++
 sound/usb/card.c |  53 ++--
 sound/usb/clock.c|   9 +-
 sound/usb/mixer.c| 351 +++---
 sound/usb/mixer_maps.c   |  65 
 sound/usb/stream.c   | 687 +--
 sound/usb/usbaudio.h |   2 +
 7 files changed, 849 insertions(+), 344 deletions(-)

-- 
1.9.1



Re: [PATCH v3 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-05-03 Thread Ruslan Bilovol
On Fri, Apr 27, 2018 at 8:06 PM, Jorge Sanjuan
 wrote:
> This adds support for the MIXER UNIT in UAC3. All the information
> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
> read the rest of the logical cluster to obtain the channel config
> as that wont make any difference in the current mixer behaviour.
>
> The name of the mixer unit is not yet requested as there is not
> support for the UAC3 Class Specific String requests.
>
> Tested in an UAC3 device working as a HEADSET with a basic mixer
> unit (same as the one in the BADD spec) with no controls.

So, after deeper looking into the code and after testing this patch,
in your usecase (mixer with no controls) you'll never execute
build_mixer_unit_ctl(), correct? So did you try to just fix issues with
incorrect parsing of mixer unit descriptor?

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  include/uapi/linux/usb/audio.h | 19 +++--
>  sound/usb/mixer.c  | 88 
> ++
>  2 files changed, 97 insertions(+), 10 deletions(-)
>
> diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
> index 3a78e7145689..13d98e6e0db1 100644
> --- a/include/uapi/linux/usb/audio.h
> +++ b/include/uapi/linux/usb/audio.h
> @@ -285,9 +285,22 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct 
> uac_mixer_unit_descriptor
>  static inline __u8 *uac_mixer_unit_bmControls(struct 
> uac_mixer_unit_descriptor *desc,
>   int protocol)
>  {
> -   return (protocol == UAC_VERSION_1) ?
> -   >baSourceID[desc->bNrInPins + 4] :
> -   >baSourceID[desc->bNrInPins + 6];
> +   switch (protocol) {
> +   case UAC_VERSION_1:
> +   return >baSourceID[desc->bNrInPins + 4];
> +   case UAC_VERSION_2:
> +   return >baSourceID[desc->bNrInPins + 6];
> +   case UAC_VERSION_3:
> +   return >baSourceID[desc->bNrInPins + 2];
> +   default:
> +   return NULL;
> +   }
> +}
> +
> +static inline __u16 uac3_mixer_unit_wClusterDescrID(struct 
> uac_mixer_unit_descriptor *desc)
> +{
> +   return (desc->baSourceID[desc->bNrInPins + 1] << 8) |
> +   desc->baSourceID[desc->bNrInPins];
>  }
>
>  static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor 
> *desc)
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 301ad61ed426..3503f4840ec3 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state, 
> struct usb_audio_term *iterm
>  }
>
>  /*
> + * Get logical cluster information for UAC3 devices.
> + */
> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int 
> cluster_id)
> +{
> +   struct uac3_cluster_header_descriptor c_header;
> +   int err;
> +
> +   err = snd_usb_ctl_msg(state->chip->dev,
> +   usb_rcvctrlpipe(state->chip->dev, 0),
> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +   cluster_id,
> +   snd_usb_ctrl_intf(state->chip),
> +   _header, sizeof(c_header));
> +   if (err < 0)
> +   goto error;
> +   if (err != sizeof(c_header)) {
> +   err = -EIO;
> +   goto error;
> +   }
> +
> +   return c_header.bNrChannels;
> +
> +error:
> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d 
> (err: %d)\n", cluster_id, err);
> +   return err;
> +}
> +
> +/*
> + * Get number of channels for a Mixer Unit.
> + */
> +static int uac_mixer_unit_get_channels(struct mixer_build *state,
> +  struct uac_mixer_unit_descriptor *desc)
> +{
> +   int mu_channels;
> +
> +   if (desc->bLength < 11)
> +   return -EINVAL;
> +   if (!desc->bNrInPins)
> +   return -EINVAL;
> +
> +   switch (state->mixer->protocol) {
> +   case UAC_VERSION_1:
> +   case UAC_VERSION_2:
> +   default:
> +   mu_channels = uac_mixer_unit_bNrChannels(desc);
> +   break;
> +   case UAC_VERSION_3:
> +   mu_channels = get_cluster_channels_v3(state,
> +   uac3_mixer_unit_wClusterDescrID(desc));
> +   break;
> +   }
> +
> +   if (!mu_channels)
> +   return -EINVAL;
> +
> +   return mu_channels;
> +}
> +
> +/*
>   * parse the source unit recursively until it reaches to a terminal
>   * or a branched unit.
>   */
> @@ -865,6 +925,18 @@ static int check_input_term(struct mixer_build *state, 
> int id,
> term->name = le16_to_cpu(d->wClockSourceStr);
> return 0;
> }
> +   case 

Re: [PATCH v3 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-05-03 Thread Ruslan Bilovol
On Fri, Apr 27, 2018 at 8:06 PM, Jorge Sanjuan
 wrote:
> This adds support for the MIXER UNIT in UAC3. All the information
> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
> read the rest of the logical cluster to obtain the channel config
> as that wont make any difference in the current mixer behaviour.
>
> The name of the mixer unit is not yet requested as there is not
> support for the UAC3 Class Specific String requests.
>
> Tested in an UAC3 device working as a HEADSET with a basic mixer
> unit (same as the one in the BADD spec) with no controls.

So, after deeper looking into the code and after testing this patch,
in your usecase (mixer with no controls) you'll never execute
build_mixer_unit_ctl(), correct? So did you try to just fix issues with
incorrect parsing of mixer unit descriptor?

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  include/uapi/linux/usb/audio.h | 19 +++--
>  sound/usb/mixer.c  | 88 
> ++
>  2 files changed, 97 insertions(+), 10 deletions(-)
>
> diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
> index 3a78e7145689..13d98e6e0db1 100644
> --- a/include/uapi/linux/usb/audio.h
> +++ b/include/uapi/linux/usb/audio.h
> @@ -285,9 +285,22 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct 
> uac_mixer_unit_descriptor
>  static inline __u8 *uac_mixer_unit_bmControls(struct 
> uac_mixer_unit_descriptor *desc,
>   int protocol)
>  {
> -   return (protocol == UAC_VERSION_1) ?
> -   >baSourceID[desc->bNrInPins + 4] :
> -   >baSourceID[desc->bNrInPins + 6];
> +   switch (protocol) {
> +   case UAC_VERSION_1:
> +   return >baSourceID[desc->bNrInPins + 4];
> +   case UAC_VERSION_2:
> +   return >baSourceID[desc->bNrInPins + 6];
> +   case UAC_VERSION_3:
> +   return >baSourceID[desc->bNrInPins + 2];
> +   default:
> +   return NULL;
> +   }
> +}
> +
> +static inline __u16 uac3_mixer_unit_wClusterDescrID(struct 
> uac_mixer_unit_descriptor *desc)
> +{
> +   return (desc->baSourceID[desc->bNrInPins + 1] << 8) |
> +   desc->baSourceID[desc->bNrInPins];
>  }
>
>  static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor 
> *desc)
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 301ad61ed426..3503f4840ec3 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state, 
> struct usb_audio_term *iterm
>  }
>
>  /*
> + * Get logical cluster information for UAC3 devices.
> + */
> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int 
> cluster_id)
> +{
> +   struct uac3_cluster_header_descriptor c_header;
> +   int err;
> +
> +   err = snd_usb_ctl_msg(state->chip->dev,
> +   usb_rcvctrlpipe(state->chip->dev, 0),
> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +   cluster_id,
> +   snd_usb_ctrl_intf(state->chip),
> +   _header, sizeof(c_header));
> +   if (err < 0)
> +   goto error;
> +   if (err != sizeof(c_header)) {
> +   err = -EIO;
> +   goto error;
> +   }
> +
> +   return c_header.bNrChannels;
> +
> +error:
> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d 
> (err: %d)\n", cluster_id, err);
> +   return err;
> +}
> +
> +/*
> + * Get number of channels for a Mixer Unit.
> + */
> +static int uac_mixer_unit_get_channels(struct mixer_build *state,
> +  struct uac_mixer_unit_descriptor *desc)
> +{
> +   int mu_channels;
> +
> +   if (desc->bLength < 11)
> +   return -EINVAL;
> +   if (!desc->bNrInPins)
> +   return -EINVAL;
> +
> +   switch (state->mixer->protocol) {
> +   case UAC_VERSION_1:
> +   case UAC_VERSION_2:
> +   default:
> +   mu_channels = uac_mixer_unit_bNrChannels(desc);
> +   break;
> +   case UAC_VERSION_3:
> +   mu_channels = get_cluster_channels_v3(state,
> +   uac3_mixer_unit_wClusterDescrID(desc));
> +   break;
> +   }
> +
> +   if (!mu_channels)
> +   return -EINVAL;
> +
> +   return mu_channels;
> +}
> +
> +/*
>   * parse the source unit recursively until it reaches to a terminal
>   * or a branched unit.
>   */
> @@ -865,6 +925,18 @@ static int check_input_term(struct mixer_build *state, 
> int id,
> term->name = le16_to_cpu(d->wClockSourceStr);
> return 0;
> }
> +   case UAC3_MIXER_UNIT: {
> +   struct 

Re: [alsa-devel] [PATCH v2 0/4] ALSA: usb: UAC3 new features.

2018-04-26 Thread Ruslan Bilovol
On Tue, Apr 24, 2018 at 9:02 PM, Takashi Iwai <ti...@suse.de> wrote:
> On Tue, 24 Apr 2018 19:24:41 +0200,
> Jorge Sanjuan wrote:
>>
>> v2 fixes:
>>  - If/else statements braces style fixes.
>>  - Add wrapping function to mixer unit code.
>>  - Make connectors control kctl struct const.
>>  - Little endian to cpu conversion in several places.
>>  - Sing off and add Fixes tag to fixup commit.
>>  - Remove flex-array for a struct that is used statically.
>>
>> Now that the UAC3 patch [1] has made it to linux-next I have some extra
>> features to make a UAC3 device fully work in Linux. Including Jack
>> insertion control that I have put on top of this other patch [2] for
>> UAC2. Also adding support for the UAC3 Mixer Unit which is most likely
>> to appear in most headset type devices.

Thanks for adding these improvements!

>
> These patches look reasonable, I'm OK to merge.  But I'll wait for
> Ruslan's comments (or at best with test results).

I reviewed first 3 patches and will review jack detection patch later,
and I'm going to test this patchset in a next few days.

>
>> UAC3 devices also require to have a Basic Audio Device (BADD) in a separate
>> config for which both Ruslan Bilovol and myself have submited different
>> approaches[3][4] but I don't know what the final merge will be. Once there
>> is official support for BADD, we'll need to test it with an actual UAC3
>> device to confirm it all wokrs.
>
> Could you guys try to get agreement which approach should we take?
>
> I have no big preference.  Currently Ruslan's patch series look
> easier, just because its addition is a bit smaller, though.

The BADD devices are quite simple, so direct initialization internal ALSA
structures looks easy and straightforward, comparing to generation of
missing descriptors.
I'm currently improving the patch series so it will look even more
smaller and easier, let's see how it goes

Thanks,
Ruslan

>
>
> Thanks!
>
> Takashi
>
>> All this features are tested with an actual UAC3 device that is still in
>> development. For this patch series, only the legacy config (#1. UAC1/UAC2)
>> and the UAC3 config have been tested. The BADD config is only tested using
>> and updated verison of [4].
>>
>> [1]: https://patchwork.kernel.org/patch/10298179/
>> [2]: https://patchwork.kernel.org/patch/10305847/
>> [3]: https://patchwork.kernel.org/patch/10340851/
>> [4]: https://www.spinics.net/lists/alsa-devel/msg71617.html
>>
>> Based on linux-next tag: next-20180420
>>
>> Jorge Sanjuan (3):
>>   ALSA: usb-audio: UAC3. Add support for mixer unit.
>>   ALSA: usb-audio: Use Class Specific EP for UAC3 devices.
>>   ALSA: usb-audio: UAC3 Add support for connector insertion.
>>
>> Michael Drake (1):
>>   ALSA: usb-audio: ADC3: Fix channel mapping conversion for ADC3.
>>
>>  include/linux/usb/audio-v2.h   |   7 ++
>>  include/linux/usb/audio-v3.h   |  14 +++
>>  include/uapi/linux/usb/audio.h |  13 ++-
>>  sound/usb/mixer.c  | 195 
>> +
>>  sound/usb/stream.c |  11 ++-
>>  5 files changed, 217 insertions(+), 23 deletions(-)
>>
>> --
>> 2.11.0
>>
>>
> ___
> Alsa-devel mailing list
> alsa-de...@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


Re: [alsa-devel] [PATCH v2 0/4] ALSA: usb: UAC3 new features.

2018-04-26 Thread Ruslan Bilovol
On Tue, Apr 24, 2018 at 9:02 PM, Takashi Iwai  wrote:
> On Tue, 24 Apr 2018 19:24:41 +0200,
> Jorge Sanjuan wrote:
>>
>> v2 fixes:
>>  - If/else statements braces style fixes.
>>  - Add wrapping function to mixer unit code.
>>  - Make connectors control kctl struct const.
>>  - Little endian to cpu conversion in several places.
>>  - Sing off and add Fixes tag to fixup commit.
>>  - Remove flex-array for a struct that is used statically.
>>
>> Now that the UAC3 patch [1] has made it to linux-next I have some extra
>> features to make a UAC3 device fully work in Linux. Including Jack
>> insertion control that I have put on top of this other patch [2] for
>> UAC2. Also adding support for the UAC3 Mixer Unit which is most likely
>> to appear in most headset type devices.

Thanks for adding these improvements!

>
> These patches look reasonable, I'm OK to merge.  But I'll wait for
> Ruslan's comments (or at best with test results).

I reviewed first 3 patches and will review jack detection patch later,
and I'm going to test this patchset in a next few days.

>
>> UAC3 devices also require to have a Basic Audio Device (BADD) in a separate
>> config for which both Ruslan Bilovol and myself have submited different
>> approaches[3][4] but I don't know what the final merge will be. Once there
>> is official support for BADD, we'll need to test it with an actual UAC3
>> device to confirm it all wokrs.
>
> Could you guys try to get agreement which approach should we take?
>
> I have no big preference.  Currently Ruslan's patch series look
> easier, just because its addition is a bit smaller, though.

The BADD devices are quite simple, so direct initialization internal ALSA
structures looks easy and straightforward, comparing to generation of
missing descriptors.
I'm currently improving the patch series so it will look even more
smaller and easier, let's see how it goes

Thanks,
Ruslan

>
>
> Thanks!
>
> Takashi
>
>> All this features are tested with an actual UAC3 device that is still in
>> development. For this patch series, only the legacy config (#1. UAC1/UAC2)
>> and the UAC3 config have been tested. The BADD config is only tested using
>> and updated verison of [4].
>>
>> [1]: https://patchwork.kernel.org/patch/10298179/
>> [2]: https://patchwork.kernel.org/patch/10305847/
>> [3]: https://patchwork.kernel.org/patch/10340851/
>> [4]: https://www.spinics.net/lists/alsa-devel/msg71617.html
>>
>> Based on linux-next tag: next-20180420
>>
>> Jorge Sanjuan (3):
>>   ALSA: usb-audio: UAC3. Add support for mixer unit.
>>   ALSA: usb-audio: Use Class Specific EP for UAC3 devices.
>>   ALSA: usb-audio: UAC3 Add support for connector insertion.
>>
>> Michael Drake (1):
>>   ALSA: usb-audio: ADC3: Fix channel mapping conversion for ADC3.
>>
>>  include/linux/usb/audio-v2.h   |   7 ++
>>  include/linux/usb/audio-v3.h   |  14 +++
>>  include/uapi/linux/usb/audio.h |  13 ++-
>>  sound/usb/mixer.c  | 195 
>> +
>>  sound/usb/stream.c |  11 ++-
>>  5 files changed, 217 insertions(+), 23 deletions(-)
>>
>> --
>> 2.11.0
>>
>>
> ___
> Alsa-devel mailing list
> alsa-de...@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


Re: [alsa-devel] [PATCH v2 3/4] ALSA: usb-audio: Use Class Specific EP for UAC3 devices.

2018-04-25 Thread Ruslan Bilovol
On Tue, Apr 24, 2018 at 8:24 PM, Jorge Sanjuan
<jorge.sanj...@codethink.co.uk> wrote:
> bmAtributes offset doesn't exist in the UAC3 CS_EP descriptor.
> Hence, checking for pitch control as if it was UAC2 doesn't make
> any sense. Use the defined UAC3 offsets instead.
>
> Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>

Reviewed-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>

> ---
>  sound/usb/stream.c | 9 -
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/sound/usb/stream.c b/sound/usb/stream.c
> index 956be9f7c72a..5ed334575fc7 100644
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -576,7 +576,7 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
>
> if (protocol == UAC_VERSION_1) {
> attributes = csep->bmAttributes;
> -   } else {
> +   } else if (protocol == UAC_VERSION_2) {
> struct uac2_iso_endpoint_descriptor *csep2 =
> (struct uac2_iso_endpoint_descriptor *) csep;
>
> @@ -585,6 +585,13 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
> /* emulate the endpoint attributes of a v1 device */
> if (csep2->bmControls & UAC2_CONTROL_PITCH)
> attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> +   } else { /* UAC_VERSION_3 */
> +   struct uac3_iso_endpoint_descriptor *csep3 =
> +   (struct uac3_iso_endpoint_descriptor *) csep;
> +
> +   /* emulate the endpoint attributes of a v1 device */
> +   if (le32_to_cpu(csep3->bmControls) & UAC2_CONTROL_PITCH)
> +   attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> }
>
> return attributes;
> --
> 2.11.0
>
> ___
> Alsa-devel mailing list
> alsa-de...@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


Re: [alsa-devel] [PATCH v2 3/4] ALSA: usb-audio: Use Class Specific EP for UAC3 devices.

2018-04-25 Thread Ruslan Bilovol
On Tue, Apr 24, 2018 at 8:24 PM, Jorge Sanjuan
 wrote:
> bmAtributes offset doesn't exist in the UAC3 CS_EP descriptor.
> Hence, checking for pitch control as if it was UAC2 doesn't make
> any sense. Use the defined UAC3 offsets instead.
>
> Signed-off-by: Jorge Sanjuan 

Reviewed-by: Ruslan Bilovol 

> ---
>  sound/usb/stream.c | 9 -
>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/sound/usb/stream.c b/sound/usb/stream.c
> index 956be9f7c72a..5ed334575fc7 100644
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -576,7 +576,7 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
>
> if (protocol == UAC_VERSION_1) {
> attributes = csep->bmAttributes;
> -   } else {
> +   } else if (protocol == UAC_VERSION_2) {
> struct uac2_iso_endpoint_descriptor *csep2 =
> (struct uac2_iso_endpoint_descriptor *) csep;
>
> @@ -585,6 +585,13 @@ static int parse_uac_endpoint_attributes(struct 
> snd_usb_audio *chip,
> /* emulate the endpoint attributes of a v1 device */
> if (csep2->bmControls & UAC2_CONTROL_PITCH)
> attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> +   } else { /* UAC_VERSION_3 */
> +   struct uac3_iso_endpoint_descriptor *csep3 =
> +   (struct uac3_iso_endpoint_descriptor *) csep;
> +
> +   /* emulate the endpoint attributes of a v1 device */
> +   if (le32_to_cpu(csep3->bmControls) & UAC2_CONTROL_PITCH)
> +   attributes |= UAC_EP_CS_ATTR_PITCH_CONTROL;
> }
>
> return attributes;
> --
> 2.11.0
>
> ___
> Alsa-devel mailing list
> alsa-de...@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


Re: [alsa-devel] [PATCH v2 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-04-25 Thread Ruslan Bilovol
 On Tue, Apr 24, 2018 at 8:24 PM, Jorge Sanjuan
 wrote:
> This adds support for the MIXER UNIT in UAC3. All the information
> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
> read the rest of the logical cluster to obtain the channel config
> as that wont make any difference in the current mixer behaviour.
>
> The name of the mixer unit is not yet requested as there is not
> support for the UAC3 Class Specific String requests.
>
> Tested in an UAC3 device working as a HEADSET with a basic mixer
> unit (same as the one in the BADD spec) with no controls.

The patch looks OK in general, but I have few comments

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  include/uapi/linux/usb/audio.h | 13 +--
>  sound/usb/mixer.c  | 87 
> --
>  2 files changed, 93 insertions(+), 7 deletions(-)
>
> diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
> index 3a78e7145689..f9be472cd025 100644
> --- a/include/uapi/linux/usb/audio.h
> +++ b/include/uapi/linux/usb/audio.h
> @@ -285,9 +285,16 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct 
> uac_mixer_unit_descriptor
>  static inline __u8 *uac_mixer_unit_bmControls(struct 
> uac_mixer_unit_descriptor *desc,
>   int protocol)

Name of this function is ambiguous, that's because UAC1 mixer unit
has only bmControls bitmap, whereas UAC2/3 mixer unit has two
bitmaps (bmMixerControls and bmControls), in latter case this func
returns pointer to bmMixerControls.

Maybe in the future we will need to rename it, but at least having
comment which clarifies that in case of UAC2/3 this function actually
returns pointer to bmMixerControls here will be helpful for code readers.

>  {
> -   return (protocol == UAC_VERSION_1) ?
> -   >baSourceID[desc->bNrInPins + 4] :
> -   >baSourceID[desc->bNrInPins + 6];
> +   switch (protocol) {
> +   case UAC_VERSION_1:
> +   return >baSourceID[desc->bNrInPins + 4];
> +   case UAC_VERSION_2:
> +   return >baSourceID[desc->bNrInPins + 6];
> +   case UAC_VERSION_3:
> +   return >baSourceID[desc->bNrInPins + 2];
> +   default:
> +   return NULL;
> +   }
>  }
>
>  static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor 
> *desc)
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 301ad61ed426..bf701b466a4e 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state, 
> struct usb_audio_term *iterm
>  }
>
>  /*
> + * Get logical cluster information for UAC3 devices.
> + */
> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int 
> cluster_id)
> +{
> +   struct uac3_cluster_header_descriptor c_header;
> +   int err;
> +
> +   err = snd_usb_ctl_msg(state->chip->dev,
> +   usb_rcvctrlpipe(state->chip->dev, 0),
> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +   cluster_id,
> +   snd_usb_ctrl_intf(state->chip),
> +   _header, sizeof(c_header));
> +   if (err < 0)
> +   goto error;
> +   if (err != sizeof(c_header)) {
> +   err = -EIO;
> +   goto error;
> +   }
> +
> +   return c_header.bNrChannels;
> +
> +error:
> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d 
> (err: %d)\n", cluster_id, err);
> +   return err;
> +}
> +
> +/*
> + * Get number of channels for a Mixer Unit.
> + */
> +static int uac_mixer_unit_get_channels(struct mixer_build *state,
> +  struct uac_mixer_unit_descriptor *desc)
> +{
> +   int mu_channels;
> +
> +   if (desc->bLength < 11)
> +   return -EINVAL;
> +   if (!desc->bNrInPins)
> +   return -EINVAL;
> +
> +   switch (state->mixer->protocol) {
> +   case UAC_VERSION_1:
> +   case UAC_VERSION_2:
> +   default:
> +   mu_channels = uac_mixer_unit_bNrChannels(desc);
> +   break;
> +   case UAC_VERSION_3:
> +   mu_channels = get_cluster_channels_v3(state,
> +   
> le16_to_cpu(desc->baSourceID[desc->bNrInPins]));

It would be good to create and use some helper here, for example implement
uac3_mixer_unit_wClusterDescrID() similar to uac_mixer_unit_bNrChannels().
It will put all this conversation to a single place and will improve
code readability.

> +   break;
> +   }
> +
> +   if (!mu_channels)
> +   return -EINVAL;
> +
> +   return mu_channels;
> +}
> +
> +/*
>   * parse the source unit recursively until it reaches to a terminal
>   * or a branched unit.
>   */
> @@ 

Re: [alsa-devel] [PATCH v2 1/4] ALSA: usb-audio: UAC3. Add support for mixer unit.

2018-04-25 Thread Ruslan Bilovol
 On Tue, Apr 24, 2018 at 8:24 PM, Jorge Sanjuan
 wrote:
> This adds support for the MIXER UNIT in UAC3. All the information
> is obtained from the (HIGH CAPABILITY) Cluster's header. We don't
> read the rest of the logical cluster to obtain the channel config
> as that wont make any difference in the current mixer behaviour.
>
> The name of the mixer unit is not yet requested as there is not
> support for the UAC3 Class Specific String requests.
>
> Tested in an UAC3 device working as a HEADSET with a basic mixer
> unit (same as the one in the BADD spec) with no controls.

The patch looks OK in general, but I have few comments

>
> Signed-off-by: Jorge Sanjuan 
> ---
>  include/uapi/linux/usb/audio.h | 13 +--
>  sound/usb/mixer.c  | 87 
> --
>  2 files changed, 93 insertions(+), 7 deletions(-)
>
> diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
> index 3a78e7145689..f9be472cd025 100644
> --- a/include/uapi/linux/usb/audio.h
> +++ b/include/uapi/linux/usb/audio.h
> @@ -285,9 +285,16 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct 
> uac_mixer_unit_descriptor
>  static inline __u8 *uac_mixer_unit_bmControls(struct 
> uac_mixer_unit_descriptor *desc,
>   int protocol)

Name of this function is ambiguous, that's because UAC1 mixer unit
has only bmControls bitmap, whereas UAC2/3 mixer unit has two
bitmaps (bmMixerControls and bmControls), in latter case this func
returns pointer to bmMixerControls.

Maybe in the future we will need to rename it, but at least having
comment which clarifies that in case of UAC2/3 this function actually
returns pointer to bmMixerControls here will be helpful for code readers.

>  {
> -   return (protocol == UAC_VERSION_1) ?
> -   >baSourceID[desc->bNrInPins + 4] :
> -   >baSourceID[desc->bNrInPins + 6];
> +   switch (protocol) {
> +   case UAC_VERSION_1:
> +   return >baSourceID[desc->bNrInPins + 4];
> +   case UAC_VERSION_2:
> +   return >baSourceID[desc->bNrInPins + 6];
> +   case UAC_VERSION_3:
> +   return >baSourceID[desc->bNrInPins + 2];
> +   default:
> +   return NULL;
> +   }
>  }
>
>  static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor 
> *desc)
> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
> index 301ad61ed426..bf701b466a4e 100644
> --- a/sound/usb/mixer.c
> +++ b/sound/usb/mixer.c
> @@ -719,6 +719,66 @@ static int get_term_name(struct mixer_build *state, 
> struct usb_audio_term *iterm
>  }
>
>  /*
> + * Get logical cluster information for UAC3 devices.
> + */
> +static int get_cluster_channels_v3(struct mixer_build *state, unsigned int 
> cluster_id)
> +{
> +   struct uac3_cluster_header_descriptor c_header;
> +   int err;
> +
> +   err = snd_usb_ctl_msg(state->chip->dev,
> +   usb_rcvctrlpipe(state->chip->dev, 0),
> +   UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
> +   USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
> +   cluster_id,
> +   snd_usb_ctrl_intf(state->chip),
> +   _header, sizeof(c_header));
> +   if (err < 0)
> +   goto error;
> +   if (err != sizeof(c_header)) {
> +   err = -EIO;
> +   goto error;
> +   }
> +
> +   return c_header.bNrChannels;
> +
> +error:
> +   usb_audio_err(state->chip, "cannot request logical cluster ID: %d 
> (err: %d)\n", cluster_id, err);
> +   return err;
> +}
> +
> +/*
> + * Get number of channels for a Mixer Unit.
> + */
> +static int uac_mixer_unit_get_channels(struct mixer_build *state,
> +  struct uac_mixer_unit_descriptor *desc)
> +{
> +   int mu_channels;
> +
> +   if (desc->bLength < 11)
> +   return -EINVAL;
> +   if (!desc->bNrInPins)
> +   return -EINVAL;
> +
> +   switch (state->mixer->protocol) {
> +   case UAC_VERSION_1:
> +   case UAC_VERSION_2:
> +   default:
> +   mu_channels = uac_mixer_unit_bNrChannels(desc);
> +   break;
> +   case UAC_VERSION_3:
> +   mu_channels = get_cluster_channels_v3(state,
> +   
> le16_to_cpu(desc->baSourceID[desc->bNrInPins]));

It would be good to create and use some helper here, for example implement
uac3_mixer_unit_wClusterDescrID() similar to uac_mixer_unit_bNrChannels().
It will put all this conversation to a single place and will improve
code readability.

> +   break;
> +   }
> +
> +   if (!mu_channels)
> +   return -EINVAL;
> +
> +   return mu_channels;
> +}
> +
> +/*
>   * parse the source unit recursively until it reaches to a terminal
>   * or a branched unit.
>   */
> @@ -865,6 +925,18 @@ static int check_input_term(struct 

Re: [alsa-devel] [PATCH 2/4] ALSA: usb-audio: ADC3: Fix channel mapping conversion for ADC3.

2018-04-24 Thread Ruslan Bilovol
On Fri, Apr 20, 2018 at 8:03 PM, Jorge Sanjuan
<jorge.sanj...@codethink.co.uk> wrote:
> From: Michael Drake <michael.dr...@codethink.co.uk>
>
> The channel mapping is defined by bChRelationship, not bChPurpose.
>
> Signed-off-by: Michael Drake <michael.dr...@codethink.co.uk>
> ---
>  sound/usb/stream.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/sound/usb/stream.c b/sound/usb/stream.c
> index 6a8f5843334e..956be9f7c72a 100644
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -349,7 +349,7 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct 
> uac3_cluster_header_descriptor
>  * TODO: this conversion is not complete, update it
>  * after adding UAC3 values to asound.h
>  */
> -   switch (is->bChPurpose) {
> +   switch (is->bChRelationship) {

Good catch!

Somehow I overlooked this, so in my case of Generic Audio it is always
mono.

Reviewed-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>

> case UAC3_CH_MONO:
> map = SNDRV_CHMAP_MONO;
> break;
> --
> 2.11.0
>
> ___
> Alsa-devel mailing list
> alsa-de...@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


Re: [alsa-devel] [PATCH 2/4] ALSA: usb-audio: ADC3: Fix channel mapping conversion for ADC3.

2018-04-24 Thread Ruslan Bilovol
On Fri, Apr 20, 2018 at 8:03 PM, Jorge Sanjuan
 wrote:
> From: Michael Drake 
>
> The channel mapping is defined by bChRelationship, not bChPurpose.
>
> Signed-off-by: Michael Drake 
> ---
>  sound/usb/stream.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/sound/usb/stream.c b/sound/usb/stream.c
> index 6a8f5843334e..956be9f7c72a 100644
> --- a/sound/usb/stream.c
> +++ b/sound/usb/stream.c
> @@ -349,7 +349,7 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct 
> uac3_cluster_header_descriptor
>  * TODO: this conversion is not complete, update it
>  * after adding UAC3 values to asound.h
>  */
> -   switch (is->bChPurpose) {
> +   switch (is->bChRelationship) {

Good catch!

Somehow I overlooked this, so in my case of Generic Audio it is always
mono.

Reviewed-by: Ruslan Bilovol 

> case UAC3_CH_MONO:
> map = SNDRV_CHMAP_MONO;
> break;
> --
> 2.11.0
>
> ___
> Alsa-devel mailing list
> alsa-de...@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


Re: [alsa-devel] [PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-24 Thread Ruslan Bilovol
On Thu, Apr 19, 2018 at 1:19 PM, Takashi Iwai <ti...@suse.de> wrote:
> On Sat, 14 Apr 2018 00:24:26 +0200,
> Ruslan Bilovol wrote:
>>
>> +static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
>> +   unsigned int ctl_mask, int control, int unitid,
>> +   const struct usbmix_name_map *badd_map)
>> +{
> 
>> + kctl = snd_ctl_new1(_feature_unit_ctl, cval);
>> +
>> + if (!kctl) {
>> + usb_audio_err(mixer->chip, "cannot malloc kcontrol\n");
>
> No need for error message after malloc failure.  The kernel is already
> chatty about it.

Okay. BTW, I'm trying to avoid separate badd variant of
build_feature_ctl(), so this most probably will go away.

There are many existing places in usb-snd which can be cleaned
up though.

>
>
>> +static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer,
>> +int ctrlif)
>> +{
>> + struct usb_device *dev = mixer->chip->dev;
>> + struct usb_interface_assoc_descriptor *assoc;
>> + int badd_profile = mixer->chip->badd_profile;
>> + const struct usbmix_ctl_map *map;
>> + int p_chmask = 0, c_chmask = 0, st_chmask = 0;
>> + int i;
>> +
>> + assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
>> +
>> + /* Detect BADD capture/playback channels from AS EP descriptors */
>> + for (i = 0; i < assoc->bInterfaceCount; i++) {
>> + int intf = assoc->bFirstInterface + i;
>> +
>> + if (intf != ctrlif) {
>
> In this case, it's better to skip like
>
> if (intf == ctrlif)
> continue;
>
> so that we can save an indentation for the whole long block.

Good point, will do it

>
>> + switch (badd_profile) {
>> + default:
>> + return -EINVAL;
>> + case UAC3_FUNCTION_SUBCLASS_GENERIC_IO:
>> + /*
>> +  * BAIF, BAOF or combination of both
>> +  * IN: Mono or Stereo cfg, Mono alt possible
>> +  * OUT: Mono or Stereo cfg, Mono alt possible
>> +  */
>> + /* c_chmask := DYNAMIC */
>> + /* p_chmask := DYNAMIC */
>> + if (!c_chmask && !p_chmask) {
>> + usb_audio_err(mixer->chip,
>> + "BADD GENERIC_IO profile: no channels?\n");
>> + return -EINVAL;
>> + }
>> + break;
>
> Maybe we can simplify the whole switch/case with a table lookup.

Yes, it should be possible, I'll implent it that way

Thanks,
Ruslan

> For example,
>
> for (f = uac3_func_tables; f->name; f++) {
> if (badd_profile == f->subclass)
> break;
> }
> if (!f->name)
> return -EINVAL;
> if (!uac3_func_has_valid_channels(mixer, f, c_chmask, p_chmask))
> return -EINVAL;
> st_chmask = f->st_chmask;
>
> and in uac3_func_has_valid_channels(),
>
> static bool uac3_func_has_valid_channels()
> {
> if ((f->c_chmask < 0 && !c_chmask) ||
> (f->c_chmask >= 0 && f->c_chmask != c_chmask)) {
> usb_audio_warn(mixer->chip, "BAAD %s c_chmask mismatch",
> f->name);
> return false;
> }
> if ((f->p_chmask < 0 && !p_chmask) ||
> (f->p_chmask >= 0 && f->p_chmask != p_chmask)) {
> usb_audio_warn(mixer->chip, "BAAD %s p_chmask mismatch",
> f->name);
> return false;
> }
> return true;
> }
>
>
> thanks,
>
> Takashi


Re: [alsa-devel] [PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-24 Thread Ruslan Bilovol
On Thu, Apr 19, 2018 at 1:19 PM, Takashi Iwai  wrote:
> On Sat, 14 Apr 2018 00:24:26 +0200,
> Ruslan Bilovol wrote:
>>
>> +static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
>> +   unsigned int ctl_mask, int control, int unitid,
>> +   const struct usbmix_name_map *badd_map)
>> +{
> 
>> + kctl = snd_ctl_new1(_feature_unit_ctl, cval);
>> +
>> + if (!kctl) {
>> + usb_audio_err(mixer->chip, "cannot malloc kcontrol\n");
>
> No need for error message after malloc failure.  The kernel is already
> chatty about it.

Okay. BTW, I'm trying to avoid separate badd variant of
build_feature_ctl(), so this most probably will go away.

There are many existing places in usb-snd which can be cleaned
up though.

>
>
>> +static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer,
>> +int ctrlif)
>> +{
>> + struct usb_device *dev = mixer->chip->dev;
>> + struct usb_interface_assoc_descriptor *assoc;
>> + int badd_profile = mixer->chip->badd_profile;
>> + const struct usbmix_ctl_map *map;
>> + int p_chmask = 0, c_chmask = 0, st_chmask = 0;
>> + int i;
>> +
>> + assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
>> +
>> + /* Detect BADD capture/playback channels from AS EP descriptors */
>> + for (i = 0; i < assoc->bInterfaceCount; i++) {
>> + int intf = assoc->bFirstInterface + i;
>> +
>> + if (intf != ctrlif) {
>
> In this case, it's better to skip like
>
> if (intf == ctrlif)
> continue;
>
> so that we can save an indentation for the whole long block.

Good point, will do it

>
>> + switch (badd_profile) {
>> + default:
>> + return -EINVAL;
>> + case UAC3_FUNCTION_SUBCLASS_GENERIC_IO:
>> + /*
>> +  * BAIF, BAOF or combination of both
>> +  * IN: Mono or Stereo cfg, Mono alt possible
>> +  * OUT: Mono or Stereo cfg, Mono alt possible
>> +  */
>> + /* c_chmask := DYNAMIC */
>> + /* p_chmask := DYNAMIC */
>> + if (!c_chmask && !p_chmask) {
>> + usb_audio_err(mixer->chip,
>> + "BADD GENERIC_IO profile: no channels?\n");
>> + return -EINVAL;
>> + }
>> + break;
>
> Maybe we can simplify the whole switch/case with a table lookup.

Yes, it should be possible, I'll implent it that way

Thanks,
Ruslan

> For example,
>
> for (f = uac3_func_tables; f->name; f++) {
> if (badd_profile == f->subclass)
> break;
> }
> if (!f->name)
> return -EINVAL;
> if (!uac3_func_has_valid_channels(mixer, f, c_chmask, p_chmask))
> return -EINVAL;
> st_chmask = f->st_chmask;
>
> and in uac3_func_has_valid_channels(),
>
> static bool uac3_func_has_valid_channels()
> {
> if ((f->c_chmask < 0 && !c_chmask) ||
> (f->c_chmask >= 0 && f->c_chmask != c_chmask)) {
> usb_audio_warn(mixer->chip, "BAAD %s c_chmask mismatch",
> f->name);
> return false;
> }
> if ((f->p_chmask < 0 && !p_chmask) ||
> (f->p_chmask >= 0 && f->p_chmask != p_chmask)) {
> usb_audio_warn(mixer->chip, "BAAD %s p_chmask mismatch",
> f->name);
> return false;
> }
> return true;
> }
>
>
> thanks,
>
> Takashi


Re: [alsa-devel] [PATCH 1/4] ALSA: usb: stream: refactor audio interface parsing

2018-04-23 Thread Ruslan Bilovol
On Thu, Apr 19, 2018 at 12:55 PM, Takashi Iwai <ti...@suse.de> wrote:
> On Sat, 14 Apr 2018 00:24:23 +0200,
> Ruslan Bilovol wrote:
>>
>> Offload snd_usb_parse_audio_interface() function which
>> became quite long after adding UAC3 spec support.
>>
>> Move class-specific parts to separate functions
>> which now produce audioformat structure that is
>> ready to be fed to snd_usb_add_audio_stream().
>>
>> This also broke Blue Microphones workaround (which
>> relies on audioformat decoded from previous altsetting)
>> into two parts: prepare quirk flag analyzing previous
>> altsetting then use it with current altsetting.
>>
>> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
>
> Could you try to split this patch to two parts: one is a simple
> refactoring to move the code to snd_usb_get_audioformat_uac12(), and
> another to add snd_usb_get_audioformat_uac3().
>
> In this way, we can see a problem more clearly if it's in the
> refactoring part.
>

Sure, will do in in next patchset

Thanks,
Ruslan


Re: [alsa-devel] [PATCH 1/4] ALSA: usb: stream: refactor audio interface parsing

2018-04-23 Thread Ruslan Bilovol
On Thu, Apr 19, 2018 at 12:55 PM, Takashi Iwai  wrote:
> On Sat, 14 Apr 2018 00:24:23 +0200,
> Ruslan Bilovol wrote:
>>
>> Offload snd_usb_parse_audio_interface() function which
>> became quite long after adding UAC3 spec support.
>>
>> Move class-specific parts to separate functions
>> which now produce audioformat structure that is
>> ready to be fed to snd_usb_add_audio_stream().
>>
>> This also broke Blue Microphones workaround (which
>> relies on audioformat decoded from previous altsetting)
>> into two parts: prepare quirk flag analyzing previous
>> altsetting then use it with current altsetting.
>>
>> Signed-off-by: Ruslan Bilovol 
>
> Could you try to split this patch to two parts: one is a simple
> refactoring to move the code to snd_usb_get_audioformat_uac12(), and
> another to add snd_usb_get_audioformat_uac3().
>
> In this way, we can see a problem more clearly if it's in the
> refactoring part.
>

Sure, will do in in next patchset

Thanks,
Ruslan


Re: [alsa-devel] [PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-23 Thread Ruslan Bilovol
On Thu, Apr 19, 2018 at 12:42 PM, Andrew Chant <ach...@google.com> wrote:
> On Sat, Apr 14, 2018 at 6:24 AM, Ruslan Bilovol
> <ruslan.bilo...@gmail.com> wrote:
>> Recently released USB Audio Class 3.0 specification
>> contains BADD (Basic Audio Device Definition) document
>> which describes pre-defined UAC3 configurations.
>>
>> BADD support is mandatory for UAC3 devices, it should be
>> implemented as a separate USB device configuration.
>> As per BADD document, class-specific descriptors
>> shall not be included in the Device’s Configuration
>> descriptor ("inferred"), but host can guess them
>> from BADD profile number, number of endpoints and
>> their max packed sizes.
>>
>> This patch adds support of all BADD profiles from the spec
>>
>> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
>> ---
>>  sound/usb/card.c   |  14 +++
>>  sound/usb/clock.c  |   9 +-
>>  sound/usb/mixer.c  | 313 
>> +++--
>>  sound/usb/mixer_maps.c |  65 ++
>>  sound/usb/stream.c |  83 +++--
>>  sound/usb/usbaudio.h   |   2 +
>>  6 files changed, 466 insertions(+), 20 deletions(-)
>
>> --- a/sound/usb/mixer_maps.c
>> +++ b/sound/usb/mixer_maps.c
>> @@ -482,3 +482,68 @@ struct usbmix_ctl_map {
>> { 0 } /* terminator */
>>  };
>>
>> +/*
>> + * Control map entries for UAC3 BADD profiles
>> + */
>> +
>> +static struct usbmix_name_map uac3_badd_generic_io_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Generic Out Playback" },
>> +   { UAC3_BADD_FU_ID5, "Generic In Capture" },
>> +   { 0 }   /* terminator */
>> +};
>> +static struct usbmix_name_map uac3_badd_headphone_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Headphone Playback" },
>> +   { 0 }   /* terminator */
>> +};
>> +static struct usbmix_name_map uac3_badd_speaker_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Speaker Playback" },
>> +   { 0 }   /* terminator */
>> +};
>> +static struct usbmix_name_map uac3_badd_microphone_map[] = {
>> +   { UAC3_BADD_FU_ID5, "Mic Capture" },
>> +   { 0 }   /* terminator */
>> +};
>> +/* Covers also 'headset adapter' profile */
>> +static struct usbmix_name_map uac3_badd_headset_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Headset Playback" },
>> +   { UAC3_BADD_FU_ID5, "Headset Capture" },
>> +   { UAC3_BADD_FU_ID7, "Side Tone Mixing" },
> Can you please call this "Sidetone"?
> This better matches other Sidetone control names in the sound tree and
> makes it compatible with existing Android userspace usage.

I have no any objections, "Side Tone" was in UAC3 documentation, but
"Sidetone" is OK too, so will change it

Thanks,
Ruslan


Re: [alsa-devel] [PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-23 Thread Ruslan Bilovol
On Thu, Apr 19, 2018 at 12:42 PM, Andrew Chant  wrote:
> On Sat, Apr 14, 2018 at 6:24 AM, Ruslan Bilovol
>  wrote:
>> Recently released USB Audio Class 3.0 specification
>> contains BADD (Basic Audio Device Definition) document
>> which describes pre-defined UAC3 configurations.
>>
>> BADD support is mandatory for UAC3 devices, it should be
>> implemented as a separate USB device configuration.
>> As per BADD document, class-specific descriptors
>> shall not be included in the Device’s Configuration
>> descriptor ("inferred"), but host can guess them
>> from BADD profile number, number of endpoints and
>> their max packed sizes.
>>
>> This patch adds support of all BADD profiles from the spec
>>
>> Signed-off-by: Ruslan Bilovol 
>> ---
>>  sound/usb/card.c   |  14 +++
>>  sound/usb/clock.c  |   9 +-
>>  sound/usb/mixer.c  | 313 
>> +++--
>>  sound/usb/mixer_maps.c |  65 ++
>>  sound/usb/stream.c |  83 +++--
>>  sound/usb/usbaudio.h   |   2 +
>>  6 files changed, 466 insertions(+), 20 deletions(-)
>
>> --- a/sound/usb/mixer_maps.c
>> +++ b/sound/usb/mixer_maps.c
>> @@ -482,3 +482,68 @@ struct usbmix_ctl_map {
>> { 0 } /* terminator */
>>  };
>>
>> +/*
>> + * Control map entries for UAC3 BADD profiles
>> + */
>> +
>> +static struct usbmix_name_map uac3_badd_generic_io_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Generic Out Playback" },
>> +   { UAC3_BADD_FU_ID5, "Generic In Capture" },
>> +   { 0 }   /* terminator */
>> +};
>> +static struct usbmix_name_map uac3_badd_headphone_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Headphone Playback" },
>> +   { 0 }   /* terminator */
>> +};
>> +static struct usbmix_name_map uac3_badd_speaker_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Speaker Playback" },
>> +   { 0 }   /* terminator */
>> +};
>> +static struct usbmix_name_map uac3_badd_microphone_map[] = {
>> +   { UAC3_BADD_FU_ID5, "Mic Capture" },
>> +   { 0 }   /* terminator */
>> +};
>> +/* Covers also 'headset adapter' profile */
>> +static struct usbmix_name_map uac3_badd_headset_map[] = {
>> +   { UAC3_BADD_FU_ID2, "Headset Playback" },
>> +   { UAC3_BADD_FU_ID5, "Headset Capture" },
>> +   { UAC3_BADD_FU_ID7, "Side Tone Mixing" },
> Can you please call this "Sidetone"?
> This better matches other Sidetone control names in the sound tree and
> makes it compatible with existing Android userspace usage.

I have no any objections, "Side Tone" was in UAC3 documentation, but
"Sidetone" is OK too, so will change it

Thanks,
Ruslan


Re: [PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-17 Thread Ruslan Bilovol
On Sat, Apr 14, 2018 at 8:55 PM, Jorge Sanjuan
<jorge.sanj...@codethink.co.uk> wrote:
>
>
> On 2018-04-13 23:24, Ruslan Bilovol wrote:
>>
>> Recently released USB Audio Class 3.0 specification
>> contains BADD (Basic Audio Device Definition) document
>> which describes pre-defined UAC3 configurations.
>>
>> BADD support is mandatory for UAC3 devices, it should be
>> implemented as a separate USB device configuration.
>> As per BADD document, class-specific descriptors
>> shall not be included in the Device’s Configuration
>> descriptor ("inferred"), but host can guess them
>> from BADD profile number, number of endpoints and
>> their max packed sizes.
>
>
> Right. I would have thought that, since BADD is a subset of UAC3, it may be
> simpler to fill the Class Specific descriptors buffer and let the UAC3 path
> intact as it would result in the same behavior (for UAC3 and BADD configs)
> without the need to add that much code to the mixer, which is already quite
> big.
>
> In the patch I proposed [1], the Class Specific buffer is filled once with
> the BADD descriptors, which are already UAC3 compliant, so the driver would
> handle the rest in the same way it would do with an UAC3 configuration.

That was looking as a good idea to me as well when I seen patch [1] first
time. However, after thinking a bit more, I realized that in mixer.c we
just need to initialize from one to three feature units for any BADD profile.
Mentioned Feature Units are simple and can have only Volume/Mute controls.
We also have nothing to do with Mixer Unit (which exists in BAIOF
topology) since it doesn't have any controls.
Most of the code there is to just detect all possible combinations of
channels, topologies (BAIF, BAOF, BAIOF, BAIF+BAOF) for BADD profiles,
and to add some meaningful names for feature unit controls, which
are missing in the descriptors.
The only change in the mixer.c I'm unhappy with is to have separate
build_feature_ctl_badd() function that is nothing else but simplified
version of build_feature_ctl() function; but I already have an idea how to
reuse original one for BADD case.

Changes to stream.c are very simple and straightforward, almost all
values are common/predefined for all BADD profiles except channel
numbers and sample size.

So as a boottom line direct changes to mixer/stream code seems more
easy and understandable in this particular case rather than generating
all needed class-specific desriptors. And we have all BADD profiles
support in this quite short patch.

Thanks,
Ruslan

>
> I will keep an eye on this as I'd need to do some work based on this
> instead.
>
> [1] https://www.spinics.net/lists/alsa-devel/msg71617.html
>
> Thanks,
>
> Jorge
>
>>
>> This patch adds support of all BADD profiles from the spec
>>
>> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
>> ---
>>  sound/usb/card.c   |  14 +++
>>  sound/usb/clock.c  |   9 +-
>>  sound/usb/mixer.c  | 313
>> +++--
>>  sound/usb/mixer_maps.c |  65 ++
>>  sound/usb/stream.c |  83 +++--
>>  sound/usb/usbaudio.h   |   2 +
>>  6 files changed, 466 insertions(+), 20 deletions(-)
>>
>> diff --git a/sound/usb/card.c b/sound/usb/card.c
>> index 4d866bd..47ebc50 100644
>> --- a/sound/usb/card.c
>> +++ b/sound/usb/card.c
>> @@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct
>> snd_usb_audio *chip, int ctrlif)
>> return -EINVAL;
>> }
>>
>> +   if (protocol == UAC_VERSION_3) {
>> +   int badd = assoc->bFunctionSubClass;
>> +
>> +   if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 &&
>> +   (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO ||
>> +badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE))
>> {
>> +   dev_err(>dev,
>> +   "Unsupported UAC3 BADD
>> profile\n");
>> +   return -EINVAL;
>> +   }
>> +
>> +   chip->badd_profile = badd;
>> +   }
>> +
>> for (i = 0; i < assoc->bInterfaceCount; i++) {
>> int intf = assoc->bFirstInterface + i;
>>
>> diff --git a/sound/usb/clock.c b/sound/usb/clock.c
>> index 0b030d8..17673f3 100644
>> --- a/sound/usb/clock.c
>> +++ b/sound/usb/clock.c
>> @@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio
>> *chip,

Re: [PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-17 Thread Ruslan Bilovol
On Sat, Apr 14, 2018 at 8:55 PM, Jorge Sanjuan
 wrote:
>
>
> On 2018-04-13 23:24, Ruslan Bilovol wrote:
>>
>> Recently released USB Audio Class 3.0 specification
>> contains BADD (Basic Audio Device Definition) document
>> which describes pre-defined UAC3 configurations.
>>
>> BADD support is mandatory for UAC3 devices, it should be
>> implemented as a separate USB device configuration.
>> As per BADD document, class-specific descriptors
>> shall not be included in the Device’s Configuration
>> descriptor ("inferred"), but host can guess them
>> from BADD profile number, number of endpoints and
>> their max packed sizes.
>
>
> Right. I would have thought that, since BADD is a subset of UAC3, it may be
> simpler to fill the Class Specific descriptors buffer and let the UAC3 path
> intact as it would result in the same behavior (for UAC3 and BADD configs)
> without the need to add that much code to the mixer, which is already quite
> big.
>
> In the patch I proposed [1], the Class Specific buffer is filled once with
> the BADD descriptors, which are already UAC3 compliant, so the driver would
> handle the rest in the same way it would do with an UAC3 configuration.

That was looking as a good idea to me as well when I seen patch [1] first
time. However, after thinking a bit more, I realized that in mixer.c we
just need to initialize from one to three feature units for any BADD profile.
Mentioned Feature Units are simple and can have only Volume/Mute controls.
We also have nothing to do with Mixer Unit (which exists in BAIOF
topology) since it doesn't have any controls.
Most of the code there is to just detect all possible combinations of
channels, topologies (BAIF, BAOF, BAIOF, BAIF+BAOF) for BADD profiles,
and to add some meaningful names for feature unit controls, which
are missing in the descriptors.
The only change in the mixer.c I'm unhappy with is to have separate
build_feature_ctl_badd() function that is nothing else but simplified
version of build_feature_ctl() function; but I already have an idea how to
reuse original one for BADD case.

Changes to stream.c are very simple and straightforward, almost all
values are common/predefined for all BADD profiles except channel
numbers and sample size.

So as a boottom line direct changes to mixer/stream code seems more
easy and understandable in this particular case rather than generating
all needed class-specific desriptors. And we have all BADD profiles
support in this quite short patch.

Thanks,
Ruslan

>
> I will keep an eye on this as I'd need to do some work based on this
> instead.
>
> [1] https://www.spinics.net/lists/alsa-devel/msg71617.html
>
> Thanks,
>
> Jorge
>
>>
>> This patch adds support of all BADD profiles from the spec
>>
>> Signed-off-by: Ruslan Bilovol 
>> ---
>>  sound/usb/card.c   |  14 +++
>>  sound/usb/clock.c  |   9 +-
>>  sound/usb/mixer.c  | 313
>> +++--
>>  sound/usb/mixer_maps.c |  65 ++
>>  sound/usb/stream.c |  83 +++--
>>  sound/usb/usbaudio.h   |   2 +
>>  6 files changed, 466 insertions(+), 20 deletions(-)
>>
>> diff --git a/sound/usb/card.c b/sound/usb/card.c
>> index 4d866bd..47ebc50 100644
>> --- a/sound/usb/card.c
>> +++ b/sound/usb/card.c
>> @@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct
>> snd_usb_audio *chip, int ctrlif)
>> return -EINVAL;
>> }
>>
>> +   if (protocol == UAC_VERSION_3) {
>> +   int badd = assoc->bFunctionSubClass;
>> +
>> +   if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 &&
>> +   (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO ||
>> +badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE))
>> {
>> +   dev_err(>dev,
>> +   "Unsupported UAC3 BADD
>> profile\n");
>> +   return -EINVAL;
>> +   }
>> +
>> +   chip->badd_profile = badd;
>> +   }
>> +
>> for (i = 0; i < assoc->bInterfaceCount; i++) {
>> int intf = assoc->bFirstInterface + i;
>>
>> diff --git a/sound/usb/clock.c b/sound/usb/clock.c
>> index 0b030d8..17673f3 100644
>> --- a/sound/usb/clock.c
>> +++ b/sound/usb/clock.c
>> @@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio
>> *chip, int iface,
>> default:
>> return se

[PATCH 2/4] include: usb: audio-v3: add BADD-specific values

2018-04-13 Thread Ruslan Bilovol
Add BADD-specific predefined values to audio-v3
so usb-audio in ALSA and UAC3 gadget can use them

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 include/linux/usb/audio-v3.h | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
index a8959aa..38add1d 100644
--- a/include/linux/usb/audio-v3.h
+++ b/include/linux/usb/audio-v3.h
@@ -392,4 +392,30 @@ struct uac3_interrupt_data_msg {
 #define UAC3_AC_ACTIVE_INTERFACE_CONTROL   0x01
 #define UAC3_AC_POWER_DOMAIN_CONTROL   0x02
 
+/* BADD predefined Unit/Terminal values */
+#define UAC3_BADD_IT_ID1   1  /* Input Terminal ID1: bTerminalID = 1 */
+#define UAC3_BADD_FU_ID2   2  /* Feature Unit ID2: bUnitID = 2 */
+#define UAC3_BADD_OT_ID3   3  /* Output Terminal ID3: bTerminalID = 3 */
+#define UAC3_BADD_IT_ID4   4  /* Input Terminal ID4: bTerminalID = 4 */
+#define UAC3_BADD_FU_ID5   5  /* Feature Unit ID5: bUnitID = 5 */
+#define UAC3_BADD_OT_ID6   6  /* Output Terminal ID6: bTerminalID = 6 */
+#define UAC3_BADD_FU_ID7   7  /* Feature Unit ID7: bUnitID = 7 */
+#define UAC3_BADD_MU_ID8   8  /* Mixer Unit ID8: bUnitID = 8 */
+#define UAC3_BADD_CS_ID9   9  /* Clock Source Entity ID9: bClockID = 9 */
+#define UAC3_BADD_PD_ID10  10 /* Power Domain ID10: bPowerDomainID = 10 */
+#define UAC3_BADD_PD_ID11  11 /* Power Domain ID11: bPowerDomainID = 11 */
+
+/* BADD wMaxPacketSize of AS endpoints */
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16 0x0060
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_160x0062
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24 0x0090
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_240x0093
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16   0x00C0
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16  0x00C4
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24   0x0120
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24  0x0126
+
+/* BADD sample rate is always fixed to 48kHz */
+#define UAC3_BADD_SAMPLING_RATE48000
+
 #endif /* __LINUX_USB_AUDIO_V3_H */
-- 
1.9.1



[PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-13 Thread Ruslan Bilovol
Recently released USB Audio Class 3.0 specification
contains BADD (Basic Audio Device Definition) document
which describes pre-defined UAC3 configurations.

BADD support is mandatory for UAC3 devices, it should be
implemented as a separate USB device configuration.
As per BADD document, class-specific descriptors
shall not be included in the Device’s Configuration
descriptor ("inferred"), but host can guess them
from BADD profile number, number of endpoints and
their max packed sizes.

This patch adds support of all BADD profiles from the spec

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/card.c   |  14 +++
 sound/usb/clock.c  |   9 +-
 sound/usb/mixer.c  | 313 +++--
 sound/usb/mixer_maps.c |  65 ++
 sound/usb/stream.c |  83 +++--
 sound/usb/usbaudio.h   |   2 +
 6 files changed, 466 insertions(+), 20 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4d866bd..47ebc50 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
return -EINVAL;
}
 
+   if (protocol == UAC_VERSION_3) {
+   int badd = assoc->bFunctionSubClass;
+
+   if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 &&
+   (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO ||
+badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) {
+   dev_err(>dev,
+   "Unsupported UAC3 BADD profile\n");
+   return -EINVAL;
+   }
+
+   chip->badd_profile = badd;
+   }
+
for (i = 0; i < assoc->bInterfaceCount; i++) {
int intf = assoc->bFirstInterface + i;
 
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 0b030d8..17673f3 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, 
int iface,
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
 
-   case UAC_VERSION_2:
case UAC_VERSION_3:
+   if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
+   if (rate != UAC3_BADD_SAMPLING_RATE)
+   return -ENXIO;
+   else
+   return 0;
+   }
+   /* fall through */
+   case UAC_VERSION_2:
return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
}
 }
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 301ad61..e5c3b0d 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -112,14 +112,12 @@ enum {
 #include "mixer_maps.c"
 
 static const struct usbmix_name_map *
-find_map(struct mixer_build *state, int unitid, int control)
+find_map(const struct usbmix_name_map *p, int unitid, int control)
 {
-   const struct usbmix_name_map *p = state->map;
-
if (!p)
return NULL;
 
-   for (p = state->map; p->id; p++) {
+   for (; p->id; p++) {
if (p->id == unitid &&
(!control || !p->control || control == p->control))
return p;
@@ -1333,6 +1331,76 @@ static struct usb_feature_control_info 
*get_feature_control_info(int control)
return NULL;
 }
 
+static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
+ unsigned int ctl_mask, int control, int unitid,
+ const struct usbmix_name_map *badd_map)
+{
+   struct usb_feature_control_info *ctl_info;
+   unsigned int len = 0;
+   struct snd_kcontrol *kctl;
+   struct usb_mixer_elem_info *cval;
+   const struct usbmix_name_map *map;
+
+   map = find_map(badd_map, unitid, control);
+   if (!map)
+   return;
+
+   cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+   if (!cval)
+   return;
+   snd_usb_mixer_elem_init_std(>head, mixer, unitid);
+   cval->control = control;
+   cval->cmask = ctl_mask;
+
+   ctl_info = get_feature_control_info(control);
+   if (!ctl_info) {
+   kfree(cval);
+   return;
+   }
+   cval->val_type = ctl_info->type;
+
+   if (ctl_mask == 0) {
+   cval->channels = 1; /* master channel */
+   } else {
+   int i, c = 0;
+
+   for (i = 0; i < 2; i++)
+   if (ctl_mask & (1 << i))
+   c++;
+   cval->channels = c;
+   }
+
+   kctl = snd_ctl_new1(_feature_unit_ctl, cval);
+
+   if (!kctl) {
+ 

[PATCH 2/4] include: usb: audio-v3: add BADD-specific values

2018-04-13 Thread Ruslan Bilovol
Add BADD-specific predefined values to audio-v3
so usb-audio in ALSA and UAC3 gadget can use them

Signed-off-by: Ruslan Bilovol 
---
 include/linux/usb/audio-v3.h | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
index a8959aa..38add1d 100644
--- a/include/linux/usb/audio-v3.h
+++ b/include/linux/usb/audio-v3.h
@@ -392,4 +392,30 @@ struct uac3_interrupt_data_msg {
 #define UAC3_AC_ACTIVE_INTERFACE_CONTROL   0x01
 #define UAC3_AC_POWER_DOMAIN_CONTROL   0x02
 
+/* BADD predefined Unit/Terminal values */
+#define UAC3_BADD_IT_ID1   1  /* Input Terminal ID1: bTerminalID = 1 */
+#define UAC3_BADD_FU_ID2   2  /* Feature Unit ID2: bUnitID = 2 */
+#define UAC3_BADD_OT_ID3   3  /* Output Terminal ID3: bTerminalID = 3 */
+#define UAC3_BADD_IT_ID4   4  /* Input Terminal ID4: bTerminalID = 4 */
+#define UAC3_BADD_FU_ID5   5  /* Feature Unit ID5: bUnitID = 5 */
+#define UAC3_BADD_OT_ID6   6  /* Output Terminal ID6: bTerminalID = 6 */
+#define UAC3_BADD_FU_ID7   7  /* Feature Unit ID7: bUnitID = 7 */
+#define UAC3_BADD_MU_ID8   8  /* Mixer Unit ID8: bUnitID = 8 */
+#define UAC3_BADD_CS_ID9   9  /* Clock Source Entity ID9: bClockID = 9 */
+#define UAC3_BADD_PD_ID10  10 /* Power Domain ID10: bPowerDomainID = 10 */
+#define UAC3_BADD_PD_ID11  11 /* Power Domain ID11: bPowerDomainID = 11 */
+
+/* BADD wMaxPacketSize of AS endpoints */
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16 0x0060
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_160x0062
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24 0x0090
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_240x0093
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16   0x00C0
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16  0x00C4
+#define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24   0x0120
+#define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24  0x0126
+
+/* BADD sample rate is always fixed to 48kHz */
+#define UAC3_BADD_SAMPLING_RATE48000
+
 #endif /* __LINUX_USB_AUDIO_V3_H */
-- 
1.9.1



[PATCH 4/4] ALSA: usb: add UAC3 BADD profiles support

2018-04-13 Thread Ruslan Bilovol
Recently released USB Audio Class 3.0 specification
contains BADD (Basic Audio Device Definition) document
which describes pre-defined UAC3 configurations.

BADD support is mandatory for UAC3 devices, it should be
implemented as a separate USB device configuration.
As per BADD document, class-specific descriptors
shall not be included in the Device’s Configuration
descriptor ("inferred"), but host can guess them
from BADD profile number, number of endpoints and
their max packed sizes.

This patch adds support of all BADD profiles from the spec

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/card.c   |  14 +++
 sound/usb/clock.c  |   9 +-
 sound/usb/mixer.c  | 313 +++--
 sound/usb/mixer_maps.c |  65 ++
 sound/usb/stream.c |  83 +++--
 sound/usb/usbaudio.h   |   2 +
 6 files changed, 466 insertions(+), 20 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4d866bd..47ebc50 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
return -EINVAL;
}
 
+   if (protocol == UAC_VERSION_3) {
+   int badd = assoc->bFunctionSubClass;
+
+   if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 &&
+   (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO ||
+badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) {
+   dev_err(>dev,
+   "Unsupported UAC3 BADD profile\n");
+   return -EINVAL;
+   }
+
+   chip->badd_profile = badd;
+   }
+
for (i = 0; i < assoc->bInterfaceCount; i++) {
int intf = assoc->bFirstInterface + i;
 
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 0b030d8..17673f3 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, 
int iface,
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
 
-   case UAC_VERSION_2:
case UAC_VERSION_3:
+   if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
+   if (rate != UAC3_BADD_SAMPLING_RATE)
+   return -ENXIO;
+   else
+   return 0;
+   }
+   /* fall through */
+   case UAC_VERSION_2:
return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
}
 }
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 301ad61..e5c3b0d 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -112,14 +112,12 @@ enum {
 #include "mixer_maps.c"
 
 static const struct usbmix_name_map *
-find_map(struct mixer_build *state, int unitid, int control)
+find_map(const struct usbmix_name_map *p, int unitid, int control)
 {
-   const struct usbmix_name_map *p = state->map;
-
if (!p)
return NULL;
 
-   for (p = state->map; p->id; p++) {
+   for (; p->id; p++) {
if (p->id == unitid &&
(!control || !p->control || control == p->control))
return p;
@@ -1333,6 +1331,76 @@ static struct usb_feature_control_info 
*get_feature_control_info(int control)
return NULL;
 }
 
+static void build_feature_ctl_badd(struct usb_mixer_interface *mixer,
+ unsigned int ctl_mask, int control, int unitid,
+ const struct usbmix_name_map *badd_map)
+{
+   struct usb_feature_control_info *ctl_info;
+   unsigned int len = 0;
+   struct snd_kcontrol *kctl;
+   struct usb_mixer_elem_info *cval;
+   const struct usbmix_name_map *map;
+
+   map = find_map(badd_map, unitid, control);
+   if (!map)
+   return;
+
+   cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+   if (!cval)
+   return;
+   snd_usb_mixer_elem_init_std(>head, mixer, unitid);
+   cval->control = control;
+   cval->cmask = ctl_mask;
+
+   ctl_info = get_feature_control_info(control);
+   if (!ctl_info) {
+   kfree(cval);
+   return;
+   }
+   cval->val_type = ctl_info->type;
+
+   if (ctl_mask == 0) {
+   cval->channels = 1; /* master channel */
+   } else {
+   int i, c = 0;
+
+   for (i = 0; i < 2; i++)
+   if (ctl_mask & (1 << i))
+   c++;
+   cval->channels = c;
+   }
+
+   kctl = snd_ctl_new1(_feature_unit_ctl, cval);
+
+   if (!kctl) {
+   usb_audio_err(

[PATCH 3/4] ALSA: usb: Only get AudioControl header for UAC1 class.

2018-04-13 Thread Ruslan Bilovol
From: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>

The control header needs to be read from buffer at this point only
in the case of UAC1 protocol. Move it inside the switch case as other
protocols such as the Basic Audio Device spec will have an empty buffer
that is latter filled as inferred.

Signed-off-by: Jorge Sanjuan <jorge.sanj...@codethink.co.uk>
[Ruslan: updated with recently added sanity checks]
Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/card.c | 39 +++
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4a1c6bb..4d866bd 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -221,32 +221,13 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
struct usb_device *dev = chip->dev;
struct usb_host_interface *host_iface;
struct usb_interface_descriptor *altsd;
-   void *control_header;
int i, protocol;
-   int rest_bytes;
 
/* find audiocontrol interface */
host_iface = _ifnum_to_if(dev, ctrlif)->altsetting[0];
-   control_header = snd_usb_find_csint_desc(host_iface->extra,
-host_iface->extralen,
-NULL, UAC_HEADER);
altsd = get_iface_desc(host_iface);
protocol = altsd->bInterfaceProtocol;
 
-   if (!control_header) {
-   dev_err(>dev, "cannot find UAC_HEADER\n");
-   return -EINVAL;
-   }
-
-   rest_bytes = (void *)(host_iface->extra + host_iface->extralen) -
-   control_header;
-
-   /* just to be sure -- this shouldn't hit at all */
-   if (rest_bytes <= 0) {
-   dev_err(>dev, "invalid control header\n");
-   return -EINVAL;
-   }
-
switch (protocol) {
default:
dev_warn(>dev,
@@ -255,7 +236,25 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
/* fall through */
 
case UAC_VERSION_1: {
-   struct uac1_ac_header_descriptor *h1 = control_header;
+   struct uac1_ac_header_descriptor *h1;
+   int rest_bytes;
+
+   h1 = snd_usb_find_csint_desc(host_iface->extra,
+host_iface->extralen,
+NULL, UAC_HEADER);
+   if (!h1) {
+   dev_err(>dev, "cannot find UAC_HEADER\n");
+   return -EINVAL;
+   }
+
+   rest_bytes = (void *)(host_iface->extra +
+   host_iface->extralen) - (void *)h1;
+
+   /* just to be sure -- this shouldn't hit at all */
+   if (rest_bytes <= 0) {
+   dev_err(>dev, "invalid control header\n");
+   return -EINVAL;
+   }
 
if (rest_bytes < sizeof(*h1)) {
dev_err(>dev, "too short v1 buffer descriptor\n");
-- 
1.9.1



[PATCH 3/4] ALSA: usb: Only get AudioControl header for UAC1 class.

2018-04-13 Thread Ruslan Bilovol
From: Jorge Sanjuan 

The control header needs to be read from buffer at this point only
in the case of UAC1 protocol. Move it inside the switch case as other
protocols such as the Basic Audio Device spec will have an empty buffer
that is latter filled as inferred.

Signed-off-by: Jorge Sanjuan 
[Ruslan: updated with recently added sanity checks]
Signed-off-by: Ruslan Bilovol 
---
 sound/usb/card.c | 39 +++
 1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4a1c6bb..4d866bd 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -221,32 +221,13 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
struct usb_device *dev = chip->dev;
struct usb_host_interface *host_iface;
struct usb_interface_descriptor *altsd;
-   void *control_header;
int i, protocol;
-   int rest_bytes;
 
/* find audiocontrol interface */
host_iface = _ifnum_to_if(dev, ctrlif)->altsetting[0];
-   control_header = snd_usb_find_csint_desc(host_iface->extra,
-host_iface->extralen,
-NULL, UAC_HEADER);
altsd = get_iface_desc(host_iface);
protocol = altsd->bInterfaceProtocol;
 
-   if (!control_header) {
-   dev_err(>dev, "cannot find UAC_HEADER\n");
-   return -EINVAL;
-   }
-
-   rest_bytes = (void *)(host_iface->extra + host_iface->extralen) -
-   control_header;
-
-   /* just to be sure -- this shouldn't hit at all */
-   if (rest_bytes <= 0) {
-   dev_err(>dev, "invalid control header\n");
-   return -EINVAL;
-   }
-
switch (protocol) {
default:
dev_warn(>dev,
@@ -255,7 +236,25 @@ static int snd_usb_create_streams(struct snd_usb_audio 
*chip, int ctrlif)
/* fall through */
 
case UAC_VERSION_1: {
-   struct uac1_ac_header_descriptor *h1 = control_header;
+   struct uac1_ac_header_descriptor *h1;
+   int rest_bytes;
+
+   h1 = snd_usb_find_csint_desc(host_iface->extra,
+host_iface->extralen,
+NULL, UAC_HEADER);
+   if (!h1) {
+   dev_err(>dev, "cannot find UAC_HEADER\n");
+   return -EINVAL;
+   }
+
+   rest_bytes = (void *)(host_iface->extra +
+   host_iface->extralen) - (void *)h1;
+
+   /* just to be sure -- this shouldn't hit at all */
+   if (rest_bytes <= 0) {
+   dev_err(>dev, "invalid control header\n");
+   return -EINVAL;
+   }
 
if (rest_bytes < sizeof(*h1)) {
dev_err(>dev, "too short v1 buffer descriptor\n");
-- 
1.9.1



[PATCH 0/4] USB Audio Device Class 3.0 BADD profiles support

2018-04-13 Thread Ruslan Bilovol
This patchset adds BADD profiles support from the USB Audio
Device Class 3.0 spec [1].

BADD profile support is defined as mandatory feature of
UAC3-compliant device, it should be implemented as a separate
USB configuration.

Notable issue with BADD configuration is that it misses
class-specific descriptors (and it's mandatory as per spec),
so host should guess them from BADD profile number and
parameters of endpoints (type, number of endpoints and
max packet size)

This patchset adds support of all known/existing BADD profiles
from the UAC3 specification.

It's an alternative implementation comparing to [2],
and doesn't build usb descriptors on the host but instead
initializes alsa-usb structures with known parameters,
so we don't need to keep whole class-specific descriptors
in the driver since we anyway need to have BADD-specific
logic.

I've picked one Jorge's UAC1 patch-improvement and
updated it to v4.17 wich contais recently introduced
header's sanity checks.

Remaining part is to add interrupt endpoint support
so we will be able to detect jack insertion in
the Headset Adapter profile.

This has been tested on ARM and x86-64 machines with
custom UAC3 gadget which I'll post later to linux-usb

Comments and testing are welcome.

[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] https://www.spinics.net/lists/alsa-devel/msg71614.html

Jorge Sanjuan (1):
  ALSA: usb: Only get AudioControl header for UAC1 class.

Ruslan Bilovol (3):
  ALSA: usb: stream: refactor audio interface parsing
  include: usb: audio-v3: add BADD-specific values
  ALSA: usb: add UAC3 BADD profiles support

 include/linux/usb/audio-v3.h |  26 ++
 sound/usb/card.c |  53 ++--
 sound/usb/clock.c|   9 +-
 sound/usb/mixer.c| 313 +++-
 sound/usb/mixer_maps.c   |  65 +
 sound/usb/stream.c   | 678 +--
 sound/usb/usbaudio.h |   2 +
 7 files changed, 836 insertions(+), 310 deletions(-)

-- 
1.9.1



[PATCH 0/4] USB Audio Device Class 3.0 BADD profiles support

2018-04-13 Thread Ruslan Bilovol
This patchset adds BADD profiles support from the USB Audio
Device Class 3.0 spec [1].

BADD profile support is defined as mandatory feature of
UAC3-compliant device, it should be implemented as a separate
USB configuration.

Notable issue with BADD configuration is that it misses
class-specific descriptors (and it's mandatory as per spec),
so host should guess them from BADD profile number and
parameters of endpoints (type, number of endpoints and
max packet size)

This patchset adds support of all known/existing BADD profiles
from the UAC3 specification.

It's an alternative implementation comparing to [2],
and doesn't build usb descriptors on the host but instead
initializes alsa-usb structures with known parameters,
so we don't need to keep whole class-specific descriptors
in the driver since we anyway need to have BADD-specific
logic.

I've picked one Jorge's UAC1 patch-improvement and
updated it to v4.17 wich contais recently introduced
header's sanity checks.

Remaining part is to add interrupt endpoint support
so we will be able to detect jack insertion in
the Headset Adapter profile.

This has been tested on ARM and x86-64 machines with
custom UAC3 gadget which I'll post later to linux-usb

Comments and testing are welcome.

[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] https://www.spinics.net/lists/alsa-devel/msg71614.html

Jorge Sanjuan (1):
  ALSA: usb: Only get AudioControl header for UAC1 class.

Ruslan Bilovol (3):
  ALSA: usb: stream: refactor audio interface parsing
  include: usb: audio-v3: add BADD-specific values
  ALSA: usb: add UAC3 BADD profiles support

 include/linux/usb/audio-v3.h |  26 ++
 sound/usb/card.c |  53 ++--
 sound/usb/clock.c|   9 +-
 sound/usb/mixer.c| 313 +++-
 sound/usb/mixer_maps.c   |  65 +
 sound/usb/stream.c   | 678 +--
 sound/usb/usbaudio.h |   2 +
 7 files changed, 836 insertions(+), 310 deletions(-)

-- 
1.9.1



[PATCH 1/4] ALSA: usb: stream: refactor audio interface parsing

2018-04-13 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function which
became quite long after adding UAC3 spec support.

Move class-specific parts to separate functions
which now produce audioformat structure that is
ready to be fed to snd_usb_add_audio_stream().

This also broke Blue Microphones workaround (which
relies on audioformat decoded from previous altsetting)
into two parts: prepare quirk flag analyzing previous
altsetting then use it with current altsetting.

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/stream.c | 613 +
 1 file changed, 334 insertions(+), 279 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 6a8f584..586d664 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -626,6 +626,319 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return NULL;
 }
 
+static struct audioformat *
+snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int protocol, int iface_no,
+ int altno, int stream, int bm_quirk)
+{
+   struct usb_device *dev = chip->dev;
+   struct uac_format_type_i_continuous_descriptor *fmt;
+   unsigned int num_channels = 0, chconfig = 0;
+   struct audioformat *fp;
+   int clock = 0;
+   u64 format;
+
+   /* get audio formats */
+   if (protocol == UAC_VERSION_1) {
+   struct uac1_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+   struct uac_input_terminal_descriptor *iterm;
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   format = le16_to_cpu(as->wFormatTag); /* remember the format 
value */
+
+   iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+as->bTerminalLink);
+   if (iterm) {
+   num_channels = iterm->bNrChannels;
+   chconfig = le16_to_cpu(iterm->wChannelConfig);
+   }
+   } else { /* UAC_VERSION_2 */
+   struct uac2_input_terminal_descriptor *input_term;
+   struct uac2_output_terminal_descriptor *output_term;
+   struct uac2_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   num_channels = as->bNrChannels;
+   format = le32_to_cpu(as->bmFormats);
+   chconfig = le32_to_cpu(as->bmChannelConfig);
+
+   /*
+* lookup the terminal associated to this interface
+* to extract the clock
+*/
+   input_term = 
snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+   
as->bTerminalLink);
+   if (input_term) {
+   clock = input_term->bCSourceID;
+   if (!chconfig && (num_channels == 
input_term->bNrChannels))
+   chconfig = 
le32_to_cpu(input_term->bmChannelConfig);
+   goto found_clock;
+   }
+
+   output_term = 
snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+ 
as->bTerminalLink);
+   if (output_term) {
+   clock = output_term->bCSourceID;
+   goto found_clock;
+   }
+
+   dev_err(>dev,
+   "%u:%d : bogus bTerminalLink %d\n",
+  

[PATCH 1/4] ALSA: usb: stream: refactor audio interface parsing

2018-04-13 Thread Ruslan Bilovol
Offload snd_usb_parse_audio_interface() function which
became quite long after adding UAC3 spec support.

Move class-specific parts to separate functions
which now produce audioformat structure that is
ready to be fed to snd_usb_add_audio_stream().

This also broke Blue Microphones workaround (which
relies on audioformat decoded from previous altsetting)
into two parts: prepare quirk flag analyzing previous
altsetting then use it with current altsetting.

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/stream.c | 613 +
 1 file changed, 334 insertions(+), 279 deletions(-)

diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 6a8f584..586d664 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -626,6 +626,319 @@ static int parse_uac_endpoint_attributes(struct 
snd_usb_audio *chip,
return NULL;
 }
 
+static struct audioformat *
+snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int protocol, int iface_no,
+ int altno, int stream, int bm_quirk)
+{
+   struct usb_device *dev = chip->dev;
+   struct uac_format_type_i_continuous_descriptor *fmt;
+   unsigned int num_channels = 0, chconfig = 0;
+   struct audioformat *fp;
+   int clock = 0;
+   u64 format;
+
+   /* get audio formats */
+   if (protocol == UAC_VERSION_1) {
+   struct uac1_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+   struct uac_input_terminal_descriptor *iterm;
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   format = le16_to_cpu(as->wFormatTag); /* remember the format 
value */
+
+   iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+as->bTerminalLink);
+   if (iterm) {
+   num_channels = iterm->bNrChannels;
+   chconfig = le16_to_cpu(iterm->wChannelConfig);
+   }
+   } else { /* UAC_VERSION_2 */
+   struct uac2_input_terminal_descriptor *input_term;
+   struct uac2_output_terminal_descriptor *output_term;
+   struct uac2_as_header_descriptor *as =
+   snd_usb_find_csint_desc(alts->extra, alts->extralen,
+   NULL, UAC_AS_GENERAL);
+
+   if (!as) {
+   dev_err(>dev,
+   "%u:%d : UAC_AS_GENERAL descriptor not found\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   if (as->bLength < sizeof(*as)) {
+   dev_err(>dev,
+   "%u:%d : invalid UAC_AS_GENERAL desc\n",
+   iface_no, altno);
+   return NULL;
+   }
+
+   num_channels = as->bNrChannels;
+   format = le32_to_cpu(as->bmFormats);
+   chconfig = le32_to_cpu(as->bmChannelConfig);
+
+   /*
+* lookup the terminal associated to this interface
+* to extract the clock
+*/
+   input_term = 
snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+   
as->bTerminalLink);
+   if (input_term) {
+   clock = input_term->bCSourceID;
+   if (!chconfig && (num_channels == 
input_term->bNrChannels))
+   chconfig = 
le32_to_cpu(input_term->bmChannelConfig);
+   goto found_clock;
+   }
+
+   output_term = 
snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+ 
as->bTerminalLink);
+   if (output_term) {
+   clock = output_term->bCSourceID;
+   goto found_clock;
+   }
+
+   dev_err(>dev,
+   "%u:%d : bogus bTerminalLink %d\n",
+   iface_no, altno,

[PATCH v3] USB Audio Device Class 3.0 support

2018-03-20 Thread Ruslan Bilovol
Hi Takashi,

This patch adds initial USB Audio Device Class 3.0 [1]
support to the ALSA that we discussed at ELCE.

The patch was tested with UAC3 gadget [2] that I posted
to USB mailing list before. It is good for working with
BADD device which implements such topologies like
BAIF (Basic Audio Input Functions), BAOF (Basic Audio
Output Functions) or compbination of both.

UAC3 spec has changed descriptors laout and many other
codes comparing to UAC2 spec, thus making reuse of existing
sources impossible or quite complex.

There are still many areas of improvement, as this patch
doesn't have UAC3 Mixer Unit support nor some new features
like Power Management

I tested this with BeagleBone Black as UAC3 gadget device.

[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] http://www.spinics.net/lists/linux-usb/msg162482.html

v3 changes:
 - dropped audioformat quirks patch (already accepted)
 - addressed coding style requested changes

v2 changes:
 - moved audioformat quirks to quirks.c
 - addressed many comments from Pierre-Louis Bossart
 - reorganized audio-v3.h
 - added more UAC3 channel relationship definitions


Ruslan Bilovol (1):
  ALSA: usb: initial USB Audio Device Class 3.0 support

 include/linux/usb/audio-v2.h   |   4 +-
 include/linux/usb/audio-v3.h   | 395 +
 include/uapi/linux/usb/audio.h |   1 +
 sound/usb/card.c   |   7 +-
 sound/usb/card.h   |   2 +-
 sound/usb/clock.c  | 228 +---
 sound/usb/clock.h  |   4 +-
 sound/usb/format.c |  91 --
 sound/usb/format.h |   6 +-
 sound/usb/mixer.c  | 337 +++
 sound/usb/stream.c | 365 +
 11 files changed, 1246 insertions(+), 194 deletions(-)
 create mode 100644 include/linux/usb/audio-v3.h

-- 
1.9.1



[PATCH v3] ALSA: usb: initial USB Audio Device Class 3.0 support

2018-03-20 Thread Ruslan Bilovol
Recently released USB Audio Class 3.0 specification
introduces many significant changes comparing to
previous versions, like
 - new Power Domains, support for LPM/L1
 - new Cluster descriptor
 - changed layout of all class-specific descriptors
 - new High Capability descriptors
 - New class-specific String descriptors
 - new and removed units
 - additional sources for interrupts
 - removed Type II Audio Data Formats
 - ... and many other things (check spec)

It also provides backward compatibility through
multiple configurations, as well as requires
mandatory support for BADD (Basic Audio Device
Definition) on each ADC3.0 compliant device

This patch adds initial support of UAC3 specification
that is enough for Generic I/O Profile (BAOF, BAIF)
device support from BADD document.

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 include/linux/usb/audio-v2.h   |   4 +-
 include/linux/usb/audio-v3.h   | 395 +
 include/uapi/linux/usb/audio.h |   1 +
 sound/usb/card.c   |   7 +-
 sound/usb/card.h   |   2 +-
 sound/usb/clock.c  | 228 +---
 sound/usb/clock.h  |   4 +-
 sound/usb/format.c |  91 --
 sound/usb/format.h |   6 +-
 sound/usb/mixer.c  | 337 +++
 sound/usb/stream.c | 365 +
 11 files changed, 1246 insertions(+), 194 deletions(-)
 create mode 100644 include/linux/usb/audio-v3.h

diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 3119d0a..2db83a1 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -34,12 +34,12 @@
  *
  */
 
-static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
+static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control)
 {
return (bmControls >> (control * 2)) & 0x1;
 }
 
-static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
+static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control)
 {
return (bmControls >> (control * 2)) & 0x2;
 }
diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
new file mode 100644
index 000..a8959aa
--- /dev/null
+++ b/include/linux/usb/audio-v3.h
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Ruslan Bilovol <ruslan.bilo...@gmail.com>
+ *
+ * This file holds USB constants and structures defined
+ * by the USB DEVICE CLASS DEFINITION FOR AUDIO DEVICES Release 3.0.
+ */
+
+#ifndef __LINUX_USB_AUDIO_V3_H
+#define __LINUX_USB_AUDIO_V3_H
+
+#include 
+
+/*
+ * v1.0, v2.0 and v3.0 of this standard have many things in common. For the 
rest
+ * of the definitions, please refer to audio.h and audio-v2.h
+ */
+
+/* All High Capability descriptors have these 2 fields at the beginning */
+struct uac3_hc_descriptor_header {
+   __le16 wLength;
+   __u8 bDescriptorType;
+   __u8 bDescriptorSubtype;
+   __le16 wDescriptorID;
+} __attribute__ ((packed));
+
+/* 4.3.1 CLUSTER DESCRIPTOR HEADER */
+struct uac3_cluster_header_descriptor {
+   __le16 wLength;
+   __u8 bDescriptorType;
+   __u8 bDescriptorSubtype;
+   __le16 wDescriptorID;
+   __u8 bNrChannels;
+} __attribute__ ((packed));
+
+/* 4.3.2.1 SEGMENTS */
+struct uac3_cluster_segment_descriptor {
+   __le16 wLength;
+   __u8 bSegmentType;
+   /* __u8[0]; segment-specific data */
+} __attribute__ ((packed));
+
+/* 4.3.2.1.1 END SEGMENT */
+struct uac3_cluster_end_segment_descriptor {
+   __le16 wLength;
+   __u8 bSegmentType;  /* Constant END_SEGMENT */
+} __attribute__ ((packed));
+
+/* 4.3.2.1.3.1 INFORMATION SEGMENT */
+struct uac3_cluster_information_segment_descriptor {
+   __le16 wLength;
+   __u8 bSegmentType;
+   __u8 bChPurpose;
+   __u8 bChRelationship;
+   __u8 bChGroupID;
+} __attribute__ ((packed));
+
+/* 4.5.2 CLASS-SPECIFIC AC INTERFACE DESCRIPTOR */
+struct uac3_ac_header_descriptor {
+   __u8 bLength;   /* 10 */
+   __u8 bDescriptorType;   /* CS_INTERFACE descriptor type */
+   __u8 bDescriptorSubtype;/* HEADER descriptor subtype */
+   __u8 bCategory;
+
+   /* includes Clock Source, Unit, Terminal, and Power Domain desc. */
+   __le16 wTotalLength;
+
+   __le32 bmControls;
+} __attribute__ ((packed));
+
+/* 4.5.2.1 INPUT TERMINAL DESCRIPTOR */
+struct uac3_input_terminal_descriptor {
+   __u8 bLength;
+   __u8 bDescriptorType;
+   __u8 bDescriptorSubtype;
+   __u8 bTerminalID;
+   __le16 wTerminalType;
+   __u8 bAssocTerminal;
+   __u8 bCSourceID;
+   __le32 bmControls;
+   __le16 wClusterDescrID;
+   __le16 wExTerminalDescrID;
+   __le16 wConnectorsDescrID;
+   __le16 wTerminalDescrStr;
+} __attribute__((packed));
+
+/* 4.5.2.2 OUTPU

[PATCH v3] USB Audio Device Class 3.0 support

2018-03-20 Thread Ruslan Bilovol
Hi Takashi,

This patch adds initial USB Audio Device Class 3.0 [1]
support to the ALSA that we discussed at ELCE.

The patch was tested with UAC3 gadget [2] that I posted
to USB mailing list before. It is good for working with
BADD device which implements such topologies like
BAIF (Basic Audio Input Functions), BAOF (Basic Audio
Output Functions) or compbination of both.

UAC3 spec has changed descriptors laout and many other
codes comparing to UAC2 spec, thus making reuse of existing
sources impossible or quite complex.

There are still many areas of improvement, as this patch
doesn't have UAC3 Mixer Unit support nor some new features
like Power Management

I tested this with BeagleBone Black as UAC3 gadget device.

[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] http://www.spinics.net/lists/linux-usb/msg162482.html

v3 changes:
 - dropped audioformat quirks patch (already accepted)
 - addressed coding style requested changes

v2 changes:
 - moved audioformat quirks to quirks.c
 - addressed many comments from Pierre-Louis Bossart
 - reorganized audio-v3.h
 - added more UAC3 channel relationship definitions


Ruslan Bilovol (1):
  ALSA: usb: initial USB Audio Device Class 3.0 support

 include/linux/usb/audio-v2.h   |   4 +-
 include/linux/usb/audio-v3.h   | 395 +
 include/uapi/linux/usb/audio.h |   1 +
 sound/usb/card.c   |   7 +-
 sound/usb/card.h   |   2 +-
 sound/usb/clock.c  | 228 +---
 sound/usb/clock.h  |   4 +-
 sound/usb/format.c |  91 --
 sound/usb/format.h |   6 +-
 sound/usb/mixer.c  | 337 +++
 sound/usb/stream.c | 365 +
 11 files changed, 1246 insertions(+), 194 deletions(-)
 create mode 100644 include/linux/usb/audio-v3.h

-- 
1.9.1



[PATCH v3] ALSA: usb: initial USB Audio Device Class 3.0 support

2018-03-20 Thread Ruslan Bilovol
Recently released USB Audio Class 3.0 specification
introduces many significant changes comparing to
previous versions, like
 - new Power Domains, support for LPM/L1
 - new Cluster descriptor
 - changed layout of all class-specific descriptors
 - new High Capability descriptors
 - New class-specific String descriptors
 - new and removed units
 - additional sources for interrupts
 - removed Type II Audio Data Formats
 - ... and many other things (check spec)

It also provides backward compatibility through
multiple configurations, as well as requires
mandatory support for BADD (Basic Audio Device
Definition) on each ADC3.0 compliant device

This patch adds initial support of UAC3 specification
that is enough for Generic I/O Profile (BAOF, BAIF)
device support from BADD document.

Signed-off-by: Ruslan Bilovol 
---
 include/linux/usb/audio-v2.h   |   4 +-
 include/linux/usb/audio-v3.h   | 395 +
 include/uapi/linux/usb/audio.h |   1 +
 sound/usb/card.c   |   7 +-
 sound/usb/card.h   |   2 +-
 sound/usb/clock.c  | 228 +---
 sound/usb/clock.h  |   4 +-
 sound/usb/format.c |  91 --
 sound/usb/format.h |   6 +-
 sound/usb/mixer.c  | 337 +++
 sound/usb/stream.c | 365 +
 11 files changed, 1246 insertions(+), 194 deletions(-)
 create mode 100644 include/linux/usb/audio-v3.h

diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 3119d0a..2db83a1 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -34,12 +34,12 @@
  *
  */
 
-static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
+static inline bool uac_v2v3_control_is_readable(u32 bmControls, u8 control)
 {
return (bmControls >> (control * 2)) & 0x1;
 }
 
-static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
+static inline bool uac_v2v3_control_is_writeable(u32 bmControls, u8 control)
 {
return (bmControls >> (control * 2)) & 0x2;
 }
diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
new file mode 100644
index 000..a8959aa
--- /dev/null
+++ b/include/linux/usb/audio-v3.h
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2017 Ruslan Bilovol 
+ *
+ * This file holds USB constants and structures defined
+ * by the USB DEVICE CLASS DEFINITION FOR AUDIO DEVICES Release 3.0.
+ */
+
+#ifndef __LINUX_USB_AUDIO_V3_H
+#define __LINUX_USB_AUDIO_V3_H
+
+#include 
+
+/*
+ * v1.0, v2.0 and v3.0 of this standard have many things in common. For the 
rest
+ * of the definitions, please refer to audio.h and audio-v2.h
+ */
+
+/* All High Capability descriptors have these 2 fields at the beginning */
+struct uac3_hc_descriptor_header {
+   __le16 wLength;
+   __u8 bDescriptorType;
+   __u8 bDescriptorSubtype;
+   __le16 wDescriptorID;
+} __attribute__ ((packed));
+
+/* 4.3.1 CLUSTER DESCRIPTOR HEADER */
+struct uac3_cluster_header_descriptor {
+   __le16 wLength;
+   __u8 bDescriptorType;
+   __u8 bDescriptorSubtype;
+   __le16 wDescriptorID;
+   __u8 bNrChannels;
+} __attribute__ ((packed));
+
+/* 4.3.2.1 SEGMENTS */
+struct uac3_cluster_segment_descriptor {
+   __le16 wLength;
+   __u8 bSegmentType;
+   /* __u8[0]; segment-specific data */
+} __attribute__ ((packed));
+
+/* 4.3.2.1.1 END SEGMENT */
+struct uac3_cluster_end_segment_descriptor {
+   __le16 wLength;
+   __u8 bSegmentType;  /* Constant END_SEGMENT */
+} __attribute__ ((packed));
+
+/* 4.3.2.1.3.1 INFORMATION SEGMENT */
+struct uac3_cluster_information_segment_descriptor {
+   __le16 wLength;
+   __u8 bSegmentType;
+   __u8 bChPurpose;
+   __u8 bChRelationship;
+   __u8 bChGroupID;
+} __attribute__ ((packed));
+
+/* 4.5.2 CLASS-SPECIFIC AC INTERFACE DESCRIPTOR */
+struct uac3_ac_header_descriptor {
+   __u8 bLength;   /* 10 */
+   __u8 bDescriptorType;   /* CS_INTERFACE descriptor type */
+   __u8 bDescriptorSubtype;/* HEADER descriptor subtype */
+   __u8 bCategory;
+
+   /* includes Clock Source, Unit, Terminal, and Power Domain desc. */
+   __le16 wTotalLength;
+
+   __le32 bmControls;
+} __attribute__ ((packed));
+
+/* 4.5.2.1 INPUT TERMINAL DESCRIPTOR */
+struct uac3_input_terminal_descriptor {
+   __u8 bLength;
+   __u8 bDescriptorType;
+   __u8 bDescriptorSubtype;
+   __u8 bTerminalID;
+   __le16 wTerminalType;
+   __u8 bAssocTerminal;
+   __u8 bCSourceID;
+   __le32 bmControls;
+   __le16 wClusterDescrID;
+   __le16 wExTerminalDescrID;
+   __le16 wConnectorsDescrID;
+   __le16 wTerminalDescrStr;
+} __attribute__((packed));
+
+/* 4.5.2.2 OUTPUT TERMINAL DESCRIPTOR */
+struct uac3_output_terminal_descriptor {

Re: [PATCH v2 2/2] ALSA: usb: initial USB Audio Device Class 3.0 support

2018-03-19 Thread Ruslan Bilovol
On Mon, Mar 19, 2018 at 6:28 PM, Takashi Iwai <ti...@suse.de> wrote:
> On Mon, 19 Mar 2018 02:46:03 +0100,
> Ruslan Bilovol wrote:
>>
>> Recently released USB Audio Class 3.0 specification
>> introduces many significant changes comparing to
>> previous versions, like
>>  - new Power Domains, support for LPM/L1
>>  - new Cluster descriptor
>>  - changed layout of all class-specific descriptors
>>  - new High Capability descriptors
>>  - New class-specific String descriptors
>>  - new and removed units
>>  - additional sources for interrupts
>>  - removed Type II Audio Data Formats
>>  - ... and many other things (check spec)
>>
>> It also provides backward compatibility through
>> multiple configurations, as well as requires
>> mandatory support for BADD (Basic Audio Device
>> Definition) on each ADC3.0 compliant device
>>
>> This patch adds initial support of UAC3 specification
>> that is enough for Generic I/O Profile (BAOF, BAIF)
>> device support from BADD document.
>>
>> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
>
> Most code changes look fairly straightforward, and not breaking the
> UAC1/UAC2 stuff.  So the stuff is good enough through a quick glance.
>
> I suppose it's better to merge via sound git tree.
> Greg, could you check include/linux/usb/* (and uapi) stuff and give an
> ack if it's OK?
>
> In anyway, I'll check the specs and compare with the definitions in
> this patch.

Please note that I took "A.12 CHANNEL RELATIONSHIP
DEFINITIONS" values from previous Pierre's email (they were
in a draft UAC3 spec but disappeared in the final version).
I've sent an email with my quiestions to audio-ch...@usb.org but
didn't get any reply from them yet.

>
>
> And, just minor nitpicking regarding the code change:
>
> it's better to drop the parentheses in a line like below
>
>> + if ((protocol == UAC_VERSION_1) || (protocol == 
>> UAC_VERSION_2)) {
>
> that is,
> if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
>
> The indentation became so deep in some functions, and it's better to
> refactor, but this can be done later once after all implementations
> are finished.

Sure, I fixed these and also kbuild test robot's complaint; if there
will no any more comments, I'm going to send v3 tomorrow.

Thanks,
Ruslan


Re: [PATCH v2 2/2] ALSA: usb: initial USB Audio Device Class 3.0 support

2018-03-19 Thread Ruslan Bilovol
On Mon, Mar 19, 2018 at 6:28 PM, Takashi Iwai  wrote:
> On Mon, 19 Mar 2018 02:46:03 +0100,
> Ruslan Bilovol wrote:
>>
>> Recently released USB Audio Class 3.0 specification
>> introduces many significant changes comparing to
>> previous versions, like
>>  - new Power Domains, support for LPM/L1
>>  - new Cluster descriptor
>>  - changed layout of all class-specific descriptors
>>  - new High Capability descriptors
>>  - New class-specific String descriptors
>>  - new and removed units
>>  - additional sources for interrupts
>>  - removed Type II Audio Data Formats
>>  - ... and many other things (check spec)
>>
>> It also provides backward compatibility through
>> multiple configurations, as well as requires
>> mandatory support for BADD (Basic Audio Device
>> Definition) on each ADC3.0 compliant device
>>
>> This patch adds initial support of UAC3 specification
>> that is enough for Generic I/O Profile (BAOF, BAIF)
>> device support from BADD document.
>>
>> Signed-off-by: Ruslan Bilovol 
>
> Most code changes look fairly straightforward, and not breaking the
> UAC1/UAC2 stuff.  So the stuff is good enough through a quick glance.
>
> I suppose it's better to merge via sound git tree.
> Greg, could you check include/linux/usb/* (and uapi) stuff and give an
> ack if it's OK?
>
> In anyway, I'll check the specs and compare with the definitions in
> this patch.

Please note that I took "A.12 CHANNEL RELATIONSHIP
DEFINITIONS" values from previous Pierre's email (they were
in a draft UAC3 spec but disappeared in the final version).
I've sent an email with my quiestions to audio-ch...@usb.org but
didn't get any reply from them yet.

>
>
> And, just minor nitpicking regarding the code change:
>
> it's better to drop the parentheses in a line like below
>
>> + if ((protocol == UAC_VERSION_1) || (protocol == 
>> UAC_VERSION_2)) {
>
> that is,
> if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
>
> The indentation became so deep in some functions, and it's better to
> refactor, but this can be done later once after all implementations
> are finished.

Sure, I fixed these and also kbuild test robot's complaint; if there
will no any more comments, I'm going to send v3 tomorrow.

Thanks,
Ruslan


Re: [PATCH v2 1/2] ALSA: usb-audio: move audioformat quirks to quirks.c

2018-03-19 Thread Ruslan Bilovol
On Mon, Mar 19, 2018 at 6:00 PM, Takashi Iwai <ti...@suse.de> wrote:
> On Mon, 19 Mar 2018 02:46:02 +0100,
> Ruslan Bilovol wrote:
>>
>> Offload USB audio interface parsing function by
>> moving quirks to a specially designed location (quirks.c)
>>
>> Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
>
> This one is applied now to for-next branch.
>

Good, I'll drop this one from my series (although don't see it
in the for-next branch yet)

Thanks,
Ruslan


Re: [PATCH v2 1/2] ALSA: usb-audio: move audioformat quirks to quirks.c

2018-03-19 Thread Ruslan Bilovol
On Mon, Mar 19, 2018 at 6:00 PM, Takashi Iwai  wrote:
> On Mon, 19 Mar 2018 02:46:02 +0100,
> Ruslan Bilovol wrote:
>>
>> Offload USB audio interface parsing function by
>> moving quirks to a specially designed location (quirks.c)
>>
>> Signed-off-by: Ruslan Bilovol 
>
> This one is applied now to for-next branch.
>

Good, I'll drop this one from my series (although don't see it
in the for-next branch yet)

Thanks,
Ruslan


Re: [PATCH] ALSA: usb-audio: Fix parsing descriptor of UAC2 processing unit

2018-03-19 Thread Ruslan Bilovol
On Mon, Mar 19, 2018 at 5:45 PM, Takashi Iwai <ti...@suse.de> wrote:
> On Mon, 19 Mar 2018 08:47:49 +0100,
> Takashi Iwai wrote:
>>
>> On Mon, 19 Mar 2018 08:40:19 +0100,
>> Greg Kroah-Hartman wrote:
>> >
>> > On Mon, Mar 19, 2018 at 07:11:08AM +0100, Kirill Marinushkin wrote:
>> > > Currently, the offsets in the UAC2 processing unit descriptor are
>> > > calculated incorrectly. It causes an issue when connecting the device 
>> > > which
>> > > provides such a feature:
>> > >
>> > > 
>> > > [84126.724420] usb 1-1.3.1: invalid Processing Unit descriptor (id 18)
>> > > 
>> > >
>> > > After this patch is applied, the UAC2 processing unit inits w/o this 
>> > > error.
>> > >
>> > > Fixes: 5e1ddb481776 ("UAPI: (Scripted) Disintegrate include/linux/usb")
>> > > Signed-off-by: Kirill Marinushkin <k.marinush...@gmail.com>
>> > > Cc: Mark Brown <broo...@kernel.org>
>> > > Cc: Jaroslav Kysela <pe...@perex.cz>
>> > > Cc: Takashi Iwai <ti...@suse.com>
>> > > Cc: Thomas Gleixner <t...@linutronix.de>
>> > > Cc: Felipe Balbi <felipe.ba...@linux.intel.com>
>> > > Cc: Philippe Ombredanne <pombreda...@nexb.com>
>> > > Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
>> > > Cc: Ruslan Bilovol <ruslan.bilo...@gmail.com>
>> > > Cc: linux-kernel@vger.kernel.org
>> > > Cc: alsa-de...@alsa-project.org
>> > > ---
>> > >  include/uapi/linux/usb/audio.h | 4 ++--
>> > >  1 file changed, 2 insertions(+), 2 deletions(-)
>> >
>> > Cc: stable <sta...@vger.kernel.org>
>> >  perhaps?
>>
>> Yes, it deserves.  But I'd need to double-check the UAC2
>> specification.  It's interesting that such a basic thing hasn't hit
>> until now.  Maybe just because it's a fairly minor feature.
>
> ... and the patch looks correct, after confirming the UAC2 spec.
> Now I applied it, with a minor correction of Fixes tag, which actually
> was introduced by 23caaf19b11e ("ALSA: usb-mixer: Add support for
> Audio Class v2.0"), and adding Cc to stable.
>

I also checked UAC1/UAC2 spec and the patch looks good.
What's interesting it seems nobody faced this issue (after searching
ower Internet can't find any mention) which was present from the
beginning of UAC2 driver implementation.

Thanks,
Ruslan


Re: [PATCH] ALSA: usb-audio: Fix parsing descriptor of UAC2 processing unit

2018-03-19 Thread Ruslan Bilovol
On Mon, Mar 19, 2018 at 5:45 PM, Takashi Iwai  wrote:
> On Mon, 19 Mar 2018 08:47:49 +0100,
> Takashi Iwai wrote:
>>
>> On Mon, 19 Mar 2018 08:40:19 +0100,
>> Greg Kroah-Hartman wrote:
>> >
>> > On Mon, Mar 19, 2018 at 07:11:08AM +0100, Kirill Marinushkin wrote:
>> > > Currently, the offsets in the UAC2 processing unit descriptor are
>> > > calculated incorrectly. It causes an issue when connecting the device 
>> > > which
>> > > provides such a feature:
>> > >
>> > > 
>> > > [84126.724420] usb 1-1.3.1: invalid Processing Unit descriptor (id 18)
>> > > 
>> > >
>> > > After this patch is applied, the UAC2 processing unit inits w/o this 
>> > > error.
>> > >
>> > > Fixes: 5e1ddb481776 ("UAPI: (Scripted) Disintegrate include/linux/usb")
>> > > Signed-off-by: Kirill Marinushkin 
>> > > Cc: Mark Brown 
>> > > Cc: Jaroslav Kysela 
>> > > Cc: Takashi Iwai 
>> > > Cc: Thomas Gleixner 
>> > > Cc: Felipe Balbi 
>> > > Cc: Philippe Ombredanne 
>> > > Cc: Greg Kroah-Hartman 
>> > > Cc: Ruslan Bilovol 
>> > > Cc: linux-kernel@vger.kernel.org
>> > > Cc: alsa-de...@alsa-project.org
>> > > ---
>> > >  include/uapi/linux/usb/audio.h | 4 ++--
>> > >  1 file changed, 2 insertions(+), 2 deletions(-)
>> >
>> > Cc: stable 
>> >  perhaps?
>>
>> Yes, it deserves.  But I'd need to double-check the UAC2
>> specification.  It's interesting that such a basic thing hasn't hit
>> until now.  Maybe just because it's a fairly minor feature.
>
> ... and the patch looks correct, after confirming the UAC2 spec.
> Now I applied it, with a minor correction of Fixes tag, which actually
> was introduced by 23caaf19b11e ("ALSA: usb-mixer: Add support for
> Audio Class v2.0"), and adding Cc to stable.
>

I also checked UAC1/UAC2 spec and the patch looks good.
What's interesting it seems nobody faced this issue (after searching
ower Internet can't find any mention) which was present from the
beginning of UAC2 driver implementation.

Thanks,
Ruslan


[PATCH v2 0/2] USB Audio Device Class 3.0 support

2018-03-18 Thread Ruslan Bilovol
Hi Takashi,

This patch adds initial USB Audio Device Class 3.0 [1]
support to the ALSA that we discussed at ELCE.

The patch was tested with UAC3 gadget [2] that I posted
to USB mailing list before. It is good for working with
BADD device which implements such topologies like
BAIF (Basic Audio Input Functions), BAOF (Basic Audio
Output Functions) or compbination of both.

UAC3 spec has changed descriptors laout and many other
codes comparing to UAC2 spec, thus making reuse of existing
sources impossible or quite complex.

There are still many areas of improvement, as this patch
doesn't have UAC3 Mixer Unit support nor some new features
like Power Management

I tested this with BeagleBone Black as UAC3 gadget device.

[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] http://www.spinics.net/lists/linux-usb/msg162482.html

v2 changes:
 - moved audioformat quirks to quirks.c
 - addressed many comments from Pierre-Louis Bossart
 - reorganized audio-v3.h
 - added more UAC3 channel relationship definitions


Ruslan Bilovol (2):
  ALSA: usb-audio: move audioformat quirks to quirks.c
  ALSA: usb: initial USB Audio Device Class 3.0 support

 include/linux/usb/audio-v2.h   |   4 +-
 include/linux/usb/audio-v3.h   | 395 +
 include/uapi/linux/usb/audio.h |   1 +
 sound/usb/card.c   |   7 +-
 sound/usb/card.h   |   2 +-
 sound/usb/clock.c  | 228 +---
 sound/usb/clock.h  |   4 +-
 sound/usb/format.c |  91 --
 sound/usb/format.h |   6 +-
 sound/usb/mixer.c  | 337 +++
 sound/usb/quirks.c |  34 
 sound/usb/quirks.h |   4 +
 sound/usb/stream.c | 393 +---
 13 files changed, 1284 insertions(+), 222 deletions(-)
 create mode 100644 include/linux/usb/audio-v3.h

-- 
1.9.1



[PATCH v2 0/2] USB Audio Device Class 3.0 support

2018-03-18 Thread Ruslan Bilovol
Hi Takashi,

This patch adds initial USB Audio Device Class 3.0 [1]
support to the ALSA that we discussed at ELCE.

The patch was tested with UAC3 gadget [2] that I posted
to USB mailing list before. It is good for working with
BADD device which implements such topologies like
BAIF (Basic Audio Input Functions), BAOF (Basic Audio
Output Functions) or compbination of both.

UAC3 spec has changed descriptors laout and many other
codes comparing to UAC2 spec, thus making reuse of existing
sources impossible or quite complex.

There are still many areas of improvement, as this patch
doesn't have UAC3 Mixer Unit support nor some new features
like Power Management

I tested this with BeagleBone Black as UAC3 gadget device.

[1] http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
[2] http://www.spinics.net/lists/linux-usb/msg162482.html

v2 changes:
 - moved audioformat quirks to quirks.c
 - addressed many comments from Pierre-Louis Bossart
 - reorganized audio-v3.h
 - added more UAC3 channel relationship definitions


Ruslan Bilovol (2):
  ALSA: usb-audio: move audioformat quirks to quirks.c
  ALSA: usb: initial USB Audio Device Class 3.0 support

 include/linux/usb/audio-v2.h   |   4 +-
 include/linux/usb/audio-v3.h   | 395 +
 include/uapi/linux/usb/audio.h |   1 +
 sound/usb/card.c   |   7 +-
 sound/usb/card.h   |   2 +-
 sound/usb/clock.c  | 228 +---
 sound/usb/clock.h  |   4 +-
 sound/usb/format.c |  91 --
 sound/usb/format.h |   6 +-
 sound/usb/mixer.c  | 337 +++
 sound/usb/quirks.c |  34 
 sound/usb/quirks.h |   4 +
 sound/usb/stream.c | 393 +---
 13 files changed, 1284 insertions(+), 222 deletions(-)
 create mode 100644 include/linux/usb/audio-v3.h

-- 
1.9.1



[PATCH v2 1/2] ALSA: usb-audio: move audioformat quirks to quirks.c

2018-03-18 Thread Ruslan Bilovol
Offload USB audio interface parsing function by
moving quirks to a specially designed location (quirks.c)

Signed-off-by: Ruslan Bilovol <ruslan.bilo...@gmail.com>
---
 sound/usb/quirks.c | 34 ++
 sound/usb/quirks.h |  4 
 sound/usb/stream.c | 30 +-
 3 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index ea8f3de..eeea8e1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1403,3 +1403,37 @@ u64 snd_usb_interface_dsd_format_quirks(struct 
snd_usb_audio *chip,
 
return 0;
 }
+
+void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
+ struct audioformat *fp,
+ int stream)
+{
+   switch (chip->usb_id) {
+   case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
+   /* Optoplay sets the sample rate attribute although
+* it seems not supporting it in fact.
+*/
+   fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
+   break;
+   case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
+   case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+   /* doesn't set the sample rate attribute, but supports it */
+   fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
+   break;
+   case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
+   case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
+   case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
+   case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
+   an older model 77d:223) */
+   /*
+* plantronics headset and Griffin iMic have set adaptive-in
+* although it's really not...
+*/
+   fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
+   if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+   fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
+   else
+   fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
+   break;
+   }
+}
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index b90c8b7..a80e0dd 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -42,4 +42,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio 
*chip,
struct audioformat *fp,
unsigned int sample_bytes);
 
+void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
+ struct audioformat *fp,
+ int stream);
+
 #endif /* __USBAUDIO_QUIRKS_H */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index d1776e5..dbbe854 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -678,35 +678,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio 
*chip, int iface_no)
INIT_LIST_HEAD(>list);
 
/* some quirks for attributes here */
-
-   switch (chip->usb_id) {
-   case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
-   /* Optoplay sets the sample rate attribute although
-* it seems not supporting it in fact.
-*/
-   fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
-   break;
-   case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
-   case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-   /* doesn't set the sample rate attribute, but supports 
it */
-   fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
-   break;
-   case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
-   case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
-   case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
-   case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
-   an older model 77d:223) */
-   /*
-* plantronics headset and Griffin iMic have set adaptive-in
-* although it's really not...
-*/
-   fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
-   if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-   fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
-   else
-   fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
-   break;
-   }
+   snd_usb_audioformat_attributes_quirk(chip, fp, stream);
 
/* ok, let's parse further... */
if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 
0) {
-- 
1.9.1



[PATCH v2 1/2] ALSA: usb-audio: move audioformat quirks to quirks.c

2018-03-18 Thread Ruslan Bilovol
Offload USB audio interface parsing function by
moving quirks to a specially designed location (quirks.c)

Signed-off-by: Ruslan Bilovol 
---
 sound/usb/quirks.c | 34 ++
 sound/usb/quirks.h |  4 
 sound/usb/stream.c | 30 +-
 3 files changed, 39 insertions(+), 29 deletions(-)

diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index ea8f3de..eeea8e1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1403,3 +1403,37 @@ u64 snd_usb_interface_dsd_format_quirks(struct 
snd_usb_audio *chip,
 
return 0;
 }
+
+void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
+ struct audioformat *fp,
+ int stream)
+{
+   switch (chip->usb_id) {
+   case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
+   /* Optoplay sets the sample rate attribute although
+* it seems not supporting it in fact.
+*/
+   fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
+   break;
+   case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
+   case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+   /* doesn't set the sample rate attribute, but supports it */
+   fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
+   break;
+   case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
+   case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
+   case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
+   case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
+   an older model 77d:223) */
+   /*
+* plantronics headset and Griffin iMic have set adaptive-in
+* although it's really not...
+*/
+   fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
+   if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+   fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
+   else
+   fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
+   break;
+   }
+}
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index b90c8b7..a80e0dd 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -42,4 +42,8 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio 
*chip,
struct audioformat *fp,
unsigned int sample_bytes);
 
+void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip,
+ struct audioformat *fp,
+ int stream);
+
 #endif /* __USBAUDIO_QUIRKS_H */
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index d1776e5..dbbe854 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -678,35 +678,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio 
*chip, int iface_no)
INIT_LIST_HEAD(>list);
 
/* some quirks for attributes here */
-
-   switch (chip->usb_id) {
-   case USB_ID(0x0a92, 0x0053): /* AudioTrak Optoplay */
-   /* Optoplay sets the sample rate attribute although
-* it seems not supporting it in fact.
-*/
-   fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE;
-   break;
-   case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */
-   case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-   /* doesn't set the sample rate attribute, but supports 
it */
-   fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE;
-   break;
-   case USB_ID(0x0763, 0x2001):  /* M-Audio Quattro USB */
-   case USB_ID(0x0763, 0x2012):  /* M-Audio Fast Track Pro USB */
-   case USB_ID(0x047f, 0x0ca1): /* plantronics headset */
-   case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is
-   an older model 77d:223) */
-   /*
-* plantronics headset and Griffin iMic have set adaptive-in
-* although it's really not...
-*/
-   fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE;
-   if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-   fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE;
-   else
-   fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC;
-   break;
-   }
+   snd_usb_audioformat_attributes_quirk(chip, fp, stream);
 
/* ok, let's parse further... */
if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 
0) {
-- 
1.9.1



  1   2   3   4   5   >