OSDN Git Service

Control API - add TLV support
authorJaroslav Kysela <perex@perex.cz>
Wed, 5 Jul 2006 15:42:16 +0000 (17:42 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 5 Jul 2006 15:42:16 +0000 (17:42 +0200)
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

include/control.h
include/sound/asound.h
src/Versions
src/control/control.c
src/control/control_hw.c
src/control/control_local.h
src/control/hcontrol.c

index 28c1fc8..af0f91a 100644 (file)
@@ -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);
 
index ae5fcd4..412029e 100644 (file)
@@ -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),
index cb4cc22..ad85b9b 100644 (file)
@@ -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;
index 4bf96e5..d0707af 100644 (file)
@@ -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
@@ -1742,6 +1821,39 @@ int snd_ctl_elem_info_is_user(const snd_ctl_elem_info_t *obj)
 }
 
 /**
+ * \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
  * \return 0 if element value need to be passed by contents, 1 if need to be passed with a pointer
index ac1f231..88770ee 100644 (file)
@@ -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,
index ce7bb83..ce81aea 100644 (file)
@@ -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);
index 05d2883..5a234a2 100644 (file)
@@ -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)
 {
@@ -833,6 +835,53 @@ int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * 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
  * \return HCTL handle