Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42750b04 authored by Jaroslav Kysela's avatar Jaroslav Kysela
Browse files

[ALSA] Control API - TLV implementation for additional information like dB scale



This patch implements a TLV mechanism to transfer an additional information
like dB scale to the user space. The types might be extended in future.
Acked-by: default avatarTakashi Iwai <tiwai@suse.de>

Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent 3eeab61a
Loading
Loading
Loading
Loading
+8 −1
Original line number Original line Diff line number Diff line
@@ -688,7 +688,7 @@ struct snd_timer_tread {
 *                                                                          *
 *                                                                          *
 ****************************************************************************/
 ****************************************************************************/


#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 3)
#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 4)


struct snd_ctl_card_info {
struct snd_ctl_card_info {
	int card;			/* card number */
	int card;			/* card number */
@@ -818,6 +818,12 @@ struct snd_ctl_elem_value {
        unsigned char reserved[128-sizeof(struct timespec)];
        unsigned char reserved[128-sizeof(struct timespec)];
};
};


struct snd_ctl_tlv {
        unsigned int numid;	/* control element numeric identification */
        unsigned int length;	/* in bytes aligned to 4 */
        unsigned int tlv[0];	/* first TLV */
};

enum {
enum {
	SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
	SNDRV_CTL_IOCTL_PVERSION = _IOR('U', 0x00, int),
	SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
	SNDRV_CTL_IOCTL_CARD_INFO = _IOR('U', 0x01, struct snd_ctl_card_info),
@@ -831,6 +837,7 @@ enum {
	SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
	SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct snd_ctl_elem_info),
	SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
	SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
	SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
	SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
	SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
	SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
	SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
	SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
	SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
	SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
	SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
+2 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,7 @@ struct snd_kcontrol_new {
	snd_kcontrol_info_t *info;
	snd_kcontrol_info_t *info;
	snd_kcontrol_get_t *get;
	snd_kcontrol_get_t *get;
	snd_kcontrol_put_t *put;
	snd_kcontrol_put_t *put;
	unsigned int *tlv;
	unsigned long private_value;
	unsigned long private_value;
};
};


@@ -58,6 +59,7 @@ struct snd_kcontrol {
	snd_kcontrol_info_t *info;
	snd_kcontrol_info_t *info;
	snd_kcontrol_get_t *get;
	snd_kcontrol_get_t *get;
	snd_kcontrol_put_t *put;
	snd_kcontrol_put_t *put;
	unsigned int *tlv;
	unsigned long private_value;
	unsigned long private_value;
	void *private_data;
	void *private_data;
	void (*private_free)(struct snd_kcontrol *kcontrol);
	void (*private_free)(struct snd_kcontrol *kcontrol);

include/sound/tlv.h

0 → 100644
+43 −0
Original line number Original line Diff line number Diff line
#ifndef __SOUND_TLV_H
#define __SOUND_TLV_H

/*
 *  Advanced Linux Sound Architecture - ALSA - Driver
 *  Copyright (c) 2006 by Jaroslav Kysela <perex@suse.cz>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

/*
 * TLV structure is right behind the struct snd_ctl_tlv:
 *   unsigned int type  	- see SNDRV_CTL_TLVT_*
 *   unsigned int length
 *   .... data aligned to sizeof(unsigned int), use
 *        block_length = (length + (sizeof(unsigned int) - 1)) &
 *                       ~(sizeof(unsigned int) - 1)) ....
 */

#define SNDRV_CTL_TLVT_CONTAINER 0	/* one level down - group of TLVs */
#define SNDRV_CTL_TLVT_DB_SCALE	1       /* dB scale */

#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
unsigned int name[] = { \
        SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
        (min), ((step) & 0xffff) | ((mute) ? 0x10000 : 0) \
}

#endif /* __SOUND_TLV_H */
+39 −2
Original line number Original line Diff line number Diff line
@@ -241,6 +241,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
	kctl.info = ncontrol->info;
	kctl.info = ncontrol->info;
	kctl.get = ncontrol->get;
	kctl.get = ncontrol->get;
	kctl.put = ncontrol->put;
	kctl.put = ncontrol->put;
	kctl.tlv = ncontrol->tlv;
	kctl.private_value = ncontrol->private_value;
	kctl.private_value = ncontrol->private_value;
	kctl.private_data = private_data;
	kctl.private_data = private_data;
	return snd_ctl_new(&kctl, access);
	return snd_ctl_new(&kctl, access);
@@ -1067,6 +1068,40 @@ static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
	return 0;
	return 0;
}
}


static int snd_ctl_tlv_read(struct snd_card *card,
                            struct snd_ctl_tlv __user *_tlv)
{
	struct snd_ctl_tlv tlv;
	struct snd_kcontrol *kctl;
	unsigned int len;
	int err = 0;

	if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
		return -EFAULT;
        if (tlv.length < sizeof(unsigned int) * 3)
                return -EINVAL;
        down_read(&card->controls_rwsem);
        kctl = snd_ctl_find_numid(card, tlv.numid);
        if (kctl == NULL) {
                err = -ENOENT;
                goto __kctl_end;
        }
        if (kctl->tlv == NULL) {
                err = -ENXIO;
                goto __kctl_end;
        }
        len = kctl->tlv[1] + 2 * sizeof(unsigned int);
        if (tlv.length < len) {
                err = -ENOMEM;
                goto __kctl_end;
        }
        if (copy_to_user(_tlv->tlv, kctl->tlv, len))
        	err = -EFAULT;
      __kctl_end:
        up_read(&card->controls_rwsem);
        return err;
}

static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
{
	struct snd_ctl_file *ctl;
	struct snd_ctl_file *ctl;
@@ -1086,11 +1121,11 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
	case SNDRV_CTL_IOCTL_CARD_INFO:
	case SNDRV_CTL_IOCTL_CARD_INFO:
		return snd_ctl_card_info(card, ctl, cmd, argp);
		return snd_ctl_card_info(card, ctl, cmd, argp);
	case SNDRV_CTL_IOCTL_ELEM_LIST:
	case SNDRV_CTL_IOCTL_ELEM_LIST:
		return snd_ctl_elem_list(ctl->card, argp);
		return snd_ctl_elem_list(card, argp);
	case SNDRV_CTL_IOCTL_ELEM_INFO:
	case SNDRV_CTL_IOCTL_ELEM_INFO:
		return snd_ctl_elem_info_user(ctl, argp);
		return snd_ctl_elem_info_user(ctl, argp);
	case SNDRV_CTL_IOCTL_ELEM_READ:
	case SNDRV_CTL_IOCTL_ELEM_READ:
		return snd_ctl_elem_read_user(ctl->card, argp);
		return snd_ctl_elem_read_user(card, argp);
	case SNDRV_CTL_IOCTL_ELEM_WRITE:
	case SNDRV_CTL_IOCTL_ELEM_WRITE:
		return snd_ctl_elem_write_user(ctl, argp);
		return snd_ctl_elem_write_user(ctl, argp);
	case SNDRV_CTL_IOCTL_ELEM_LOCK:
	case SNDRV_CTL_IOCTL_ELEM_LOCK:
@@ -1105,6 +1140,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
		return snd_ctl_elem_remove(ctl, argp);
		return snd_ctl_elem_remove(ctl, argp);
	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
		return snd_ctl_subscribe_events(ctl, ip);
		return snd_ctl_subscribe_events(ctl, ip);
        case SNDRV_CTL_IOCTL_TLV_READ:
                return snd_ctl_tlv_read(card, argp);
	case SNDRV_CTL_IOCTL_POWER:
	case SNDRV_CTL_IOCTL_POWER:
		return -ENOPROTOOPT;
		return -ENOPROTOOPT;
	case SNDRV_CTL_IOCTL_POWER_STATE:
	case SNDRV_CTL_IOCTL_POWER_STATE:
+4 −0
Original line number Original line Diff line number Diff line
@@ -70,9 +70,12 @@
#include <sound/pcm.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/info.h>
#include <sound/tlv.h>


#include "ca0106.h"
#include "ca0106.h"


static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale, -5150, 75, 1);

static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
					struct snd_ctl_elem_info *uinfo)
					struct snd_ctl_elem_info *uinfo)
{
{
@@ -472,6 +475,7 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
	.info =	 snd_ca0106_volume_info,			\
	.info =	 snd_ca0106_volume_info,			\
	.get =   snd_ca0106_volume_get,				\
	.get =   snd_ca0106_volume_get,				\
	.put =   snd_ca0106_volume_put,				\
	.put =   snd_ca0106_volume_put,				\
	.tlv =	 snd_ca0106_db_scale,				\
	.private_value = ((chid) << 8) | (reg)			\
	.private_value = ((chid) << 8) | (reg)			\
}
}