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

[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
...@@ -688,7 +688,7 @@ struct snd_timer_tread { ...@@ -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 { ...@@ -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 { ...@@ -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),
......
...@@ -42,6 +42,7 @@ struct snd_kcontrol_new { ...@@ -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 { ...@@ -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);
......
#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 */
...@@ -241,6 +241,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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:
......
...@@ -70,9 +70,12 @@ ...@@ -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, ...@@ -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) \
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment