aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/tlv.h14
-rw-r--r--sound/core/vmaster.c8
-rw-r--r--sound/usb/usbmixer.c13
3 files changed, 31 insertions, 4 deletions
diff --git a/include/sound/tlv.h b/include/sound/tlv.h
index d136ea2181ed..9fd5b19ccf5c 100644
--- a/include/sound/tlv.h
+++ b/include/sound/tlv.h
@@ -35,6 +35,8 @@
35#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */ 35#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
36#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */ 36#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
37#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */ 37#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
38#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
39#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
38 40
39#define TLV_DB_SCALE_ITEM(min, step, mute) \ 41#define TLV_DB_SCALE_ITEM(min, step, mute) \
40 SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \ 42 SNDRV_CTL_TLVT_DB_SCALE, 2 * sizeof(unsigned int), \
@@ -42,6 +44,18 @@
42#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \ 44#define DECLARE_TLV_DB_SCALE(name, min, step, mute) \
43 unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) } 45 unsigned int name[] = { TLV_DB_SCALE_ITEM(min, step, mute) }
44 46
47/* dB scale specified with min/max values instead of step */
48#define TLV_DB_MINMAX_ITEM(min_dB, max_dB) \
49 SNDRV_CTL_TLVT_DB_MINMAX, 2 * sizeof(unsigned int), \
50 (min_dB), (max_dB)
51#define TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \
52 SNDRV_CTL_TLVT_DB_MINMAX_MUTE, 2 * sizeof(unsigned int), \
53 (min_dB), (max_dB)
54#define DECLARE_TLV_DB_MINMAX(name, min_dB, max_dB) \
55 unsigned int name[] = { TLV_DB_MINMAX_ITEM(min_dB, max_dB) }
56#define DECLARE_TLV_DB_MINMAX_MUTE(name, min_dB, max_dB) \
57 unsigned int name[] = { TLV_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) }
58
45/* linear volume between min_dB and max_dB (.01dB unit) */ 59/* linear volume between min_dB and max_dB (.01dB unit) */
46#define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \ 60#define TLV_DB_LINEAR_ITEM(min_dB, max_dB) \
47 SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \ 61 SNDRV_CTL_TLVT_DB_LINEAR, 2 * sizeof(unsigned int), \
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 257624bd1997..3b9b550109cb 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -353,7 +353,8 @@ static void master_free(struct snd_kcontrol *kcontrol)
353 * 353 *
354 * The optional argument @tlv can be used to specify the TLV information 354 * The optional argument @tlv can be used to specify the TLV information
355 * for dB scale of the master control. It should be a single element 355 * for dB scale of the master control. It should be a single element
356 * with #SNDRV_CTL_TLVT_DB_SCALE type, and should be the max 0dB. 356 * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
357 * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
357 */ 358 */
358struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, 359struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
359 const unsigned int *tlv) 360 const unsigned int *tlv)
@@ -384,7 +385,10 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
384 kctl->private_free = master_free; 385 kctl->private_free = master_free;
385 386
386 /* additional (constant) TLV read */ 387 /* additional (constant) TLV read */
387 if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) { 388 if (tlv &&
389 (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE ||
390 tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX ||
391 tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) {
388 kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 392 kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
389 memcpy(master->tlv, tlv, sizeof(master->tlv)); 393 memcpy(master->tlv, tlv, sizeof(master->tlv));
390 kctl->tlv.p = master->tlv; 394 kctl->tlv.p = master->tlv;
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index ec9cdf986928..df8969188d15 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -461,7 +461,7 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
461 unsigned int size, unsigned int __user *_tlv) 461 unsigned int size, unsigned int __user *_tlv)
462{ 462{
463 struct usb_mixer_elem_info *cval = kcontrol->private_data; 463 struct usb_mixer_elem_info *cval = kcontrol->private_data;
464 DECLARE_TLV_DB_SCALE(scale, 0, 0, 0); 464 DECLARE_TLV_DB_MINMAX(scale, 0, 0);
465 465
466 if (size < sizeof(scale)) 466 if (size < sizeof(scale))
467 return -ENOMEM; 467 return -ENOMEM;
@@ -469,7 +469,16 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
469 * while ALSA TLV contains in 1/100 dB unit 469 * while ALSA TLV contains in 1/100 dB unit
470 */ 470 */
471 scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; 471 scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256;
472 scale[3] = (convert_signed_value(cval, cval->res) * 100) / 256; 472 scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256;
473 if (scale[3] <= scale[2]) {
474 /* something is wrong; assume it's either from/to 0dB */
475 if (scale[2] < 0)
476 scale[3] = 0;
477 else if (scale[2] > 0)
478 scale[2] = 0;
479 else /* totally crap, return an error */
480 return -EINVAL;
481 }
473 if (copy_to_user(_tlv, scale, sizeof(scale))) 482 if (copy_to_user(_tlv, scale, sizeof(scale)))
474 return -EFAULT; 483 return -EFAULT;
475 return 0; 484 return 0;