Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/arm/broadcom port-arm/49057: Raspberry Pi Audio vol...
details: https://anonhg.NetBSD.org/src/rev/098067bedbf2
branches: trunk
changeset: 336738:098067bedbf2
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sun Mar 15 18:31:29 2015 +0000
description:
port-arm/49057: Raspberry Pi Audio volume control does not work
AUDS server messages expect volume to be expressed in units of 1/256 dB,
where we previously (incorrectly) treated it as as percentage. Map the
NetBSD audio level (0-255) to 20 steps (levels from FreeBSD bcm2835_audio.c)
and provide independent volume knobs for outputs.auto, outputs.hdmi, and
outputs.headphones.
diffstat:
sys/arch/arm/broadcom/bcm2835_vcaudio.c | 139 ++++++++++++++++++++-----------
1 files changed, 91 insertions(+), 48 deletions(-)
diffs (237 lines):
diff -r f0033a53d8be -r 098067bedbf2 sys/arch/arm/broadcom/bcm2835_vcaudio.c
--- a/sys/arch/arm/broadcom/bcm2835_vcaudio.c Sun Mar 15 13:15:26 2015 +0000
+++ b/sys/arch/arm/broadcom/bcm2835_vcaudio.c Sun Mar 15 18:31:29 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_vcaudio.c,v 1.8 2015/03/13 22:48:41 jmcneill Exp $ */
+/* $NetBSD: bcm2835_vcaudio.c,v 1.9 2015/03/15 18:31:29 jmcneill Exp $ */
/*-
* Copyright (c) 2013 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.8 2015/03/13 22:48:41 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.9 2015/03/15 18:31:29 jmcneill Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -52,14 +52,25 @@
#include "bcm2835_vcaudioreg.h"
-#define vol2pct(vol) (((vol) * 100) / 255)
+/* levels with 5% volume step */
+static int vcaudio_levels[] = {
+ -10239, -4605, -3794, -3218, -2772,
+ -2407, -2099, -1832, -1597, -1386,
+ -1195, -1021, -861, -713, -575,
+ -446, -325, -210, -102, 0,
+};
+
+#define vol2db(vol) vcaudio_levels[((vol) * 20) >> 8]
+#define vol2vc(vol) ((uint32_t)(-(vol2db((vol)) << 8) / 100))
enum {
VCAUDIO_OUTPUT_CLASS,
VCAUDIO_INPUT_CLASS,
VCAUDIO_OUTPUT_MASTER_VOLUME,
VCAUDIO_INPUT_DAC_VOLUME,
+ VCAUDIO_OUTPUT_AUTO_VOLUME,
VCAUDIO_OUTPUT_HEADPHONE_VOLUME,
+ VCAUDIO_OUTPUT_HDMI_VOLUME,
VCAUDIO_OUTPUT_SELECT,
VCAUDIO_ENUM_LAST,
};
@@ -125,7 +136,7 @@
short sc_peer_version;
- int sc_hpvol;
+ int sc_hwvol[3];
enum vcaudio_dest sc_dest;
uint8_t sc_swvol;
@@ -267,7 +278,9 @@
int error;
sc->sc_swvol = 255;
- sc->sc_hpvol = 128;
+ sc->sc_hwvol[VCAUDIO_DEST_AUTO] = 255;
+ sc->sc_hwvol[VCAUDIO_DEST_HP] = 255;
+ sc->sc_hwvol[VCAUDIO_DEST_HDMI] = 255;
sc->sc_dest = VCAUDIO_DEST_AUTO;
sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD;
@@ -352,7 +365,7 @@
memset(&msg, 0, sizeof(msg));
msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
- msg.u.control.volume = vol2pct(sc->sc_hpvol);
+ msg.u.control.volume = vol2vc(sc->sc_hwvol[sc->sc_dest]);
msg.u.control.dest = sc->sc_dest;
error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
if (error) {
@@ -642,58 +655,59 @@
}
static int
+vcaudio_set_volume(struct vcaudio_softc *sc, enum vcaudio_dest dest,
+ int hwvol)
+{
+ VC_AUDIO_MSG_T msg;
+ int error;
+
+ sc->sc_hwvol[dest] = hwvol;
+ if (dest != sc->sc_dest)
+ return 0;
+
+ vchi_service_use(sc->sc_service);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
+ msg.u.control.volume = vol2vc(hwvol);
+ msg.u.control.dest = dest;
+
+ error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
+ if (error) {
+ device_printf(sc->sc_dev,
+ "couldn't send CONTROL message (%d)\n", error);
+ }
+
+ vchi_service_release(sc->sc_service);
+
+ return error;
+}
+
+static int
vcaudio_set_port(void *priv, mixer_ctrl_t *mc)
{
struct vcaudio_softc *sc = priv;
- VC_AUDIO_MSG_T msg;
- int error;
switch (mc->dev) {
case VCAUDIO_OUTPUT_MASTER_VOLUME:
case VCAUDIO_INPUT_DAC_VOLUME:
sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
return 0;
+ case VCAUDIO_OUTPUT_AUTO_VOLUME:
+ return vcaudio_set_volume(sc, VCAUDIO_DEST_AUTO,
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
case VCAUDIO_OUTPUT_HEADPHONE_VOLUME:
- sc->sc_hpvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
-
- vchi_service_use(sc->sc_service);
-
- memset(&msg, 0, sizeof(msg));
- msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
- msg.u.control.volume = vol2pct(sc->sc_hpvol);
- msg.u.control.dest = sc->sc_dest;
-
- error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
- if (error) {
- device_printf(sc->sc_dev,
- "couldn't send CONTROL message (%d)\n", error);
- }
-
- vchi_service_release(sc->sc_service);
-
- return error;
+ return vcaudio_set_volume(sc, VCAUDIO_DEST_HP,
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
+ case VCAUDIO_OUTPUT_HDMI_VOLUME:
+ return vcaudio_set_volume(sc, VCAUDIO_DEST_HDMI,
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
case VCAUDIO_OUTPUT_SELECT:
if (mc->un.ord < 0 || mc->un.ord > 2)
return EINVAL;
-
sc->sc_dest = mc->un.ord;
-
- vchi_service_use(sc->sc_service);
-
- memset(&msg, 0, sizeof(msg));
- msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
- msg.u.control.volume = vol2pct(sc->sc_hpvol);
- msg.u.control.dest = sc->sc_dest;
-
- error = vcaudio_msg_sync(sc, &msg, sizeof(msg));
- if (error) {
- device_printf(sc->sc_dev,
- "couldn't send CONTROL message (%d)\n", error);
- }
-
- vchi_service_release(sc->sc_service);
-
- return error;
+ return vcaudio_set_volume(sc, mc->un.ord,
+ sc->sc_hwvol[mc->un.ord]);
}
return ENXIO;
}
@@ -702,18 +716,28 @@
vcaudio_get_port(void *priv, mixer_ctrl_t *mc)
{
struct vcaudio_softc *sc = priv;
- uint8_t vol = sc->sc_swvol;
switch (mc->dev) {
case VCAUDIO_OUTPUT_MASTER_VOLUME:
case VCAUDIO_INPUT_DAC_VOLUME:
- mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol;
- mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol;
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
+ mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
+ sc->sc_swvol;
+ return 0;
+ case VCAUDIO_OUTPUT_AUTO_VOLUME:
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
+ mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
+ sc->sc_hwvol[VCAUDIO_DEST_AUTO];
return 0;
case VCAUDIO_OUTPUT_HEADPHONE_VOLUME:
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
- sc->sc_hpvol;
+ sc->sc_hwvol[VCAUDIO_DEST_HP];
+ return 0;
+ case VCAUDIO_OUTPUT_HDMI_VOLUME:
+ mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
+ mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
+ sc->sc_hwvol[VCAUDIO_DEST_HDMI];
return 0;
case VCAUDIO_OUTPUT_SELECT:
mc->un.ord = sc->sc_dest;
@@ -746,12 +770,31 @@
di->un.v.num_channels = 2;
strcpy(di->un.v.units.name, AudioNvolume);
return 0;
+ case VCAUDIO_OUTPUT_AUTO_VOLUME:
+ di->mixer_class = VCAUDIO_OUTPUT_CLASS;
+ strcpy(di->label.name, "auto");
+ di->type = AUDIO_MIXER_VALUE;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ di->un.v.num_channels = 2;
+ di->un.v.delta = 13;
+ strcpy(di->un.v.units.name, AudioNvolume);
+ return 0;
case VCAUDIO_OUTPUT_HEADPHONE_VOLUME:
di->mixer_class = VCAUDIO_OUTPUT_CLASS;
strcpy(di->label.name, AudioNheadphone);
di->type = AUDIO_MIXER_VALUE;
di->next = di->prev = AUDIO_MIXER_LAST;
di->un.v.num_channels = 2;
+ di->un.v.delta = 13;
+ strcpy(di->un.v.units.name, AudioNvolume);
+ return 0;
+ case VCAUDIO_OUTPUT_HDMI_VOLUME:
+ di->mixer_class = VCAUDIO_OUTPUT_CLASS;
+ strcpy(di->label.name, "hdmi");
+ di->type = AUDIO_MIXER_VALUE;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ di->un.v.num_channels = 2;
+ di->un.v.delta = 13;
strcpy(di->un.v.units.name, AudioNvolume);
return 0;
case VCAUDIO_INPUT_DAC_VOLUME:
Home |
Main Index |
Thread Index |
Old Index