Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-7]: src/sys/arch/arm/broadcom Pull up following revision(s) (requ...
details: https://anonhg.NetBSD.org/src/rev/c819f3226262
branches: netbsd-7
changeset: 799087:c819f3226262
user: snj <snj%NetBSD.org@localhost>
date: Sun Mar 15 22:55:47 2015 +0000
description:
Pull up following revision(s) (requested by jmcneill in ticket #594):
sys/arch/arm/broadcom/bcm2835_vcaudio.c: revision 1.8, 1.9
sys/arch/arm/broadcom/files.bcm2835: revision 1.25
port-arm/49057: Raspberry Pi Audio volume control does not work
- Use software volume control for outputs.master/inputs.dac
- Previous volume control (for analog output only) is available on new
outputs.headphones mixer control.
- Add an outputs.select enum to choose between "auto", "headphones", and
"hdmi" outputs.
--
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 | 191 +++++++++++++++++++++++++++----
sys/arch/arm/broadcom/files.bcm2835 | 4 +-
2 files changed, 165 insertions(+), 30 deletions(-)
diffs (truncated from 318 to 300 lines):
diff -r ab7a60b6b32f -r c819f3226262 sys/arch/arm/broadcom/bcm2835_vcaudio.c
--- a/sys/arch/arm/broadcom/bcm2835_vcaudio.c Sun Mar 15 22:52:18 2015 +0000
+++ b/sys/arch/arm/broadcom/bcm2835_vcaudio.c Sun Mar 15 22:55:47 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: bcm2835_vcaudio.c,v 1.3.4.1 2014/10/19 15:22:00 martin Exp $ */
+/* $NetBSD: bcm2835_vcaudio.c,v 1.3.4.2 2015/03/15 22:55:47 snj 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.3.4.1 2014/10/19 15:22:00 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bcm2835_vcaudio.c,v 1.3.4.2 2015/03/15 22:55:47 snj Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -44,6 +44,7 @@
#include <sys/audioio.h>
#include <dev/audio_if.h>
#include <dev/auconv.h>
+#include <dev/auvolconv.h>
#include <interface/compat/vchi_bsd.h>
#include <interface/vchiq_arm/vchiq_netbsd.h>
@@ -51,13 +52,26 @@
#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,
};
@@ -122,8 +136,10 @@
short sc_peer_version;
- int sc_volume;
+ int sc_hwvol[3];
enum vcaudio_dest sc_dest;
+
+ uint8_t sc_swvol;
};
static int vcaudio_match(device_t, cfdata_t, void *);
@@ -163,6 +179,10 @@
static void vcaudio_get_locks(void *, kmutex_t **, kmutex_t **);
+static stream_filter_t *vcaudio_swvol_filter(struct audio_softc *,
+ const audio_params_t *, const audio_params_t *);
+static void vcaudio_swvol_dtor(stream_filter_t *);
+
static const struct audio_hw_if vcaudio_hw_if = {
.open = vcaudio_open,
.close = vcaudio_close,
@@ -257,7 +277,10 @@
VC_AUDIO_MSG_T msg;
int error;
- sc->sc_volume = 128;
+ sc->sc_swvol = 255;
+ 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;
@@ -342,8 +365,8 @@
memset(&msg, 0, sizeof(msg));
msg.type = VC_AUDIO_MSG_TYPE_CONTROL;
- msg.u.control.volume = vol2pct(sc->sc_volume);
- msg.u.control.dest = VCAUDIO_DEST_AUTO;
+ 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) {
aprint_error_dev(sc->sc_dev,
@@ -585,6 +608,9 @@
AUMODE_PLAY, play, true, pfil);
if (index < 0)
return EINVAL;
+ if (pfil->req_size > 0)
+ play = &pfil->filters[0].param;
+ pfil->prepend(pfil, vcaudio_swvol_filter, play);
}
return 0;
@@ -629,33 +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_volume = 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_volume);
- msg.u.control.dest = VCAUDIO_DEST_AUTO;
-
- 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;
+ 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:
+ 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;
+ return vcaudio_set_volume(sc, mc->un.ord,
+ sc->sc_hwvol[mc->un.ord]);
}
return ENXIO;
}
@@ -670,7 +722,25 @@
case VCAUDIO_INPUT_DAC_VOLUME:
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
- sc->sc_volume;
+ 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_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;
return 0;
}
return ENXIO;
@@ -700,6 +770,33 @@
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:
di->mixer_class = VCAUDIO_INPUT_CLASS;
strcpy(di->label.name, AudioNdac);
@@ -708,6 +805,19 @@
di->un.v.num_channels = 2;
strcpy(di->un.v.units.name, AudioNvolume);
return 0;
+ case VCAUDIO_OUTPUT_SELECT:
+ di->mixer_class = VCAUDIO_OUTPUT_CLASS;
+ strcpy(di->label.name, AudioNselect);
+ di->type = AUDIO_MIXER_ENUM;
+ di->next = di->prev = AUDIO_MIXER_LAST;
+ di->un.e.num_mem = 3;
+ di->un.e.member[0].ord = 0;
+ strcpy(di->un.e.member[0].label.name, "auto");
+ di->un.e.member[1].ord = 1;
+ strcpy(di->un.e.member[1].label.name, AudioNheadphone);
+ di->un.e.member[2].ord = 2;
+ strcpy(di->un.e.member[2].label.name, "hdmi");
+ return 0;
}
return ENXIO;
@@ -786,3 +896,28 @@
*intr = &sc->sc_intr_lock;
*thread = &sc->sc_lock;
}
+
+static stream_filter_t *
+vcaudio_swvol_filter(struct audio_softc *asc,
+ const audio_params_t *from, const audio_params_t *to)
+{
+ auvolconv_filter_t *this;
+ device_t dev = audio_get_device(asc);
+ struct vcaudio_softc *sc = device_private(dev);
+
+ this = kmem_alloc(sizeof(auvolconv_filter_t), KM_SLEEP);
+ this->base.base.fetch_to = auvolconv_slinear16_le_fetch_to;
+ this->base.dtor = vcaudio_swvol_dtor;
+ this->base.set_fetcher = stream_filter_set_fetcher;
+ this->base.set_inputbuffer = stream_filter_set_inputbuffer;
+ this->vol = &sc->sc_swvol;
+
+ return (stream_filter_t *)this;
+}
+
+static void
+vcaudio_swvol_dtor(stream_filter_t *this)
+{
+ if (this)
+ kmem_free(this, sizeof(auvolconv_filter_t));
+}
Home |
Main Index |
Thread Index |
Old Index