diff options
Diffstat (limited to 'sound/usb/usbmixer.c')
-rw-r--r-- | sound/usb/usbmixer.c | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ec9cdf986928..ab5a3ac2ac47 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; |
@@ -2033,6 +2043,58 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, | |||
2033 | } | 2043 | } |
2034 | } | 2044 | } |
2035 | 2045 | ||
2046 | static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol, | ||
2047 | struct snd_ctl_elem_value *ucontrol) | ||
2048 | { | ||
2049 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
2050 | |||
2051 | ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02); | ||
2052 | return 0; | ||
2053 | } | ||
2054 | |||
2055 | static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol, | ||
2056 | struct snd_ctl_elem_value *ucontrol) | ||
2057 | { | ||
2058 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
2059 | u8 old_status, new_status; | ||
2060 | int err, changed; | ||
2061 | |||
2062 | old_status = mixer->xonar_u1_status; | ||
2063 | if (ucontrol->value.integer.value[0]) | ||
2064 | new_status = old_status | 0x02; | ||
2065 | else | ||
2066 | new_status = old_status & ~0x02; | ||
2067 | changed = new_status != old_status; | ||
2068 | err = snd_usb_ctl_msg(mixer->chip->dev, | ||
2069 | usb_sndctrlpipe(mixer->chip->dev, 0), 0x08, | ||
2070 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, | ||
2071 | 50, 0, &new_status, 1, 100); | ||
2072 | if (err < 0) | ||
2073 | return err; | ||
2074 | mixer->xonar_u1_status = new_status; | ||
2075 | return changed; | ||
2076 | } | ||
2077 | |||
2078 | static struct snd_kcontrol_new snd_xonar_u1_output_switch = { | ||
2079 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2080 | .name = "Digital Playback Switch", | ||
2081 | .info = snd_ctl_boolean_mono_info, | ||
2082 | .get = snd_xonar_u1_switch_get, | ||
2083 | .put = snd_xonar_u1_switch_put, | ||
2084 | }; | ||
2085 | |||
2086 | static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) | ||
2087 | { | ||
2088 | int err; | ||
2089 | |||
2090 | err = snd_ctl_add(mixer->chip->card, | ||
2091 | snd_ctl_new1(&snd_xonar_u1_output_switch, mixer)); | ||
2092 | if (err < 0) | ||
2093 | return err; | ||
2094 | mixer->xonar_u1_status = 0x05; | ||
2095 | return 0; | ||
2096 | } | ||
2097 | |||
2036 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | 2098 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, |
2037 | int ignore_error) | 2099 | int ignore_error) |
2038 | { | 2100 | { |
@@ -2075,6 +2137,13 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2075 | snd_audigy2nx_proc_read); | 2137 | snd_audigy2nx_proc_read); |
2076 | } | 2138 | } |
2077 | 2139 | ||
2140 | if (mixer->chip->usb_id == USB_ID(0x0b05, 0x1739) || | ||
2141 | mixer->chip->usb_id == USB_ID(0x0b05, 0x1743)) { | ||
2142 | err = snd_xonar_u1_controls_create(mixer); | ||
2143 | if (err < 0) | ||
2144 | goto _error; | ||
2145 | } | ||
2146 | |||
2078 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); | 2147 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); |
2079 | if (err < 0) | 2148 | if (err < 0) |
2080 | goto _error; | 2149 | goto _error; |