return count;
}
+static int snd_hctl_elem_decode_tlv_db_gain(unsigned int *tlv, unsigned int tlv_size, long volume, long *db_gain)
+{
+ unsigned int type;
+ unsigned int size;
+ unsigned int idx = 0;
+ int err = 0;
+
+ type = tlv[idx++];
+ size = tlv[idx++];
+ tlv_size -= 2 * sizeof(unsigned int);
+ if (size > tlv_size) {
+ printf("TLV size error (%i, %i, %i)!\n", type, size, tlv_size);
+ err=-EINVAL;
+ goto __exit_decode_db_gain;
+ }
+ switch (type) {
+ case SND_CTL_TLVT_CONTAINER:
+ size += sizeof(unsigned int) -1;
+ size /= sizeof(unsigned int);
+ printf("TLV container!\n");
+ while (idx < size) {
+ if (tlv[idx+1] > (size - idx) * sizeof(unsigned int)) {
+ printf("TLV size error in compound!\n");
+ err=-EINVAL;
+ goto __exit_decode_db_gain;
+ }
+ err = snd_hctl_elem_decode_tlv_db_gain(tlv + idx, tlv[idx+1], volume, db_gain);
+ if (!err) break; /* db_gain obtained */
+ idx += 2 + (tlv[1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
+ }
+ break;
+ case SND_CTL_TLVT_DB_SCALE:
+ if (size != 2 * sizeof(unsigned int)) {
+ while (size > 0) {
+ printf("0x%x", tlv[idx++]);
+ size -= sizeof(unsigned int);
+ }
+ printf("\n");
+ } else {
+ int min,step,mute;
+ min = tlv[2];
+ step = (tlv[3] & 0xffff);
+ mute = (tlv[3] >> 16) & 1;
+ *db_gain = (volume * step) + min;
+ if (mute && (volume == 0)) *db_gain = -9999999;
+ }
+ break;
+ default:
+ printf("unk-%i-", type);
+ while (size > 0) {
+ printf("0x%x", tlv[idx++]);
+ size -= sizeof(unsigned int);
+ }
+ printf("\n");
+ break;
+ }
+
+ __exit_decode_db_gain:
+ return err;
+}
+
+/**
+ * \brief Get db_gain information for an HCTL element
+ * \param elem HCTL element
+ * \param volume The current control volume
+ * \param db_gain The return value in db_gain scale
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_hctl_elem_get_db_gain(snd_hctl_elem_t *elem, long volume, long *db_gain)
+{
+ snd_ctl_elem_info_t *info;
+ unsigned int *tlv;
+ unsigned int tlv_size=4096;
+ unsigned int type;
+ unsigned int size;
+ unsigned int idx = 0;
+ int err=0;
+
+ snd_ctl_elem_info_alloca(&info);
+ snd_hctl_elem_info(elem, info);
+
+ if (tlv_size < 2 * sizeof(unsigned int)) {
+ printf("TLV size error!\n");
+ err=-EINVAL;
+ goto __exit_db_gain;
+ }
+ if (!snd_ctl_elem_info_is_tlv_readable(info)) {
+ err=-EINVAL;
+ goto __exit_db_gain;
+ }
+ tlv = malloc(4096);
+ if ((err = snd_hctl_elem_tlv_read(elem, tlv, tlv_size)) < 0) {
+ printf("Control element TLV read error: %s\n", snd_strerror(err));
+ goto __free_exit_db_gain;
+ }
+ err = snd_hctl_elem_decode_tlv_db_gain(tlv, tlv_size, volume, db_gain);
+
+ __free_exit_db_gain:
+ free(tlv);
+ __exit_db_gain:
+ return err;
+}
+
+
+
+
+
+
/**
* \brief Get information for an HCTL element
* \param elem HCTL element
return 0;
}
-static int get_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
- int dir ATTRIBUTE_UNUSED,
- snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
- long *value ATTRIBUTE_UNUSED)
+static int get_dB_ops(snd_mixer_elem_t *elem,
+ int dir,
+ snd_mixer_selem_channel_id_t channel,
+ long *value)
{
- return -ENXIO;
+ selem_none_t *s = snd_mixer_elem_get_private(elem);
+ selem_ctl_t *c;
+ int err = -EINVAL;
+ long volume, db_gain;
+ if (dir == SM_PLAY) {
+ c = &s->ctls[CTL_PLAYBACK_VOLUME];
+ if (c->type != 2) {
+ goto _err;
+ }
+ } else if (dir == SM_CAPT) {
+ c = &s->ctls[CTL_CAPTURE_VOLUME];
+ if (c->type != 2) {
+ goto _err;
+ }
+ } else goto _err;
+ if (err = get_volume_ops(elem, dir, channel, &volume)) {
+ goto _err;
+ }
+ if ((err = snd_hctl_elem_get_db_gain(c->elem, volume, &db_gain)) < 0) {
+ goto _err;
+ }
+ err = 0;
+ *value = db_gain;
+_err:
+ //if (err) printf("get_dB_ops:err=%d\n",err);
+ return err;
}
static int get_switch_ops(snd_mixer_elem_t *elem, int dir,