diff mbox

[1/4] ALSA: control: return payload length for TLV operation

Message ID a21ab28c-12d5-41c2-9209-4127fe3ca79a@sakamocchi.jp (mailing list archive)
State New, archived
Headers show

Commit Message

Takashi Sakamoto Sept. 2, 2016, 11:18 a.m. UTC
Clemens,

On Aug 31 2016 20:54, Clemens Ladisch wrote:
> Takashi Iwai wrote:
>> TLV has never been and (will never be) an API to handle a
>> generic binary stream.
> 
> It would be possible to define something like SNDRV_CTL_TLVT_HWDEP_BLOB
> or _COEFFICIENTS, or to reserve a range of TLVT values for driver-
> defined types.  (But we cannot change soc-wm-adsp to support only proper
> TLV data, because this would introduce a regression.)

For our information, I wrote a patch including your idea.


Thanks for your bright comment ;)

Takashi Sakamoto

---- 8< ----

From d1a0eabf1b33fae5de7cedf7aee23778f5dcf46c Mon Sep 17 00:00:00 2001
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Date: Fri, 2 Sep 2016 00:12:20 +0900
Subject: [PATCH] ALSA: control: coefficient support

---
 include/uapi/sound/asound.h |  5 +++++
 include/uapi/sound/tlv.h    |  1 +
 sound/soc/codecs/wm_adsp.c  |  3 ++-
 sound/soc/soc-ops.c         | 37 ++++++++++++++++++++++++++++++++++---
 sound/soc/soc-topology.c    |  3 ++-
 5 files changed, 44 insertions(+), 5 deletions(-)

Comments

Takashi Iwai Sept. 2, 2016, 4:05 p.m. UTC | #1
On Fri, 02 Sep 2016 13:18:04 +0200,
Takashi Sakamoto wrote:
> 
> Clemens,
> 
> On Aug 31 2016 20:54, Clemens Ladisch wrote:
> > Takashi Iwai wrote:
> >> TLV has never been and (will never be) an API to handle a
> >> generic binary stream.
> > 
> > It would be possible to define something like SNDRV_CTL_TLVT_HWDEP_BLOB
> > or _COEFFICIENTS, or to reserve a range of TLVT values for driver-
> > defined types.  (But we cannot change soc-wm-adsp to support only proper
> > TLV data, because this would introduce a regression.)
> 
> For our information, I wrote a patch including your idea.
> 
> 
> Thanks for your bright comment ;)
> 
> Takashi Sakamoto
> 
> ---- 8< ----
> 
> >From d1a0eabf1b33fae5de7cedf7aee23778f5dcf46c Mon Sep 17 00:00:00 2001
> From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> Date: Fri, 2 Sep 2016 00:12:20 +0900
> Subject: [PATCH] ALSA: control: coefficient support
> 
> ---
>  include/uapi/sound/asound.h |  5 +++++
>  include/uapi/sound/tlv.h    |  1 +
>  sound/soc/codecs/wm_adsp.c  |  3 ++-
>  sound/soc/soc-ops.c         | 37 ++++++++++++++++++++++++++++++++++---
>  sound/soc/soc-topology.c    |  3 ++-
>  5 files changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
> index 609cadb..69c0585 100644
> --- a/include/uapi/sound/asound.h
> +++ b/include/uapi/sound/asound.h
> @@ -848,6 +848,11 @@ typedef int __bitwise snd_ctl_elem_iface_t;
>  #define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE		(1<<5)	/* TLV write is possible */
>  #define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
> (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
>  #define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND	(1<<6)	/* TLV command is
> possible */
> +/*
> + * Arbitrary data is accepted for coefficients, instead of pure
> threshold level
> + * information.
> + */
> +#define SNDRV_CTL_ELEM_ACCESS_TLV_COEFF		(1<<7)
>  #define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually
> nothing, but may be updated */
>  #define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
>  #define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */

The introduction of a new flag is a good idea (although it's better to
be named not specifically to coef).  Then we can skip such elements to
be accessed from alsactl or amixer.

However...

> @@ -773,19 +774,49 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol
> *kcontrol, int op_flag,
>  				unsigned int size, unsigned int __user *tlv)
>  {
>  	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
> -	unsigned int count = size < params->max ? size : params->max;
> +	unsigned int count;
> +	unsigned int type;
>  	int ret = -ENXIO;
> 
> +	/*
> +	 * The TLV packet can transfer numerical ID for one control element.
> +	 * But ALSA control core don't tell it to each implementation of
> +	 * TLV callback. Here, instead, use the first volatile data to
> +	 * check access information.
> +	 */
> +	if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_COEFF))
> +		return -ENXIO;
> +
> +	/* The data should be constructed according to TLV protocol. */
> +	if (copy_from_user(&type, tlv, sizeof(unsigned int)))
> +		return -EFAULT;
> +
> +	/* The type should be an arbitrary data. */
> +	if (type != SNDRV_CTL_TLVT_COEFF)
> +		return -ENXIO;

This breaks the already existing application and is a regression, as
Clemens mentioned.  This should have been forced from the beginning,
but it's too late to put now.  So, it's likely no-go.

But, the addition of the flag is helpful alone.  Could you concentrate
on that and resubmit?


thanks,

Takashi
Takashi Sakamoto Sept. 3, 2016, 3:53 a.m. UTC | #2
On Sep 3 2016 01:05, Takashi Iwai wrote:
> But, the addition of the flag is helpful alone.  Could you concentrate
> on that and resubmit?

Before starting it, I'd like to wait for comments from Clemens Ladisch,
Charles Keepax and Vinod Koul, in a view of application interfaces
stable, safe and tolerant for long term usage. I'm unwilling to use my
time more for light-minded work done to bring confusions to hardware-
abstraction layers for user land applications.

But, if possible, I'd request you to re-think about my proposal to
return processed byte of TLV packet payload to user land, again. It
looks to be intrusive, but in my taste, it doesn't bring much impacts to
applications, than adding new flags to kernel/userspace interfaces.

The length of processed bytes from drivers in ALSA SoC part might help
developers to get current value of 'struct soc_bytes_ext.max' of each
control element set. As of kernel 4.8, soc-da7218/nau8825/wm5102 modules
implements the coefficients, and it's already in ALSA topology design. I
believe it better to assist developers for the feature, than judging
it's coarse and abuse for good APIs.


Regards

Takashi Sakamoto
Charles Keepax Sept. 3, 2016, 11:32 a.m. UTC | #3
On Fri, Sep 02, 2016 at 08:18:04PM +0900, Takashi Sakamoto wrote:
> Clemens,
> 
> On Aug 31 2016 20:54, Clemens Ladisch wrote:
> > Takashi Iwai wrote:
> >> TLV has never been and (will never be) an API to handle a
> >> generic binary stream.
> > 
> > It would be possible to define something like SNDRV_CTL_TLVT_HWDEP_BLOB
> > or _COEFFICIENTS, or to reserve a range of TLVT values for driver-
> > defined types.  (But we cannot change soc-wm-adsp to support only proper
> > TLV data, because this would introduce a regression.)
> 
> For our information, I wrote a patch including your idea.
> 
> 
> Thanks for your bright comment ;)
> 
> Takashi Sakamoto
> 
> ---- 8< ----
> 
> >From d1a0eabf1b33fae5de7cedf7aee23778f5dcf46c Mon Sep 17 00:00:00 2001
> From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> Date: Fri, 2 Sep 2016 00:12:20 +0900
> Subject: [PATCH] ALSA: control: coefficient support
> 
> ---
>  include/uapi/sound/asound.h |  5 +++++
>  include/uapi/sound/tlv.h    |  1 +
>  sound/soc/codecs/wm_adsp.c  |  3 ++-
>  sound/soc/soc-ops.c         | 37 ++++++++++++++++++++++++++++++++++---
>  sound/soc/soc-topology.c    |  3 ++-
>  5 files changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
> index 609cadb..69c0585 100644
> --- a/include/uapi/sound/asound.h
> +++ b/include/uapi/sound/asound.h
> @@ -848,6 +848,11 @@ typedef int __bitwise snd_ctl_elem_iface_t;
>  #define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE		(1<<5)	/* TLV write is possible */
>  #define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
> (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
>  #define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND	(1<<6)	/* TLV command is
> possible */
> +/*
> + * Arbitrary data is accepted for coefficients, instead of pure
> threshold level
> + * information.
> + */
> +#define SNDRV_CTL_ELEM_ACCESS_TLV_COEFF		(1<<7)

Yeah the addition of a new flag here would very much get my vote.
The only way at the moment to tell if you are dealing with this
type of control from user-space is to look for
a control of type SNDRV_CTL_ELEM_TYPE_BYTES that doesn't have
SNDRV_CTL_ELEM_ACCESS_READ or SNDRV_CTL_ELEM_ACCESS_WRITE. Which
is far from ideal.

>  #define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually
> nothing, but may be updated */
>  #define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
>  #define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */
> diff --git a/include/uapi/sound/tlv.h b/include/uapi/sound/tlv.h
> index ffc4f20..fd1c867 100644
> --- a/include/uapi/sound/tlv.h
> +++ b/include/uapi/sound/tlv.h
> @@ -19,6 +19,7 @@
>  #define SNDRV_CTL_TLVT_DB_RANGE 3	/* dB range container */
>  #define SNDRV_CTL_TLVT_DB_MINMAX 4	/* dB scale with min/max */
>  #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5	/* dB scale with min/max with
> mute */
> +#define SNDRV_CTL_TLVT_COEFF	6	/* Arbitrary data */
> 
>  /*
>   * channel-mapping TLV items
> diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
> index 21fbe7d..525d70b 100644
> --- a/sound/soc/codecs/wm_adsp.c
> +++ b/sound/soc/codecs/wm_adsp.c
> @@ -930,7 +930,8 @@ static unsigned int wmfw_convert_flags(unsigned int
> in, unsigned int len)
>  		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
>  		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;
> 
> -		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
> +		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK |
> +		      SNDRV_CTL_ELEM_ACCESS_TLV_COEFF;
>  	} else {
>  		rd = SNDRV_CTL_ELEM_ACCESS_READ;
>  		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
> diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
> index a513a34..14cdd59 100644
> --- a/sound/soc/soc-ops.c
> +++ b/sound/soc/soc-ops.c
> @@ -31,6 +31,7 @@
>  #include <sound/soc.h>
>  #include <sound/soc-dpcm.h>
>  #include <sound/initval.h>
> +#include <sound/tlv.h>
> 
>  /**
>   * snd_soc_info_enum_double - enumerated double mixer info callback
> @@ -773,19 +774,49 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol
> *kcontrol, int op_flag,
>  				unsigned int size, unsigned int __user *tlv)
>  {
>  	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
> -	unsigned int count = size < params->max ? size : params->max;
> +	unsigned int count;
> +	unsigned int type;
>  	int ret = -ENXIO;
> 
> +	/*
> +	 * The TLV packet can transfer numerical ID for one control element.
> +	 * But ALSA control core don't tell it to each implementation of
> +	 * TLV callback. Here, instead, use the first volatile data to
> +	 * check access information.
> +	 */
> +	if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_COEFF))
> +		return -ENXIO;
> +
> +	/* The data should be constructed according to TLV protocol. */
> +	if (copy_from_user(&type, tlv, sizeof(unsigned int)))
> +		return -EFAULT;
> +
> +	/* The type should be an arbitrary data. */
> +	if (type != SNDRV_CTL_TLVT_COEFF)
> +		return -ENXIO;
> +

I agree it is probably a bit late to add this now.

Thanks,
Charles
diff mbox

Patch

diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 609cadb..69c0585 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -848,6 +848,11 @@  typedef int __bitwise snd_ctl_elem_iface_t;
 #define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE		(1<<5)	/* TLV write is possible */
 #define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
(SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
 #define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND	(1<<6)	/* TLV command is
possible */
+/*
+ * Arbitrary data is accepted for coefficients, instead of pure
threshold level
+ * information.
+ */
+#define SNDRV_CTL_ELEM_ACCESS_TLV_COEFF		(1<<7)
 #define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually
nothing, but may be updated */
 #define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
 #define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */
diff --git a/include/uapi/sound/tlv.h b/include/uapi/sound/tlv.h
index ffc4f20..fd1c867 100644
--- a/include/uapi/sound/tlv.h
+++ b/include/uapi/sound/tlv.h
@@ -19,6 +19,7 @@ 
 #define SNDRV_CTL_TLVT_DB_RANGE 3	/* dB range container */
 #define SNDRV_CTL_TLVT_DB_MINMAX 4	/* dB scale with min/max */
 #define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5	/* dB scale with min/max with
mute */
+#define SNDRV_CTL_TLVT_COEFF	6	/* Arbitrary data */

 /*
  * channel-mapping TLV items
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 21fbe7d..525d70b 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -930,7 +930,8 @@  static unsigned int wmfw_convert_flags(unsigned int
in, unsigned int len)
 		wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE;
 		vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE;

-		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+		out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK |
+		      SNDRV_CTL_ELEM_ACCESS_TLV_COEFF;
 	} else {
 		rd = SNDRV_CTL_ELEM_ACCESS_READ;
 		wr = SNDRV_CTL_ELEM_ACCESS_WRITE;
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index a513a34..14cdd59 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -31,6 +31,7 @@ 
 #include <sound/soc.h>
 #include <sound/soc-dpcm.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>

 /**
  * snd_soc_info_enum_double - enumerated double mixer info callback
@@ -773,19 +774,49 @@  int snd_soc_bytes_tlv_callback(struct snd_kcontrol
*kcontrol, int op_flag,
 				unsigned int size, unsigned int __user *tlv)
 {
 	struct soc_bytes_ext *params = (void *)kcontrol->private_value;
-	unsigned int count = size < params->max ? size : params->max;
+	unsigned int count;
+	unsigned int type;
 	int ret = -ENXIO;

+	/*
+	 * The TLV packet can transfer numerical ID for one control element.
+	 * But ALSA control core don't tell it to each implementation of
+	 * TLV callback. Here, instead, use the first volatile data to
+	 * check access information.
+	 */
+	if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_COEFF))
+		return -ENXIO;
+
+	/* The data should be constructed according to TLV protocol. */
+	if (copy_from_user(&type, tlv, sizeof(unsigned int)))
+		return -EFAULT;
+
+	/* The type should be an arbitrary data. */
+	if (type != SNDRV_CTL_TLVT_COEFF)
+		return -ENXIO;
+
+	/*
+	 * The second element of TLV packet payload means the length of an
+	 * actual data. But this implementation is going to trim it.
+	 */
+	count = min_t(unsigned int, tlv[1] - sizeof(unsigned int), params->max);
+
 	switch (op_flag) {
 	case SNDRV_CTL_TLV_OP_READ:
 		if (params->get)
-			ret = params->get(kcontrol, tlv, count);
+			ret = params->get(kcontrol, tlv + 2, count);
 		break;
 	case SNDRV_CTL_TLV_OP_WRITE:
 		if (params->put)
-			ret = params->put(kcontrol, tlv, count);
+			ret = params->put(kcontrol, tlv + 2, count);
 		break;
 	}
+
+	if (ret >= 0) {
+		if (copy_to_user(tlv + 1, &count, sizeof(unsigned int)))
+			return -EFAULT;
+	}
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback);
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index ee7f15a..a8f6060 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -507,7 +507,8 @@  static int soc_tplg_kcontrol_bind_io(struct
snd_soc_tplg_ctl_hdr *hdr,
 	if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES
 		&& k->iface & SNDRV_CTL_ELEM_IFACE_MIXER
 		&& k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
-		&& k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+		&& k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK
+		&& k->access & SNDRV_CTL_ELEM_ACCESS_TLV_COEFF) {
 		struct soc_bytes_ext *sbe;
 		struct snd_soc_tplg_bytes_control *be;