aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/usbmixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/usbmixer.c')
-rw-r--r--sound/usb/usbmixer.c121
1 files changed, 105 insertions, 16 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 4bd3a7a0edc1..9efcfd08d747 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -86,6 +86,7 @@ struct usb_mixer_interface {
86 u8 rc_buffer[6]; 86 u8 rc_buffer[6];
87 87
88 u8 audigy2nx_leds[3]; 88 u8 audigy2nx_leds[3];
89 u8 xonar_u1_status;
89}; 90};
90 91
91 92
@@ -461,7 +462,7 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
461 unsigned int size, unsigned int __user *_tlv) 462 unsigned int size, unsigned int __user *_tlv)
462{ 463{
463 struct usb_mixer_elem_info *cval = kcontrol->private_data; 464 struct usb_mixer_elem_info *cval = kcontrol->private_data;
464 DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); 465 DECLARE_TLV_DB_MINMAX(scale, 0, 0);
465 466
466 if (size < sizeof(scale)) 467 if (size < sizeof(scale))
467 return -ENOMEM; 468 return -ENOMEM;
@@ -469,7 +470,16 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
469 * while ALSA TLV contains in 1/100 dB unit 470 * while ALSA TLV contains in 1/100 dB unit
470 */ 471 */
471 scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; 472 scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
472 scale[3] = (convert_signed_value(cval, cval->res) * 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 }
473 if (copy_to_user(_tlv, scale, sizeof(scale))) 483 if (copy_to_user(_tlv, scale, sizeof(scale)))
474 return -EFAULT; 484 return -EFAULT;
475 return 0; 485 return 0;
@@ -888,6 +898,11 @@ static struct snd_kcontrol_new usb_feature_unit_ctl = {
888 * build a feature control 898 * build a feature control
889 */ 899 */
890 900
901static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
902{
903 return strlcat(kctl->id.name, str, sizeof(kctl->id.name));
904}
905
891static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, 906static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
892 unsigned int ctl_mask, int control, 907 unsigned int ctl_mask, int control,
893 struct usb_audio_term *iterm, int unitid) 908 struct usb_audio_term *iterm, int unitid)
@@ -968,13 +983,13 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
968 */ 983 */
969 if (! mapped_name && ! (state->oterm.type >> 16)) { 984 if (! mapped_name && ! (state->oterm.type >> 16)) {
970 if ((state->oterm.type & 0xff00) == 0x0100) { 985 if ((state->oterm.type & 0xff00) == 0x0100) {
971 len = strlcat(kctl->id.name, " Capture", sizeof(kctl->id.name)); 986 len = append_ctl_name(kctl, " Capture");
972 } else { 987 } else {
973 len = strlcat(kctl->id.name + len, " Playback", sizeof(kctl->id.name)); 988 len = append_ctl_name(kctl, " Playback");
974 } 989 }
975 } 990 }
976 strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume", 991 append_ctl_name(kctl, control == USB_FEATURE_MUTE ?
977 sizeof(kctl->id.name)); 992 " Switch" : " Volume");
978 if (control == USB_FEATURE_VOLUME) { 993 if (control == USB_FEATURE_VOLUME) {
979 kctl->tlv.c = mixer_vol_tlv; 994 kctl->tlv.c = mixer_vol_tlv;
980 kctl->vd[0].access |= 995 kctl->vd[0].access |=
@@ -990,20 +1005,35 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
990 break; 1005 break;
991 } 1006 }
992 1007
993 /* quirk for UDA1321/N101 */ 1008 /* volume control quirks */
994 /* note that detection between firmware 2.1.1.7 (N101) and later 2.1.1.21 */
995 /* is not very clear from datasheets */
996 /* I hope that the min value is -15360 for newer firmware --jk */
997 switch (state->chip->usb_id) { 1009 switch (state->chip->usb_id) {
998 case USB_ID(0x0471, 0x0101): 1010 case USB_ID(0x0471, 0x0101):
999 case USB_ID(0x0471, 0x0104): 1011 case USB_ID(0x0471, 0x0104):
1000 case USB_ID(0x0471, 0x0105): 1012 case USB_ID(0x0471, 0x0105):
1001 case USB_ID(0x0672, 0x1041): 1013 case USB_ID(0x0672, 0x1041):
1014 /* quirk for UDA1321/N101.
1015 * note that detection between firmware 2.1.1.7 (N101)
1016 * and later 2.1.1.21 is not very clear from datasheets.
1017 * I hope that the min value is -15360 for newer firmware --jk
1018 */
1002 if (!strcmp(kctl->id.name, "PCM Playback Volume") && 1019 if (!strcmp(kctl->id.name, "PCM Playback Volume") &&
1003 cval->min == -15616) { 1020 cval->min == -15616) {
1004 snd_printk(KERN_INFO "using volume control quirk for the UDA1321/N101 chip\n"); 1021 snd_printk(KERN_INFO
1022 "set volume quirk for UDA1321/N101 chip\n");
1005 cval->max = -256; 1023 cval->max = -256;
1006 } 1024 }
1025 break;
1026
1027 case USB_ID(0x046d, 0x09a4):
1028 if (!strcmp(kctl->id.name, "Mic Capture Volume")) {
1029 snd_printk(KERN_INFO
1030 "set volume quirk for QuickCam E3500\n");
1031 cval->min = 6080;
1032 cval->max = 8768;
1033 cval->res = 192;
1034 }
1035 break;
1036
1007 } 1037 }
1008 1038
1009 snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", 1039 snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
@@ -1118,7 +1148,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
1118 len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); 1148 len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0);
1119 if (! len) 1149 if (! len)
1120 len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); 1150 len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1);
1121 strlcat(kctl->id.name + len, " Volume", sizeof(kctl->id.name)); 1151 append_ctl_name(kctl, " Volume");
1122 1152
1123 snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n", 1153 snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
1124 cval->id, kctl->id.name, cval->channels, cval->min, cval->max); 1154 cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
@@ -1375,8 +1405,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned
1375 if (! len) 1405 if (! len)
1376 strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); 1406 strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
1377 } 1407 }
1378 strlcat(kctl->id.name, " ", sizeof(kctl->id.name)); 1408 append_ctl_name(kctl, " ");
1379 strlcat(kctl->id.name, valinfo->suffix, sizeof(kctl->id.name)); 1409 append_ctl_name(kctl, valinfo->suffix);
1380 1410
1381 snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", 1411 snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
1382 cval->id, kctl->id.name, cval->channels, cval->min, cval->max); 1412 cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
@@ -1585,9 +1615,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
1585 strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); 1615 strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
1586 1616
1587 if ((state->oterm.type & 0xff00) == 0x0100) 1617 if ((state->oterm.type & 0xff00) == 0x0100)
1588 strlcat(kctl->id.name, " Capture Source", sizeof(kctl->id.name)); 1618 append_ctl_name(kctl, " Capture Source");
1589 else 1619 else
1590 strlcat(kctl->id.name, " Playback Source", sizeof(kctl->id.name)); 1620 append_ctl_name(kctl, " Playback Source");
1591 } 1621 }
1592 1622
1593 snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", 1623 snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
@@ -2018,6 +2048,58 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
2018 } 2048 }
2019} 2049}
2020 2050
2051static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
2052 struct snd_ctl_elem_value *ucontrol)
2053{
2054 struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
2055
2056 ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
2057 return 0;
2058}
2059
2060static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
2061 struct snd_ctl_elem_value *ucontrol)
2062{
2063 struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
2064 u8 old_status, new_status;
2065 int err, changed;
2066
2067 old_status = mixer->xonar_u1_status;
2068 if (ucontrol->value.integer.value[0])
2069 new_status = old_status | 0x02;
2070 else
2071 new_status = old_status & ~0x02;
2072 changed = new_status != old_status;
2073 err = snd_usb_ctl_msg(mixer->chip->dev,
2074 usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
2075 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
2076 50, 0, &new_status, 1, 100);
2077 if (err < 0)
2078 return err;
2079 mixer->xonar_u1_status = new_status;
2080 return changed;
2081}
2082
2083static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
2084 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2085 .name = "Digital Playback Switch",
2086 .info = snd_ctl_boolean_mono_info,
2087 .get = snd_xonar_u1_switch_get,
2088 .put = snd_xonar_u1_switch_put,
2089};
2090
2091static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
2092{
2093 int err;
2094
2095 err = snd_ctl_add(mixer->chip->card,
2096 snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
2097 if (err < 0)
2098 return err;
2099 mixer->xonar_u1_status = 0x05;
2100 return 0;
2101}
2102
2021int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, 2103int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
2022 int ignore_error) 2104 int ignore_error)
2023{ 2105{
@@ -2060,6 +2142,13 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
2060 snd_audigy2nx_proc_read); 2142 snd_audigy2nx_proc_read);
2061 } 2143 }
2062 2144
2145 if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) ||
2146 mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) {
2147 err = snd_xonar_u1_controls_create(mixer);
2148 if (err < 0)
2149 goto _error;
2150 }
2151
2063 err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); 2152 err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops);
2064 if (err < 0) 2153 if (err < 0)
2065 goto _error; 2154 goto _error;