]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'topic/tlv-minmax' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Thu, 10 Sep 2009 13:33:06 +0000 (15:33 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 10 Sep 2009 13:33:06 +0000 (15:33 +0200)
* topic/tlv-minmax:
  ALSA: usb-audio - Correct bogus volume dB information
  ALSA: usb-audio - Use the new TLV_DB_MINMAX type
  ALSA: Add new TLV types for dBwith min/max

include/sound/tlv.h
sound/core/vmaster.c
sound/usb/usbmixer.c

index d136ea2181ed4f2fc0b92dd25b7cd0ac8e6c2860..9fd5b19ccf5c05a7002440588041e49b3e9a8e18 100644 (file)
@@ -35,6 +35,8 @@
 #define SNDRV_CTL_TLVT_DB_SCALE        1       /* dB scale */
 #define SNDRV_CTL_TLVT_DB_LINEAR 2     /* linear volume */
 #define SNDRV_CTL_TLVT_DB_RANGE 3      /* dB range container */
+#define SNDRV_CTL_TLVT_DB_MINMAX 4     /* dB scale with min/max */
+#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5        /* dB scale with min/max with mute */
 
 #define TLV_DB_SCALE_ITEM(min, step, mute)                     \
        SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int),      \
 #define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
        unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
 
+/* dB scale specified with min/max values instead of step */
+#define TLV_DB_MINMAX_ITEM(min_dB, max_dB)                     \
+       SNDRV_CTL_TLVT_DB_MINMAX, 2 * sizeof(unsigned int),     \
+       (min_dB), (max_dB)
+#define TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB)                        \
+       SNDRV_CTL_TLVT_DB_MINMAX_MUTE, 2 * sizeof(unsigned int),        \
+       (min_dB), (max_dB)
+#define DECLARE_TLV_DB_MINMAX(name, min_dB, max_dB) \
+       unsigned int name[] = { TLV_DB_MINMAX_ITEM(min_dB, max_dB) }
+#define DECLARE_TLV_DB_MINMAX_MUTE(name, min_dB, max_dB) \
+       unsigned int name[] = { TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) }
+
 /* linear volume between min_dB and max_dB (.01dB unit) */
 #define TLV_DB_LINEAR_ITEM(min_dB, max_dB)                 \
        SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
index 257624bd199776c37ecc01815fd377e3150ac3ec..3b9b550109cb9fe4e59b60db5ee436546029867c 100644 (file)
@@ -353,7 +353,8 @@ static void master_free(struct snd_kcontrol *kcontrol)
  *
  * The optional argument @tlv can be used to specify the TLV information
  * for dB scale of the master control.  It should be a single element
- * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB.
+ * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
+ * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
  */
 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
                                                 const unsigned int *tlv)
@@ -384,7 +385,10 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
        kctl->private_free = master_free;
 
        /* additional (constant) TLV read */
-       if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
+       if (tlv &&
+           (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE ||
+            tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX ||
+            tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) {
                kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
                memcpy(master->tlv, tlv, sizeof(master->tlv));
                kctl->tlv.p = master->tlv;
index ec9cdf986928cfd1ce1847b18e111fdb71552fba..df8969188d158d7217f9951f9173954d16c91d38 100644 (file)
@@ -461,7 +461,7 @@ 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);
+       DECLARE_TLV_DB_MINMAX(scale, 0, 0);
 
        if (size < sizeof(scale))
                return -ENOMEM;
@@ -469,7 +469,16 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
         * 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;
+       scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
+       if (scale[3] <= scale[2]) {
+               /* something is wrong; assume it's either from/to 0dB */
+               if (scale[2] < 0)
+                       scale[3] = 0;
+               else if (scale[2] > 0)
+                       scale[2] = 0;
+               else /* totally crap, return an error */
+                       return -EINVAL;
+       }
        if (copy_to_user(_tlv, scale, sizeof(scale)))
                return -EFAULT;
        return 0;