[alsa-devel] [RFC/PATCH] control_external: Add ability to specify TLV data.
Dylan Reid
dgreid at chromium.org
Mon Apr 16 01:59:12 CEST 2012
On Sun, Apr 15, 2012 at 6:45 AM, Takashi Iwai <tiwai at suse.de> wrote:
> 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 "<=" ?
It certainly should.
>
> Other than that, I like the implementation, looks pretty
> straightforward.
Thanks for taking the time to look at it, fixed version on the way.
-dg
>
>
> 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