Commit a540e133 authored by Takashi Iwai's avatar Takashi Iwai

Merge remote branch 'alsa/devel' into topic/misc

parents cebe41d4 c3a3e040
This diff is collapsed.
...@@ -123,6 +123,7 @@ struct usb_mixer_elem_info { ...@@ -123,6 +123,7 @@ struct usb_mixer_elem_info {
int channels; int channels;
int val_type; int val_type;
int min, max, res; int min, max, res;
int dBmin, dBmax;
int cached; int cached;
int cache_val[MAX_CHANNELS]; int cache_val[MAX_CHANNELS];
u8 initialized; u8 initialized;
...@@ -209,42 +210,50 @@ enum { ...@@ -209,42 +210,50 @@ enum {
*/ */
#include "usbmixer_maps.c" #include "usbmixer_maps.c"
/* get the mapped name if the unit matches */ static const struct usbmix_name_map *
static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) find_map(struct mixer_build *state, int unitid, int control)
{ {
const struct usbmix_name_map *p; const struct usbmix_name_map *p = state->map;
if (! state->map) if (!p)
return 0; return NULL;
for (p = state->map; p->id; p++) { for (p = state->map; p->id; p++) {
if (p->id == unitid && p->name && if (p->id == unitid &&
(! control || ! p->control || control == p->control)) { (!control || !p->control || control == p->control))
buflen--; return p;
return strlcpy(buf, p->name, buflen);
}
} }
return NULL;
}
/* get the mapped name if the unit matches */
static int
check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
{
if (!p || !p->name)
return 0; return 0;
buflen--;
return strlcpy(buf, p->name, buflen);
} }
/* check whether the control should be ignored */ /* check whether the control should be ignored */
static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) static inline int
check_ignored_ctl(const struct usbmix_name_map *p)
{ {
const struct usbmix_name_map *p; if (!p || p->name || p->dB)
if (! state->map)
return 0; return 0;
for (p = state->map; p->id; p++) {
if (p->id == unitid && ! p->name &&
(! control || ! p->control || control == p->control)) {
/*
printk(KERN_DEBUG "ignored control %d:%d\n",
unitid, control);
*/
return 1; return 1;
}
/* dB mapping */
static inline void check_mapped_dB(const struct usbmix_name_map *p,
struct usb_mixer_elem_info *cval)
{
if (p && p->dB) {
cval->dBmin = p->dB->min;
cval->dBmax = p->dB->max;
} }
}
return 0;
} }
/* get the mapped selector source name */ /* get the mapped selector source name */
...@@ -481,20 +490,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, ...@@ -481,20 +490,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
if (size < sizeof(scale)) if (size < sizeof(scale))
return -ENOMEM; return -ENOMEM;
/* USB descriptions contain the dB scale in 1/256 dB unit scale[2] = cval->dBmin;
* while ALSA TLV contains in 1/100 dB unit scale[3] = cval->dBmax;
*/
scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
if (scale[3] <= scale[2]) {
/* something is wrong; assume it's either from/to 0dB */
if (scale[2] < 0)
scale[3] = 0;
else if (scale[2] > 0)
scale[2] = 0;
else /* totally crap, return an error */
return -EINVAL;
}
if (copy_to_user(_tlv, scale, sizeof(scale))) if (copy_to_user(_tlv, scale, sizeof(scale)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -735,6 +732,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) ...@@ -735,6 +732,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
cval->min = default_min; cval->min = default_min;
cval->max = cval->min + 1; cval->max = cval->min + 1;
cval->res = 1; cval->res = 1;
cval->dBmin = cval->dBmax = 0;
if (cval->val_type == USB_MIXER_BOOLEAN || if (cval->val_type == USB_MIXER_BOOLEAN ||
cval->val_type == USB_MIXER_INV_BOOLEAN) { cval->val_type == USB_MIXER_INV_BOOLEAN) {
...@@ -802,6 +800,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) ...@@ -802,6 +800,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
cval->initialized = 1; cval->initialized = 1;
} }
/* USB descriptions contain the dB scale in 1/256 dB unit
* while ALSA TLV contains in 1/100 dB unit
*/
cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256;
cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256;
if (cval->dBmin > cval->dBmax) {
/* something is wrong; assume it's either from/to 0dB */
if (cval->dBmin < 0)
cval->dBmax = 0;
else if (cval->dBmin > 0)
cval->dBmin = 0;
if (cval->dBmin > cval->dBmax) {
/* totally crap, return an error */
return -EINVAL;
}
}
return 0; return 0;
} }
...@@ -927,6 +943,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, ...@@ -927,6 +943,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
int nameid = desc[desc[0] - 1]; int nameid = desc[desc[0] - 1];
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval; struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
control++; /* change from zero-based to 1-based value */ control++; /* change from zero-based to 1-based value */
...@@ -935,7 +952,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, ...@@ -935,7 +952,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
return; return;
} }
if (check_ignored_ctl(state, unitid, control)) map = find_map(state, unitid, control);
if (check_ignored_ctl(map))
return; return;
cval = kzalloc(sizeof(*cval), GFP_KERNEL); cval = kzalloc(sizeof(*cval), GFP_KERNEL);
...@@ -969,10 +987,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, ...@@ -969,10 +987,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
} }
kctl->private_free = usb_mixer_elem_free; kctl->private_free = usb_mixer_elem_free;
len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
mapped_name = len != 0; mapped_name = len != 0;
if (! len && nameid) if (! len && nameid)
len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); len = snd_usb_copy_string_desc(state, nameid,
kctl->id.name, sizeof(kctl->id.name));
switch (control) { switch (control) {
case USB_FEATURE_MUTE: case USB_FEATURE_MUTE:
...@@ -1010,6 +1029,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, ...@@ -1010,6 +1029,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
kctl->vd[0].access |= kctl->vd[0].access |=
SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
check_mapped_dB(map, cval);
} }
break; break;
...@@ -1137,8 +1157,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, ...@@ -1137,8 +1157,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
unsigned int num_outs = desc[5 + input_pins]; unsigned int num_outs = desc[5 + input_pins];
unsigned int i, len; unsigned int i, len;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
const struct usbmix_name_map *map;
if (check_ignored_ctl(state, unitid, 0)) map = find_map(state, unitid, 0);
if (check_ignored_ctl(map))
return; return;
cval = kzalloc(sizeof(*cval), GFP_KERNEL); cval = kzalloc(sizeof(*cval), GFP_KERNEL);
...@@ -1167,7 +1189,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, ...@@ -1167,7 +1189,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
} }
kctl->private_free = usb_mixer_elem_free; kctl->private_free = usb_mixer_elem_free;
len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (! len) if (! len)
len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
if (! len) if (! len)
...@@ -1382,6 +1404,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned ...@@ -1382,6 +1404,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
int i, err, nameid, type, len; int i, err, nameid, type, len;
struct procunit_info *info; struct procunit_info *info;
struct procunit_value_info *valinfo; struct procunit_value_info *valinfo;
const struct usbmix_name_map *map;
static struct procunit_value_info default_value_info[] = { static struct procunit_value_info default_value_info[] = {
{ 0x01, "Switch", USB_MIXER_BOOLEAN }, { 0x01, "Switch", USB_MIXER_BOOLEAN },
{ 0 } { 0 }
...@@ -1411,7 +1434,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned ...@@ -1411,7 +1434,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
/* FIXME: bitmap might be longer than 8bit */ /* FIXME: bitmap might be longer than 8bit */
if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1))))
continue; continue;
if (check_ignored_ctl(state, unitid, valinfo->control)) map = find_map(state, unitid, valinfo->control);
if (check_ignored_ctl(map))
continue; continue;
cval = kzalloc(sizeof(*cval), GFP_KERNEL); cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (! cval) { if (! cval) {
...@@ -1452,8 +1476,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned ...@@ -1452,8 +1476,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
} }
kctl->private_free = usb_mixer_elem_free; kctl->private_free = usb_mixer_elem_free;
if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) if (check_mapped_name(map, kctl->id.name,
; sizeof(kctl->id.name)))
/* nothing */ ;
else if (info->name) else if (info->name)
strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
else { else {
...@@ -1592,6 +1617,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi ...@@ -1592,6 +1617,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
int err; int err;
struct usb_mixer_elem_info *cval; struct usb_mixer_elem_info *cval;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
const struct usbmix_name_map *map;
char **namelist; char **namelist;
if (! num_ins || desc[0] < 5 + num_ins) { if (! num_ins || desc[0] < 5 + num_ins) {
...@@ -1607,7 +1633,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi ...@@ -1607,7 +1633,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
if (num_ins == 1) /* only one ? nonsense! */ if (num_ins == 1) /* only one ? nonsense! */
return 0; return 0;
if (check_ignored_ctl(state, unitid, 0)) map = find_map(state, unitid, 0);
if (check_ignored_ctl(map))
return 0; return 0;
cval = kzalloc(sizeof(*cval), GFP_KERNEL); cval = kzalloc(sizeof(*cval), GFP_KERNEL);
...@@ -1662,7 +1689,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi ...@@ -1662,7 +1689,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
kctl->private_free = usb_mixer_selector_elem_free; kctl->private_free = usb_mixer_selector_elem_free;
nameid = desc[desc[0] - 1]; nameid = desc[desc[0] - 1];
len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (len) if (len)
; ;
else if (nameid) else if (nameid)
......
...@@ -19,11 +19,16 @@ ...@@ -19,11 +19,16 @@
* *
*/ */
struct usbmix_dB_map {
u32 min;
u32 max;
};
struct usbmix_name_map { struct usbmix_name_map {
int id; int id;
const char *name; const char *name;
int control; int control;
struct usbmix_dB_map *dB;
}; };
struct usbmix_selector_map { struct usbmix_selector_map {
...@@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = { ...@@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = {
{ 8, "Line Playback" }, /* FU */ { 8, "Line Playback" }, /* FU */
/* 9: IT mic */ /* 9: IT mic */
{ 10, "Mic Playback" }, /* FU */ { 10, "Mic Playback" }, /* FU */
{ 11, "Capture Input Source" }, /* SU */ { 11, "Capture Source" }, /* SU */
{ 12, "Capture" }, /* FU */ { 12, "Capture" }, /* FU */
/* 13: OT pcm capture */ /* 13: OT pcm capture */
/* 14: MU (w/o controls) */ /* 14: MU (w/o controls) */
...@@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = { ...@@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = {
* e.g. no Master and fake PCM volume * e.g. no Master and fake PCM volume
* Pavel Mihaylov <bin@bash.info> * Pavel Mihaylov <bin@bash.info>
*/ */
static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */
static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */
static struct usbmix_name_map mp3plus_map[] = { static struct usbmix_name_map mp3plus_map[] = {
/* 1: IT pcm */ /* 1: IT pcm */
/* 2: IT mic */ /* 2: IT mic */
...@@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = { ...@@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = {
/* 5: OT digital out */ /* 5: OT digital out */
/* 6: OT speaker */ /* 6: OT speaker */
/* 7: OT pcm capture */ /* 7: OT pcm capture */
{ 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ { 8, "Capture Source" }, /* FU, default PCM Capture Source */
/* (Mic, Input 1 = Line input, Input 2 = Optical input) */ /* (Mic, Input 1 = Line input, Input 2 = Optical input) */
{ 9, "Master Playback" }, /* FU, default Speaker 1 */ { 9, "Master Playback" }, /* FU, default Speaker 1 */
/* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */
/* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 },
/* FU, Mic Capture */
{ 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */
{ 11, "Line Capture" }, /* FU, default PCM Capture */ { 11, "Line Capture", .dB = &mp3plus_dB_2 },
/* FU, default PCM Capture */
{ 12, "Digital In Playback" }, /* FU, default PCM 1 */ { 12, "Digital In Playback" }, /* FU, default PCM 1 */
/* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 },
{ 14, "Line Playback" }, /* FU, default Speaker */ /* FU, default Mic Playback */
{ 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */
/* 15: MU */ /* 15: MU */
{ 0 } /* terminator */ { 0 } /* terminator */
}; };
......
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