diff options
Diffstat (limited to 'sound/usb/usbmixer.c')
-rw-r--r-- | sound/usb/usbmixer.c | 121 |
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 | ||
901 | static 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 | |||
891 | static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | 906 | static 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 | ||
2051 | static 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 | |||
2060 | static 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 | |||
2083 | static 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 | |||
2091 | static 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 | |||
2021 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | 2103 | int 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; |