mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Control API - add TLV support
snd_ctl_elem_tlv_read snd_ctl_elem_tlv_write snd_ctl_elem_tlv_command snd_ctl_elem_info_is_tlv_readable snd_ctl_elem_info_is_tlv_writable snd_ctl_elem_info_is_tlv_commandable snd_hctl_elem_tlv_read snd_hctl_elem_tlv_write snd_hctl_elem_tlv_command
This commit is contained in:
parent
408697bfe2
commit
c7a0708a23
7 changed files with 248 additions and 4 deletions
|
|
@ -122,6 +122,8 @@ typedef enum _snd_ctl_event_type {
|
|||
#define SND_CTL_EVENT_MASK_INFO (1<<1)
|
||||
/** Element has been added \hideinitializer */
|
||||
#define SND_CTL_EVENT_MASK_ADD (1<<2)
|
||||
/** Element's TLV value has been changed \hideinitializer */
|
||||
#define SND_CTL_EVENT_MASK_TLV (1<<3)
|
||||
|
||||
/** CTL name helper */
|
||||
#define SND_CTL_NAME_NONE ""
|
||||
|
|
@ -164,6 +166,11 @@ typedef enum _snd_ctl_event_type {
|
|||
/** ACPI/PCI Power State D3cold */
|
||||
#define SND_CTL_POWER_D3cold (SND_CTL_POWER_D3|0x0001)
|
||||
|
||||
/** TLV type - Container */
|
||||
#define SND_CTL_TLVT_CONTAINER 0x0000
|
||||
/** TLV type - basic dB scale */
|
||||
#define SND_CTL_TLVT_DB_SCALE 0x0001
|
||||
|
||||
/** CTL type */
|
||||
typedef enum _snd_ctl_type {
|
||||
/** Kernel level CTL */
|
||||
|
|
@ -212,12 +219,18 @@ int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int s
|
|||
int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
|
||||
int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe);
|
||||
int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info);
|
||||
int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t * list);
|
||||
int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list);
|
||||
int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info);
|
||||
int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *value);
|
||||
int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *value);
|
||||
int snd_ctl_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id);
|
||||
int snd_ctl_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id);
|
||||
int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
|
||||
unsigned int *tlv, unsigned int tlv_size);
|
||||
int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
|
||||
const unsigned int *tlv);
|
||||
int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
|
||||
const unsigned int *tlv);
|
||||
int snd_ctl_hwdep_next_device(snd_ctl_t *ctl, int * device);
|
||||
int snd_ctl_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info);
|
||||
int snd_ctl_pcm_next_device(snd_ctl_t *ctl, int *device);
|
||||
|
|
@ -340,6 +353,9 @@ int snd_ctl_elem_info_is_writable(const snd_ctl_elem_info_t *obj);
|
|||
int snd_ctl_elem_info_is_volatile(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_inactive(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_locked(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_tlv_readable(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_tlv_writable(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_tlv_commandable(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_owner(const snd_ctl_elem_info_t *obj);
|
||||
int snd_ctl_elem_info_is_user(const snd_ctl_elem_info_t *obj);
|
||||
pid_t snd_ctl_elem_info_get_owner(const snd_ctl_elem_info_t *obj);
|
||||
|
|
@ -485,6 +501,9 @@ snd_hctl_elem_t *snd_hctl_elem_prev(snd_hctl_elem_t *elem);
|
|||
int snd_hctl_elem_info(snd_hctl_elem_t *elem, snd_ctl_elem_info_t * info);
|
||||
int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
|
||||
int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
|
||||
int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size);
|
||||
int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv);
|
||||
int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv);
|
||||
|
||||
snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem);
|
||||
|
||||
|
|
|
|||
|
|
@ -756,10 +756,15 @@ enum sndrv_ctl_elem_iface {
|
|||
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
|
||||
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
|
||||
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) /* control value may be changed without a notification */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<2) /* when was control changed */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) /* when was control changed */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) /* TLV read is supported */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) /* TLV write is supported */
|
||||
#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 */
|
||||
#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 */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) /* flag only for kernel */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */
|
||||
#define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */
|
||||
|
|
@ -847,6 +852,12 @@ struct sndrv_ctl_elem_value {
|
|||
unsigned char reserved[128-sizeof(struct timespec)];
|
||||
};
|
||||
|
||||
struct sndrv_ctl_tlv {
|
||||
unsigned int numid; /* control element numeric identification */
|
||||
unsigned int length; /* in bytes aligned to 4 */
|
||||
unsigned int tlv[0]; /* first TLV */
|
||||
};
|
||||
|
||||
enum {
|
||||
SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
|
||||
SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct sndrv_ctl_card_info),
|
||||
|
|
@ -860,6 +871,9 @@ enum {
|
|||
SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct sndrv_ctl_elem_info),
|
||||
SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct sndrv_ctl_elem_info),
|
||||
SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct sndrv_ctl_elem_id),
|
||||
SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct sndrv_ctl_tlv),
|
||||
SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct sndrv_ctl_tlv),
|
||||
SNDRV_CTL_IOCTL_TLV_COMMAND = _IOWR('U', 0x1c, struct sndrv_ctl_tlv),
|
||||
SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
|
||||
SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct sndrv_hwdep_info),
|
||||
SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
|
||||
|
|
|
|||
14
src/Versions
14
src/Versions
|
|
@ -274,3 +274,17 @@ ALSA_1.0.11 {
|
|||
snd_pcm_set_params;
|
||||
snd_pcm_get_params;
|
||||
} ALSA_1.0.10;
|
||||
|
||||
ALSA_1.0.12 {
|
||||
global:
|
||||
|
||||
snd_ctl_elem_tlv_read;
|
||||
snd_ctl_elem_tlv_write;
|
||||
snd_ctl_elem_tlv_command;
|
||||
snd_ctl_elem_info_is_tlv_readable;
|
||||
snd_ctl_elem_info_is_tlv_writable;
|
||||
snd_ctl_elem_info_is_tlv_commandable;
|
||||
snd_hctl_elem_tlv_read;
|
||||
snd_hctl_elem_tlv_write;
|
||||
snd_hctl_elem_tlv_command;
|
||||
} ALSA_1.0.11;
|
||||
|
|
|
|||
|
|
@ -404,7 +404,9 @@ int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
|
|||
* \brief Set CTL element value
|
||||
* \param ctl CTL handle
|
||||
* \param control CTL element id/value pointer
|
||||
* \return 0 on success otherwise a negative error code
|
||||
* \retval 0 on success
|
||||
* \retval >0 on success when value was changed
|
||||
* \retval <0 a negative error code
|
||||
*/
|
||||
int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
|
||||
{
|
||||
|
|
@ -412,6 +414,83 @@ int snd_ctl_elem_write(snd_ctl_t *ctl, snd_ctl_elem_value_t *control)
|
|||
return ctl->ops->element_write(ctl, control);
|
||||
}
|
||||
|
||||
static int snd_ctl_tlv_do(snd_ctl_t *ctl, int op_flag,
|
||||
const snd_ctl_elem_id_t *id,
|
||||
unsigned int *tlv, unsigned int tlv_size)
|
||||
{
|
||||
snd_ctl_elem_info_t *info = NULL;
|
||||
int err;
|
||||
|
||||
if (id->numid == 0) {
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (info == NULL)
|
||||
return -ENOMEM;
|
||||
info->id = *id;
|
||||
id = &info->id;
|
||||
err = snd_ctl_elem_info(ctl, info);
|
||||
if (err < 0)
|
||||
goto __err;
|
||||
if (id->numid == 0) {
|
||||
err = -ENOENT;
|
||||
goto __err;
|
||||
}
|
||||
}
|
||||
err = ctl->ops->element_tlv(ctl, op_flag, id->numid, tlv, tlv_size);
|
||||
__err:
|
||||
if (info)
|
||||
free(info);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get CTL element TLV value
|
||||
* \param ctl CTL handle
|
||||
* \param id CTL element id pointer
|
||||
* \param tlv TLV array pointer to store
|
||||
* \param tlv_size TLV array size in bytes
|
||||
* \return 0 on success otherwise a negative error code
|
||||
*/
|
||||
int snd_ctl_elem_tlv_read(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
|
||||
unsigned int *tlv, unsigned int tlv_size)
|
||||
{
|
||||
assert(ctl && id && (id->name[0] || id->numid) && tlv);
|
||||
return snd_ctl_tlv_do(ctl, 0, id, tlv, tlv_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set CTL element TLV value
|
||||
* \param ctl CTL handle
|
||||
* \param id CTL element id pointer
|
||||
* \param tlv TLV array pointer to store
|
||||
* \retval 0 on success
|
||||
* \retval >0 on success when value was changed
|
||||
* \retval <0 a negative error code
|
||||
*/
|
||||
int snd_ctl_elem_tlv_write(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
|
||||
const unsigned int *tlv)
|
||||
{
|
||||
assert(ctl && id && (id->name[0] || id->numid) && tlv);
|
||||
return snd_ctl_tlv_do(ctl, 1, id, (unsigned int *)tlv, tlv[1] + 2 * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Process CTL element TLV command
|
||||
* \param ctl CTL handle
|
||||
* \param id CTL element id pointer
|
||||
* \param tlv TLV array pointer to process
|
||||
* \retval 0 on success
|
||||
* \retval >0 on success when value was changed
|
||||
* \retval <0 a negative error code
|
||||
*/
|
||||
int snd_ctl_elem_tlv_command(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id,
|
||||
const unsigned int *tlv)
|
||||
{
|
||||
assert(ctl && id && (id->name[0] || id->numid) && tlv);
|
||||
return snd_ctl_tlv_do(ctl, -1, id, (unsigned int *)tlv, tlv[1] + 2 * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Lock CTL element
|
||||
* \param ctl CTL handle
|
||||
|
|
@ -1741,6 +1820,39 @@ int snd_ctl_elem_info_is_user(const snd_ctl_elem_info_t *obj)
|
|||
return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_USER);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get info about TLV readability from a CTL element id/info
|
||||
* \param obj CTL element id/info
|
||||
* \return 0 if element's TLV is not readable, 1 if element's TLV is readable
|
||||
*/
|
||||
int snd_ctl_elem_info_is_tlv_readable(const snd_ctl_elem_info_t *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get info about TLV writeability from a CTL element id/info
|
||||
* \param obj CTL element id/info
|
||||
* \return 0 if element's TLV is not writable, 1 if element's TLV is writable
|
||||
*/
|
||||
int snd_ctl_elem_info_is_tlv_writable(const snd_ctl_elem_info_t *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get info about TLV command possibility from a CTL element id/info
|
||||
* \param obj CTL element id/info
|
||||
* \return 0 if element's TLV command is not possible, 1 if element's TLV command is supported
|
||||
*/
|
||||
int snd_ctl_elem_info_is_tlv_commandable(const snd_ctl_elem_info_t *obj)
|
||||
{
|
||||
assert(obj);
|
||||
return !!(obj->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief (DEPRECATED) Get info about values passing policy from a CTL element value
|
||||
* \param obj CTL element id/info
|
||||
|
|
|
|||
|
|
@ -200,6 +200,39 @@ static int snd_ctl_hw_elem_unlock(snd_ctl_t *handle, snd_ctl_elem_id_t *id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_hw_elem_tlv(snd_ctl_t *handle, int op_flag,
|
||||
unsigned int numid,
|
||||
unsigned int *tlv, unsigned int tlv_size)
|
||||
{
|
||||
int inum;
|
||||
snd_ctl_hw_t *hw = handle->private_data;
|
||||
struct sndrv_ctl_tlv *xtlv;
|
||||
|
||||
switch (op_flag) {
|
||||
case -1: inum = SNDRV_CTL_IOCTL_TLV_COMMAND; break;
|
||||
case 0: inum = SNDRV_CTL_IOCTL_TLV_READ; break;
|
||||
case 1: inum = SNDRV_CTL_IOCTL_TLV_WRITE; break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
xtlv = malloc(sizeof(struct sndrv_ctl_tlv) + tlv_size);
|
||||
if (xtlv == NULL)
|
||||
return -ENOMEM;
|
||||
xtlv->numid = numid;
|
||||
xtlv->length = tlv_size;
|
||||
memcpy(xtlv->tlv, tlv, tlv_size);
|
||||
if (ioctl(hw->fd, inum, xtlv) < 0) {
|
||||
free(xtlv);
|
||||
return -errno;
|
||||
}
|
||||
if (op_flag == 0) {
|
||||
if (xtlv->tlv[1] + 2 * sizeof(unsigned int) > tlv_size)
|
||||
return -EFAULT;
|
||||
memcpy(tlv, xtlv->tlv, xtlv->tlv[1] + 2 * sizeof(unsigned int));
|
||||
}
|
||||
free(xtlv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_ctl_hw_hwdep_next_device(snd_ctl_t *handle, int * device)
|
||||
{
|
||||
snd_ctl_hw_t *hw = handle->private_data;
|
||||
|
|
@ -305,6 +338,7 @@ snd_ctl_ops_t snd_ctl_hw_ops = {
|
|||
.element_write = snd_ctl_hw_elem_write,
|
||||
.element_lock = snd_ctl_hw_elem_lock,
|
||||
.element_unlock = snd_ctl_hw_elem_unlock,
|
||||
.element_tlv = snd_ctl_hw_elem_tlv,
|
||||
.hwdep_next_device = snd_ctl_hw_hwdep_next_device,
|
||||
.hwdep_info = snd_ctl_hw_hwdep_info,
|
||||
.pcm_next_device = snd_ctl_hw_pcm_next_device,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ typedef struct _snd_ctl_ops {
|
|||
int (*element_write)(snd_ctl_t *handle, snd_ctl_elem_value_t *control);
|
||||
int (*element_lock)(snd_ctl_t *handle, snd_ctl_elem_id_t *lock);
|
||||
int (*element_unlock)(snd_ctl_t *handle, snd_ctl_elem_id_t *unlock);
|
||||
int (*element_tlv)(snd_ctl_t *handle, int op_flag, unsigned int numid,
|
||||
unsigned int *tlv, unsigned int tlv_size);
|
||||
int (*hwdep_next_device)(snd_ctl_t *handle, int *device);
|
||||
int (*hwdep_info)(snd_ctl_t *handle, snd_hwdep_info_t * info);
|
||||
int (*pcm_next_device)(snd_ctl_t *handle, int *device);
|
||||
|
|
|
|||
|
|
@ -821,7 +821,9 @@ int snd_hctl_elem_read(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
|
|||
* \brief Set value for an HCTL element
|
||||
* \param elem HCTL element
|
||||
* \param value HCTL element value
|
||||
* \return 0 otherwise a negative error code on failure
|
||||
* \retval 0 on success
|
||||
* \ratval >1 on success when value was changed
|
||||
* \retval <0 a negative error code on failure
|
||||
*/
|
||||
int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
|
||||
{
|
||||
|
|
@ -832,6 +834,53 @@ int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value)
|
|||
return snd_ctl_elem_write(elem->hctl->ctl, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get TLV value for an HCTL element
|
||||
* \param elem HCTL element
|
||||
* \param tlv TLV array for value
|
||||
* \param tlv_size size of TLV array in bytes
|
||||
* \return 0 otherwise a negative error code on failure
|
||||
*/
|
||||
int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size)
|
||||
{
|
||||
assert(elem);
|
||||
assert(tlv);
|
||||
assert(tlv_size >= 12);
|
||||
return snd_ctl_elem_tlv_read(elem->hctl->ctl, &elem->id, tlv, tlv_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set TLV value for an HCTL element
|
||||
* \param elem HCTL element
|
||||
* \param tlv TLV array for value
|
||||
* \retval 0 on success
|
||||
* \ratval >1 on success when value was changed
|
||||
* \retval <0 a negative error code on failure
|
||||
*/
|
||||
int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv)
|
||||
{
|
||||
assert(elem);
|
||||
assert(tlv);
|
||||
assert(tlv[1] >= 4);
|
||||
return snd_ctl_elem_tlv_write(elem->hctl->ctl, &elem->id, tlv);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set TLV value for an HCTL element
|
||||
* \param elem HCTL element
|
||||
* \param tlv TLV array for value
|
||||
* \retval 0 on success
|
||||
* \ratval >1 on success when value was changed
|
||||
* \retval <0 a negative error code on failure
|
||||
*/
|
||||
int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv)
|
||||
{
|
||||
assert(elem);
|
||||
assert(tlv);
|
||||
assert(tlv[1] >= 4);
|
||||
return snd_ctl_elem_tlv_command(elem->hctl->ctl, &elem->id, tlv);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get HCTL handle for an HCTL element
|
||||
* \param elem HCTL element
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue