aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-02-11 11:50:44 -0500
committerJaroslav Kysela <perex@perex.cz>2010-02-11 12:00:16 -0500
commitc3a3e040f01457d2ea4f199f75ca205401001a3b (patch)
tree38ba87d579c874ff68f55317ef468f56127cdc87
parentd5e1ca05f758fec2845a97fd7aa1eeca91c51a21 (diff)
ALSA: usbmixer - add possibility to remap dB values
USB devices tends to represent dB ranges in different way than ALSA expects. Add possibility to override these values and add guessed values for SoundBlaster MP3+. Also rename 'Capture Input Source' control to 'Capture Source' for SoundBlaster MP3+ and Extigy. Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--sound/usb/usbmixer.c125
-rw-r--r--sound/usb/usbmixer_maps.c23
2 files changed, 93 insertions, 55 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index c998220b99c6..c72ad0c82581 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -123,6 +123,7 @@ struct usb_mixer_elem_info {
123 int channels; 123 int channels;
124 int val_type; 124 int val_type;
125 int min, max, res; 125 int min, max, res;
126 int dBmin, dBmax;
126 int cached; 127 int cached;
127 int cache_val[MAX_CHANNELS]; 128 int cache_val[MAX_CHANNELS];
128 u8 initialized; 129 u8 initialized;
@@ -194,42 +195,50 @@ enum {
194 */ 195 */
195#include "usbmixer_maps.c" 196#include "usbmixer_maps.c"
196 197
197/* get the mapped name if the unit matches */ 198static const struct usbmix_name_map *
198static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) 199find_map(struct mixer_build *state, int unitid, int control)
199{ 200{
200 const struct usbmix_name_map *p; 201 const struct usbmix_name_map *p = state->map;
201 202
202 if (! state->map) 203 if (!p)
203 return 0; 204 return NULL;
204 205
205 for (p = state->map; p->id; p++) { 206 for (p = state->map; p->id; p++) {
206 if (p->id == unitid && p->name && 207 if (p->id == unitid &&
207 (! control || ! p->control || control == p->control)) { 208 (!control || !p->control || control == p->control))
208 buflen--; 209 return p;
209 return strlcpy(buf, p->name, buflen);
210 }
211 } 210 }
212 return 0; 211 return NULL;
213} 212}
214 213
215/* check whether the control should be ignored */ 214/* get the mapped name if the unit matches */
216static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) 215static int
216check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
217{ 217{
218 const struct usbmix_name_map *p; 218 if (!p || !p->name)
219 return 0;
219 220
220 if (! state->map) 221 buflen--;
222 return strlcpy(buf, p->name, buflen);
223}
224
225/* check whether the control should be ignored */
226static inline int
227check_ignored_ctl(const struct usbmix_name_map *p)
228{
229 if (!p || p->name || p->dB)
221 return 0; 230 return 0;
222 for (p = state->map; p->id; p++) { 231 return 1;
223 if (p->id == unitid && ! p->name && 232}
224 (! control || ! p->control || control == p->control)) { 233
225 /* 234/* dB mapping */
226 printk(KERN_DEBUG "ignored control %d:%d\n", 235static inline void check_mapped_dB(const struct usbmix_name_map *p,
227 unitid, control); 236 struct usb_mixer_elem_info *cval)
228 */ 237{
229 return 1; 238 if (p && p->dB) {
230 } 239 cval->dBmin = p->dB->min;
240 cval->dBmax = p->dB->max;
231 } 241 }
232 return 0;
233} 242}
234 243
235/* get the mapped selector source name */ 244/* get the mapped selector source name */
@@ -466,20 +475,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
466 475
467 if (size < sizeof(scale)) 476 if (size < sizeof(scale))
468 return -ENOMEM; 477 return -ENOMEM;
469 /* USB descriptions contain the dB scale in 1/256 dB unit 478 scale[2] = cval->dBmin;
470 * while ALSA TLV contains in 1/100 dB unit 479 scale[3] = cval->dBmax;
471 */
472 scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
473 scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
474 if (scale[3] <= scale[2]) {
475 /* something is wrong; assume it's either from/to 0dB */
476 if (scale[2] < 0)
477 scale[3] = 0;
478 else if (scale[2] > 0)
479 scale[2] = 0;
480 else /* totally crap, return an error */
481 return -EINVAL;
482 }
483 if (copy_to_user(_tlv, scale, sizeof(scale))) 480 if (copy_to_user(_tlv, scale, sizeof(scale)))
484 return -EFAULT; 481 return -EFAULT;
485 return 0; 482 return 0;
@@ -720,6 +717,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
720 cval->min = default_min; 717 cval->min = default_min;
721 cval->max = cval->min + 1; 718 cval->max = cval->min + 1;
722 cval->res = 1; 719 cval->res = 1;
720 cval->dBmin = cval->dBmax = 0;
723 721
724 if (cval->val_type == USB_MIXER_BOOLEAN || 722 if (cval->val_type == USB_MIXER_BOOLEAN ||
725 cval->val_type == USB_MIXER_INV_BOOLEAN) { 723 cval->val_type == USB_MIXER_INV_BOOLEAN) {
@@ -787,6 +785,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min)
787 785
788 cval->initialized = 1; 786 cval->initialized = 1;
789 } 787 }
788
789 /* USB descriptions contain the dB scale in 1/256 dB unit
790 * while ALSA TLV contains in 1/100 dB unit
791 */
792 cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256;
793 cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256;
794 if (cval->dBmin > cval->dBmax) {
795 /* something is wrong; assume it's either from/to 0dB */
796 if (cval->dBmin < 0)
797 cval->dBmax = 0;
798 else if (cval->dBmin > 0)
799 cval->dBmin = 0;
800 if (cval->dBmin > cval->dBmax) {
801 /* totally crap, return an error */
802 return -EINVAL;
803 }
804 }
805
790 return 0; 806 return 0;
791} 807}
792 808
@@ -912,6 +928,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
912 int nameid = desc[desc[0] - 1]; 928 int nameid = desc[desc[0] - 1];
913 struct snd_kcontrol *kctl; 929 struct snd_kcontrol *kctl;
914 struct usb_mixer_elem_info *cval; 930 struct usb_mixer_elem_info *cval;
931 const struct usbmix_name_map *map;
915 932
916 control++; /* change from zero-based to 1-based value */ 933 control++; /* change from zero-based to 1-based value */
917 934
@@ -920,7 +937,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
920 return; 937 return;
921 } 938 }
922 939
923 if (check_ignored_ctl(state, unitid, control)) 940 map = find_map(state, unitid, control);
941 if (check_ignored_ctl(map))
924 return; 942 return;
925 943
926 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 944 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
@@ -954,10 +972,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
954 } 972 }
955 kctl->private_free = usb_mixer_elem_free; 973 kctl->private_free = usb_mixer_elem_free;
956 974
957 len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); 975 len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
958 mapped_name = len != 0; 976 mapped_name = len != 0;
959 if (! len && nameid) 977 if (! len && nameid)
960 len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); 978 len = snd_usb_copy_string_desc(state, nameid,
979 kctl->id.name, sizeof(kctl->id.name));
961 980
962 switch (control) { 981 switch (control) {
963 case USB_FEATURE_MUTE: 982 case USB_FEATURE_MUTE:
@@ -995,6 +1014,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
995 kctl->vd[0].access |= 1014 kctl->vd[0].access |=
996 SNDRV_CTL_ELEM_ACCESS_TLV_READ | 1015 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
997 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 1016 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1017 check_mapped_dB(map, cval);
998 } 1018 }
999 break; 1019 break;
1000 1020
@@ -1122,8 +1142,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
1122 unsigned int num_outs = desc[5 + input_pins]; 1142 unsigned int num_outs = desc[5 + input_pins];
1123 unsigned int i, len; 1143 unsigned int i, len;
1124 struct snd_kcontrol *kctl; 1144 struct snd_kcontrol *kctl;
1145 const struct usbmix_name_map *map;
1125 1146
1126 if (check_ignored_ctl(state, unitid, 0)) 1147 map = find_map(state, unitid, 0);
1148 if (check_ignored_ctl(map))
1127 return; 1149 return;
1128 1150
1129 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 1151 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
@@ -1152,7 +1174,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
1152 } 1174 }
1153 kctl->private_free = usb_mixer_elem_free; 1175 kctl->private_free = usb_mixer_elem_free;
1154 1176
1155 len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); 1177 len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
1156 if (! len) 1178 if (! len)
1157 len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); 1179 len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
1158 if (! len) 1180 if (! len)
@@ -1342,6 +1364,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
1342 int i, err, nameid, type, len; 1364 int i, err, nameid, type, len;
1343 struct procunit_info *info; 1365 struct procunit_info *info;
1344 struct procunit_value_info *valinfo; 1366 struct procunit_value_info *valinfo;
1367 const struct usbmix_name_map *map;
1345 static struct procunit_value_info default_value_info[] = { 1368 static struct procunit_value_info default_value_info[] = {
1346 { 0x01, "Switch", USB_MIXER_BOOLEAN }, 1369 { 0x01, "Switch", USB_MIXER_BOOLEAN },
1347 { 0 } 1370 { 0 }
@@ -1371,7 +1394,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
1371 /* FIXME: bitmap might be longer than 8bit */ 1394 /* FIXME: bitmap might be longer than 8bit */
1372 if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) 1395 if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1))))
1373 continue; 1396 continue;
1374 if (check_ignored_ctl(state, unitid, valinfo->control)) 1397 map = find_map(state, unitid, valinfo->control);
1398 if (check_ignored_ctl(map))
1375 continue; 1399 continue;
1376 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 1400 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1377 if (! cval) { 1401 if (! cval) {
@@ -1402,8 +1426,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
1402 } 1426 }
1403 kctl->private_free = usb_mixer_elem_free; 1427 kctl->private_free = usb_mixer_elem_free;
1404 1428
1405 if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) 1429 if (check_mapped_name(map, kctl->id.name,
1406 ; 1430 sizeof(kctl->id.name)))
1431 /* nothing */ ;
1407 else if (info->name) 1432 else if (info->name)
1408 strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); 1433 strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
1409 else { 1434 else {
@@ -1542,6 +1567,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
1542 int err; 1567 int err;
1543 struct usb_mixer_elem_info *cval; 1568 struct usb_mixer_elem_info *cval;
1544 struct snd_kcontrol *kctl; 1569 struct snd_kcontrol *kctl;
1570 const struct usbmix_name_map *map;
1545 char **namelist; 1571 char **namelist;
1546 1572
1547 if (! num_ins || desc[0] < 5 + num_ins) { 1573 if (! num_ins || desc[0] < 5 + num_ins) {
@@ -1557,7 +1583,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
1557 if (num_ins == 1) /* only one ? nonsense! */ 1583 if (num_ins == 1) /* only one ? nonsense! */
1558 return 0; 1584 return 0;
1559 1585
1560 if (check_ignored_ctl(state, unitid, 0)) 1586 map = find_map(state, unitid, 0);
1587 if (check_ignored_ctl(map))
1561 return 0; 1588 return 0;
1562 1589
1563 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 1590 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
@@ -1612,7 +1639,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
1612 kctl->private_free = usb_mixer_selector_elem_free; 1639 kctl->private_free = usb_mixer_selector_elem_free;
1613 1640
1614 nameid = desc[desc[0] - 1]; 1641 nameid = desc[desc[0] - 1];
1615 len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); 1642 len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
1616 if (len) 1643 if (len)
1617 ; 1644 ;
1618 else if (nameid) 1645 else if (nameid)
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c
index 77c35885e21c..79e903a60862 100644
--- a/sound/usb/usbmixer_maps.c
+++ b/sound/usb/usbmixer_maps.c
@@ -19,11 +19,16 @@
19 * 19 *
20 */ 20 */
21 21
22struct usbmix_dB_map {
23 u32 min;
24 u32 max;
25};
22 26
23struct usbmix_name_map { 27struct usbmix_name_map {
24 int id; 28 int id;
25 const char *name; 29 const char *name;
26 int control; 30 int control;
31 struct usbmix_dB_map *dB;
27}; 32};
28 33
29struct usbmix_selector_map { 34struct usbmix_selector_map {
@@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = {
72 { 8, "Line Playback" }, /* FU */ 77 { 8, "Line Playback" }, /* FU */
73 /* 9: IT mic */ 78 /* 9: IT mic */
74 { 10, "Mic Playback" }, /* FU */ 79 { 10, "Mic Playback" }, /* FU */
75 { 11, "Capture Input Source" }, /* SU */ 80 { 11, "Capture Source" }, /* SU */
76 { 12, "Capture" }, /* FU */ 81 { 12, "Capture" }, /* FU */
77 /* 13: OT pcm capture */ 82 /* 13: OT pcm capture */
78 /* 14: MU (w/o controls) */ 83 /* 14: MU (w/o controls) */
@@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = {
102 * e.g. no Master and fake PCM volume 107 * e.g. no Master and fake PCM volume
103 * Pavel Mihaylov <bin@bash.info> 108 * Pavel Mihaylov <bin@bash.info>
104 */ 109 */
110static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */
111static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */
112
105static struct usbmix_name_map mp3plus_map[] = { 113static struct usbmix_name_map mp3plus_map[] = {
106 /* 1: IT pcm */ 114 /* 1: IT pcm */
107 /* 2: IT mic */ 115 /* 2: IT mic */
@@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = {
110 /* 5: OT digital out */ 118 /* 5: OT digital out */
111 /* 6: OT speaker */ 119 /* 6: OT speaker */
112 /* 7: OT pcm capture */ 120 /* 7: OT pcm capture */
113 { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ 121 { 8, "Capture Source" }, /* FU, default PCM Capture Source */
114 /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ 122 /* (Mic, Input 1 = Line input, Input 2 = Optical input) */
115 { 9, "Master Playback" }, /* FU, default Speaker 1 */ 123 { 9, "Master Playback" }, /* FU, default Speaker 1 */
116 /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ 124 /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */
117 /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ 125 { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 },
126 /* FU, Mic Capture */
118 { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ 127 { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */
119 { 11, "Line Capture" }, /* FU, default PCM Capture */ 128 { 11, "Line Capture", .dB = &mp3plus_dB_2 },
129 /* FU, default PCM Capture */
120 { 12, "Digital In Playback" }, /* FU, default PCM 1 */ 130 { 12, "Digital In Playback" }, /* FU, default PCM 1 */
121 /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ 131 { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 },
122 { 14, "Line Playback" }, /* FU, default Speaker */ 132 /* FU, default Mic Playback */
133 { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */
123 /* 15: MU */ 134 /* 15: MU */
124 { 0 } /* terminator */ 135 { 0 } /* terminator */
125}; 136};