diff options
-rw-r--r-- | include/sound/tlv.h | 14 | ||||
-rw-r--r-- | sound/core/vmaster.c | 8 | ||||
-rw-r--r-- | sound/usb/usbmixer.c | 13 |
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 | */ |
358 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | 359 | struct 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; |