[alsa-devel] [RFC/PATCH] control_external: Add ability to specify TLV data.
Takashi Iwai
tiwai at suse.de
Sun Apr 15 15:45:27 CEST 2012
At Sat, 14 Apr 2012 19:36:26 -0700,
Dylan Reid wrote:
>
> Allow external control plugins to provide TLV data. This allows
> user-space pcms to specify dB ranges for controls.
>
> This follows the same model as the ALSA drivers for accessing the
> data. The code is based on that implementation. The control can
> provide static data or a callback. The data is accessed or modified
> in the new snd_ctl_ext_elem_tlv callback.
>
> Rev bump the protocol version to enable checking if an external
> control supports TLV.
>
> Signed-off-by: Dylan Reid <dgreid at chromium.org>
> ---
> include/control_external.h | 17 +++++++++++++++-
> src/control/control_ext.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 62 insertions(+), 1 deletions(-)
>
> diff --git a/include/control_external.h b/include/control_external.h
> index 7c066cf..5392ea6 100644
> --- a/include/control_external.h
> +++ b/include/control_external.h
> @@ -60,13 +60,16 @@ typedef struct snd_ctl_ext snd_ctl_ext_t;
> typedef struct snd_ctl_ext_callback snd_ctl_ext_callback_t;
> /** Key to access a control pointer */
> typedef unsigned long snd_ctl_ext_key_t;
> +/** Callback to handle TLV commands. */
> +typedef int (snd_ctl_ext_tlv_rw_t)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int op_flag, unsigned int numid,
> + unsigned int *tlv, unsigned int tlv_size);
>
> /*
> * Protocol version
> */
> #define SND_CTL_EXT_VERSION_MAJOR 1 /**< Protocol major version */
> #define SND_CTL_EXT_VERSION_MINOR 0 /**< Protocol minor version */
> -#define SND_CTL_EXT_VERSION_TINY 0 /**< Protocol tiny version */
> +#define SND_CTL_EXT_VERSION_TINY 1 /**< Protocol tiny version */
> /**
> * external plugin protocol version
> */
> @@ -122,6 +125,13 @@ struct snd_ctl_ext {
> * control handle filled by #snd_ctl_ext_create()
> */
> snd_ctl_t *handle;
> + /**
> + * optional TLV data for the control.
> + */
> + union {
> + snd_ctl_ext_tlv_rw_t *c;
> + const unsigned int *p;
> + } tlv;
>
> int nonblock; /**< non-block mode; read-only */
> int subscribed; /**< events subscribed; read-only */
> @@ -245,7 +255,12 @@ typedef enum snd_ctl_ext_access {
> SND_CTL_EXT_ACCESS_WRITE = (1<<1),
> SND_CTL_EXT_ACCESS_READWRITE = (3<<0),
> SND_CTL_EXT_ACCESS_VOLATILE = (1<<2),
> + SND_CTL_EXT_ACCESS_TLV_READ = (1<<4),
> + SND_CTL_EXT_ACCESS_TLV_WRITE = (1<<5),
> + SND_CTL_EXT_ACCESS_TLV_READWRITE = (3<<4),
> + SND_CTL_EXT_ACCESS_TLV_COMMAND = (1<<6),
> SND_CTL_EXT_ACCESS_INACTIVE = (1<<8),
> + SND_CTL_EXT_ACCESS_TLV_CALLBACK = (1<<28),
> } snd_ctl_ext_access_t;
>
> /**
> diff --git a/src/control/control_ext.c b/src/control/control_ext.c
> index e20d4f3..0a0b397 100644
> --- a/src/control/control_ext.c
> +++ b/src/control/control_ext.c
> @@ -324,6 +324,51 @@ static int snd_ctl_ext_elem_unlock(snd_ctl_t *handle ATTRIBUTE_UNUSED,
> return -ENXIO;
> }
>
> +static int snd_ctl_ext_elem_tlv(snd_ctl_t *handle, int op_flag,
> + unsigned int numid,
> + unsigned int *tlv, unsigned int tlv_size)
> +{
> + snd_ctl_ext_t *ext = handle->private_data;
> + snd_ctl_ext_key_t key;
> + int type, ret;
> + unsigned int access, count, len;
> + snd_ctl_elem_id_t id;
> +
> + /* we don't support TLV on protocol ver 1.0.0 or earlier */
> + if (ext->version < SNDRV_PROTOCOL_VERSION(1, 0, 0))
> + return -ENXIO;
Shouldn't this be "<=" ?
Other than that, I like the implementation, looks pretty
straightforward.
thanks,
Takashi
> +
> + snd_ctl_elem_id_clear(&id);
> + if (numid > 0) {
> + ext->callback->elem_list(ext, numid - 1, &id);
> + id.numid = numid;
> + } else
> + id.numid = 0;
> + key = ext->callback->find_elem(ext, &id);
> +
> + if (key == SND_CTL_EXT_KEY_NOT_FOUND)
> + return -ENOENT;
> + ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
> + if (ret < 0)
> + return ret;
> +
> + if ((op_flag == 0 && (access & SND_CTL_EXT_ACCESS_TLV_READ) == 0) ||
> + (op_flag > 0 && (access & SND_CTL_EXT_ACCESS_TLV_WRITE) == 0) ||
> + (op_flag < 0 && (access & SND_CTL_EXT_ACCESS_TLV_COMMAND) == 0))
> + return -ENXIO;
> + if (access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
> + return ext->tlv.c(ext, key, op_flag, numid, tlv, tlv_size);
> + } else {
> + if (op_flag)
> + return -ENXIO;
> + len = ext->tlv.p[1] + 2 * sizeof(unsigned int);
> + if (tlv_size < len)
> + return -ENOMEM;
> + memcpy(tlv, ext->tlv.p, len);
> + return 0;
> + }
> +}
> +
> static int snd_ctl_ext_next_device(snd_ctl_t *handle ATTRIBUTE_UNUSED,
> int *device ATTRIBUTE_UNUSED)
> {
> @@ -429,6 +474,7 @@ static const snd_ctl_ops_t snd_ctl_ext_ops = {
> .element_write = snd_ctl_ext_elem_write,
> .element_lock = snd_ctl_ext_elem_lock,
> .element_unlock = snd_ctl_ext_elem_unlock,
> + .element_tlv = snd_ctl_ext_elem_tlv,
> .hwdep_next_device = snd_ctl_ext_next_device,
> .hwdep_info = snd_ctl_ext_hwdep_info,
> .pcm_next_device = snd_ctl_ext_next_device,
> --
> 1.7.9.rc0
>
More information about the Alsa-devel
mailing list