aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb')
-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};