Pull bugzilla-7897 into release branch
[sfrench/cifs-2.6.git] / sound / usb / usbmixer.c
index 491e975a0c87ef8d2a5a820beba42da61150cdac..7b3bf3545a3bd880cf911d4c39756aac93f1586e 100644 (file)
@@ -37,6 +37,7 @@
 #include <sound/control.h>
 #include <sound/hwdep.h>
 #include <sound/info.h>
+#include <sound/tlv.h>
 
 #include "usbaudio.h"
 
@@ -416,6 +417,26 @@ static inline int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channe
        return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
 }
 
+/*
+ * TLV callback for mixer volume controls
+ */
+static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                        unsigned int size, unsigned int __user *_tlv)
+{
+       struct usb_mixer_elem_info *cval = kcontrol->private_data;
+       DECLARE_TLV_DB_SCALE(scale, 0, 0, 0);
+
+       if (size < sizeof(scale))
+               return -ENOMEM;
+       /* USB descriptions contain the dB scale in 1/256 dB unit
+        * while ALSA TLV contains in 1/100 dB unit
+        */
+       scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
+       scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256;
+       if (copy_to_user(_tlv, scale, sizeof(scale)))
+               return -EFAULT;
+       return 0;
+}
 
 /*
  * parser routines begin here...
@@ -933,6 +954,12 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
                }
                strlcat(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume",
                        sizeof(kctl->id.name));
+               if (control == USB_FEATURE_VOLUME) {
+                       kctl->tlv.c = mixer_vol_tlv;
+                       kctl->vd[0].access |= 
+                               SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                               SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+               }
                break;
 
        default:
@@ -1499,7 +1526,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi
                namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
                if (! namelist[i]) {
                        snd_printk(KERN_ERR "cannot malloc\n");
-                       while (--i > 0)
+                       while (i--)
                                kfree(namelist[i]);
                        kfree(namelist);
                        kfree(cval);
@@ -1593,8 +1620,7 @@ static void snd_usb_mixer_free(struct usb_mixer_interface *mixer)
                kfree(mixer->urb->transfer_buffer);
                usb_free_urb(mixer->urb);
        }
-       if (mixer->rc_urb)
-               usb_free_urb(mixer->rc_urb);
+       usb_free_urb(mixer->rc_urb);
        kfree(mixer->rc_setup_packet);
        kfree(mixer);
 }
@@ -1683,7 +1709,7 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
        }
 }
 
-static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs)
+static void snd_usb_mixer_status_complete(struct urb *urb)
 {
        struct usb_mixer_interface *mixer = urb->context;
 
@@ -1745,8 +1771,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
        return 0;
 }
 
-static void snd_usb_soundblaster_remote_complete(struct urb *urb,
-                                                struct pt_regs *regs)
+static void snd_usb_soundblaster_remote_complete(struct urb *urb)
 {
        struct usb_mixer_interface *mixer = urb->context;
        const struct rc_config *rc = mixer->rc_cfg;
@@ -2030,8 +2055,6 @@ void snd_usb_mixer_disconnect(struct list_head *p)
        struct usb_mixer_interface *mixer;
        
        mixer = list_entry(p, struct usb_mixer_interface, list);
-       if (mixer->urb)
-               usb_kill_urb(mixer->urb);
-       if (mixer->rc_urb)
-               usb_kill_urb(mixer->rc_urb);
+       usb_kill_urb(mixer->urb);
+       usb_kill_urb(mixer->rc_urb);
 }