diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-02-12 04:42:38 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-02-12 04:42:38 -0500 |
commit | a540e13386e90f8c833c5cd0d16d877b8a277af1 (patch) | |
tree | bfa3fa455ac1302e7355122f9979531c7aa476e7 /sound/usb | |
parent | cebe41d4b8f8092359de31e241815fcb4b4dc0be (diff) | |
parent | c3a3e040f01457d2ea4f199f75ca205401001a3b (diff) |
Merge remote branch 'alsa/devel' into topic/misc
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/usbmixer.c | 125 | ||||
-rw-r--r-- | sound/usb/usbmixer_maps.c | 23 |
2 files changed, 93 insertions, 55 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index f5596cfdbde1..dd0c1d7bf3ed 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; |
@@ -209,42 +210,50 @@ enum { | |||
209 | */ | 210 | */ |
210 | #include "usbmixer_maps.c" | 211 | #include "usbmixer_maps.c" |
211 | 212 | ||
212 | /* get the mapped name if the unit matches */ | 213 | static const struct usbmix_name_map * |
213 | static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) | 214 | find_map(struct mixer_build *state, int unitid, int control) |
214 | { | 215 | { |
215 | const struct usbmix_name_map *p; | 216 | const struct usbmix_name_map *p = state->map; |
216 | 217 | ||
217 | if (! state->map) | 218 | if (!p) |
218 | return 0; | 219 | return NULL; |
219 | 220 | ||
220 | for (p = state->map; p->id; p++) { | 221 | for (p = state->map; p->id; p++) { |
221 | if (p->id == unitid && p->name && | 222 | if (p->id == unitid && |
222 | (! control || ! p->control || control == p->control)) { | 223 | (!control || !p->control || control == p->control)) |
223 | buflen--; | 224 | return p; |
224 | return strlcpy(buf, p->name, buflen); | ||
225 | } | ||
226 | } | 225 | } |
227 | return 0; | 226 | return NULL; |
228 | } | 227 | } |
229 | 228 | ||
230 | /* check whether the control should be ignored */ | 229 | /* get the mapped name if the unit matches */ |
231 | static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) | 230 | static int |
231 | check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) | ||
232 | { | 232 | { |
233 | const struct usbmix_name_map *p; | 233 | if (!p || !p->name) |
234 | return 0; | ||
234 | 235 | ||
235 | if (! state->map) | 236 | buflen--; |
237 | return strlcpy(buf, p->name, buflen); | ||
238 | } | ||
239 | |||
240 | /* check whether the control should be ignored */ | ||
241 | static inline int | ||
242 | check_ignored_ctl(const struct usbmix_name_map *p) | ||
243 | { | ||
244 | if (!p || p->name || p->dB) | ||
236 | return 0; | 245 | return 0; |
237 | for (p = state->map; p->id; p++) { | 246 | return 1; |
238 | if (p->id == unitid && ! p->name && | 247 | } |
239 | (! control || ! p->control || control == p->control)) { | 248 | |
240 | /* | 249 | /* dB mapping */ |
241 | printk(KERN_DEBUG "ignored control %d:%d\n", | 250 | static inline void check_mapped_dB(const struct usbmix_name_map *p, |
242 | unitid, control); | 251 | struct usb_mixer_elem_info *cval) |
243 | */ | 252 | { |
244 | return 1; | 253 | if (p && p->dB) { |
245 | } | 254 | cval->dBmin = p->dB->min; |
255 | cval->dBmax = p->dB->max; | ||
246 | } | 256 | } |
247 | return 0; | ||
248 | } | 257 | } |
249 | 258 | ||
250 | /* get the mapped selector source name */ | 259 | /* get the mapped selector source name */ |
@@ -481,20 +490,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
481 | 490 | ||
482 | if (size < sizeof(scale)) | 491 | if (size < sizeof(scale)) |
483 | return -ENOMEM; | 492 | return -ENOMEM; |
484 | /* USB descriptions contain the dB scale in 1/256 dB unit | 493 | scale[2] = cval->dBmin; |
485 | * while ALSA TLV contains in 1/100 dB unit | 494 | scale[3] = cval->dBmax; |
486 | */ | ||
487 | scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
488 | scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; | ||
489 | if (scale[3] <= scale[2]) { | ||
490 | /* something is wrong; assume it's either from/to 0dB */ | ||
491 | if (scale[2] < 0) | ||
492 | scale[3] = 0; | ||
493 | else if (scale[2] > 0) | ||
494 | scale[2] = 0; | ||
495 | else /* totally crap, return an error */ | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | if (copy_to_user(_tlv, scale, sizeof(scale))) | 495 | if (copy_to_user(_tlv, scale, sizeof(scale))) |
499 | return -EFAULT; | 496 | return -EFAULT; |
500 | return 0; | 497 | return 0; |
@@ -735,6 +732,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
735 | cval->min = default_min; | 732 | cval->min = default_min; |
736 | cval->max = cval->min + 1; | 733 | cval->max = cval->min + 1; |
737 | cval->res = 1; | 734 | cval->res = 1; |
735 | cval->dBmin = cval->dBmax = 0; | ||
738 | 736 | ||
739 | if (cval->val_type == USB_MIXER_BOOLEAN || | 737 | if (cval->val_type == USB_MIXER_BOOLEAN || |
740 | cval->val_type == USB_MIXER_INV_BOOLEAN) { | 738 | 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 | 800 | ||
803 | cval->initialized = 1; | 801 | cval->initialized = 1; |
804 | } | 802 | } |
803 | |||
804 | /* USB descriptions contain the dB scale in 1/256 dB unit | ||
805 | * while ALSA TLV contains in 1/100 dB unit | ||
806 | */ | ||
807 | cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
808 | cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256; | ||
809 | if (cval->dBmin > cval->dBmax) { | ||
810 | /* something is wrong; assume it's either from/to 0dB */ | ||
811 | if (cval->dBmin < 0) | ||
812 | cval->dBmax = 0; | ||
813 | else if (cval->dBmin > 0) | ||
814 | cval->dBmin = 0; | ||
815 | if (cval->dBmin > cval->dBmax) { | ||
816 | /* totally crap, return an error */ | ||
817 | return -EINVAL; | ||
818 | } | ||
819 | } | ||
820 | |||
805 | return 0; | 821 | return 0; |
806 | } | 822 | } |
807 | 823 | ||
@@ -927,6 +943,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
927 | int nameid = desc[desc[0] - 1]; | 943 | int nameid = desc[desc[0] - 1]; |
928 | struct snd_kcontrol *kctl; | 944 | struct snd_kcontrol *kctl; |
929 | struct usb_mixer_elem_info *cval; | 945 | struct usb_mixer_elem_info *cval; |
946 | const struct usbmix_name_map *map; | ||
930 | 947 | ||
931 | control++; /* change from zero-based to 1-based value */ | 948 | control++; /* change from zero-based to 1-based value */ |
932 | 949 | ||
@@ -935,7 +952,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
935 | return; | 952 | return; |
936 | } | 953 | } |
937 | 954 | ||
938 | if (check_ignored_ctl(state, unitid, control)) | 955 | map = find_map(state, unitid, control); |
956 | if (check_ignored_ctl(map)) | ||
939 | return; | 957 | return; |
940 | 958 | ||
941 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 959 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -969,10 +987,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
969 | } | 987 | } |
970 | kctl->private_free = usb_mixer_elem_free; | 988 | kctl->private_free = usb_mixer_elem_free; |
971 | 989 | ||
972 | len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); | 990 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
973 | mapped_name = len != 0; | 991 | mapped_name = len != 0; |
974 | if (! len && nameid) | 992 | if (! len && nameid) |
975 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); | 993 | len = snd_usb_copy_string_desc(state, nameid, |
994 | kctl->id.name, sizeof(kctl->id.name)); | ||
976 | 995 | ||
977 | switch (control) { | 996 | switch (control) { |
978 | case USB_FEATURE_MUTE: | 997 | case USB_FEATURE_MUTE: |
@@ -1010,6 +1029,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
1010 | kctl->vd[0].access |= | 1029 | kctl->vd[0].access |= |
1011 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 1030 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
1012 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | 1031 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; |
1032 | check_mapped_dB(map, cval); | ||
1013 | } | 1033 | } |
1014 | break; | 1034 | break; |
1015 | 1035 | ||
@@ -1137,8 +1157,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
1137 | unsigned int num_outs = desc[5 + input_pins]; | 1157 | unsigned int num_outs = desc[5 + input_pins]; |
1138 | unsigned int i, len; | 1158 | unsigned int i, len; |
1139 | struct snd_kcontrol *kctl; | 1159 | struct snd_kcontrol *kctl; |
1160 | const struct usbmix_name_map *map; | ||
1140 | 1161 | ||
1141 | if (check_ignored_ctl(state, unitid, 0)) | 1162 | map = find_map(state, unitid, 0); |
1163 | if (check_ignored_ctl(map)) | ||
1142 | return; | 1164 | return; |
1143 | 1165 | ||
1144 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1166 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -1167,7 +1189,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
1167 | } | 1189 | } |
1168 | kctl->private_free = usb_mixer_elem_free; | 1190 | kctl->private_free = usb_mixer_elem_free; |
1169 | 1191 | ||
1170 | len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); | 1192 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1171 | if (! len) | 1193 | if (! len) |
1172 | len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); | 1194 | len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); |
1173 | if (! len) | 1195 | if (! len) |
@@ -1382,6 +1404,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1382 | int i, err, nameid, type, len; | 1404 | int i, err, nameid, type, len; |
1383 | struct procunit_info *info; | 1405 | struct procunit_info *info; |
1384 | struct procunit_value_info *valinfo; | 1406 | struct procunit_value_info *valinfo; |
1407 | const struct usbmix_name_map *map; | ||
1385 | static struct procunit_value_info default_value_info[] = { | 1408 | static struct procunit_value_info default_value_info[] = { |
1386 | { 0x01, "Switch", USB_MIXER_BOOLEAN }, | 1409 | { 0x01, "Switch", USB_MIXER_BOOLEAN }, |
1387 | { 0 } | 1410 | { 0 } |
@@ -1411,7 +1434,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1411 | /* FIXME: bitmap might be longer than 8bit */ | 1434 | /* FIXME: bitmap might be longer than 8bit */ |
1412 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) | 1435 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) |
1413 | continue; | 1436 | continue; |
1414 | if (check_ignored_ctl(state, unitid, valinfo->control)) | 1437 | map = find_map(state, unitid, valinfo->control); |
1438 | if (check_ignored_ctl(map)) | ||
1415 | continue; | 1439 | continue; |
1416 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1440 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
1417 | if (! cval) { | 1441 | if (! cval) { |
@@ -1452,8 +1476,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1452 | } | 1476 | } |
1453 | kctl->private_free = usb_mixer_elem_free; | 1477 | kctl->private_free = usb_mixer_elem_free; |
1454 | 1478 | ||
1455 | if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) | 1479 | if (check_mapped_name(map, kctl->id.name, |
1456 | ; | 1480 | sizeof(kctl->id.name))) |
1481 | /* nothing */ ; | ||
1457 | else if (info->name) | 1482 | else if (info->name) |
1458 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); | 1483 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); |
1459 | else { | 1484 | else { |
@@ -1592,6 +1617,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1592 | int err; | 1617 | int err; |
1593 | struct usb_mixer_elem_info *cval; | 1618 | struct usb_mixer_elem_info *cval; |
1594 | struct snd_kcontrol *kctl; | 1619 | struct snd_kcontrol *kctl; |
1620 | const struct usbmix_name_map *map; | ||
1595 | char **namelist; | 1621 | char **namelist; |
1596 | 1622 | ||
1597 | if (! num_ins || desc[0] < 5 + num_ins) { | 1623 | 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 | if (num_ins == 1) /* only one ? nonsense! */ | 1633 | if (num_ins == 1) /* only one ? nonsense! */ |
1608 | return 0; | 1634 | return 0; |
1609 | 1635 | ||
1610 | if (check_ignored_ctl(state, unitid, 0)) | 1636 | map = find_map(state, unitid, 0); |
1637 | if (check_ignored_ctl(map)) | ||
1611 | return 0; | 1638 | return 0; |
1612 | 1639 | ||
1613 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1640 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -1662,7 +1689,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1662 | kctl->private_free = usb_mixer_selector_elem_free; | 1689 | kctl->private_free = usb_mixer_selector_elem_free; |
1663 | 1690 | ||
1664 | nameid = desc[desc[0] - 1]; | 1691 | nameid = desc[desc[0] - 1]; |
1665 | len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); | 1692 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1666 | if (len) | 1693 | if (len) |
1667 | ; | 1694 | ; |
1668 | else if (nameid) | 1695 | 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 | ||
22 | struct usbmix_dB_map { | ||
23 | u32 min; | ||
24 | u32 max; | ||
25 | }; | ||
22 | 26 | ||
23 | struct usbmix_name_map { | 27 | struct 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 | ||
29 | struct usbmix_selector_map { | 34 | struct 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 | */ |
110 | static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ | ||
111 | static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ | ||
112 | |||
105 | static struct usbmix_name_map mp3plus_map[] = { | 113 | static 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 | }; |