diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2006-05-29 20:23:14 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2006-05-29 20:23:14 +0000 |
commit | 286c2bdbdf6b926fab7e57f77cbce263c0f5f1c2 (patch) | |
tree | 792f5442439ff9f581370324be7709c7a0087680 /sys/dev/audio.c | |
parent | 2a1119bdf41232e0fe0fe1f92771c4546b3d61a1 (diff) |
Add support for the audio volume keys found on many laptops' builtin
keyboard. These specific keys are posted to a kernel thread which will
issue mixer commands if an audio device exists.
Written by Alexey Vatchenko <avv , mail zp ua> with tweaks by deraadt@ and I.
Diffstat (limited to 'sys/dev/audio.c')
-rw-r--r-- | sys/dev/audio.c | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/sys/dev/audio.c b/sys/dev/audio.c index 7ceb6743ca7..69d15fdb1da 100644 --- a/sys/dev/audio.c +++ b/sys/dev/audio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: audio.c,v 1.49 2006/03/12 10:34:50 jakemsr Exp $ */ +/* $OpenBSD: audio.c,v 1.50 2006/05/29 20:23:13 miod Exp $ */ /* $NetBSD: audio.c,v 1.119 1999/11/09 16:50:47 augustss Exp $ */ /* @@ -87,6 +87,8 @@ #include <machine/endian.h> +#include "wskbd.h" /* NWSKBD (mixer tuning using keyboard) */ + #ifdef AUDIO_DEBUG #define DPRINTF(x) if (audiodebug) printf x #define DPRINTFN(n,x) if (audiodebug>(n)) printf x @@ -208,6 +210,12 @@ int filt_audioread(struct knote *kn, long hint); struct filterops audioread_filtops = { 1, NULL, filt_audiordetach, filt_audioread}; +#if NWSKBD > 0 +/* Mixer manipulation using keyboard */ +int wskbd_get_mixerdev(struct audio_softc *sc, int dir, int *index); +int wskbd_set_mixervolume(int dir); +#endif + int audioprobe(parent, match, aux) struct device *parent; @@ -3096,3 +3104,162 @@ filt_audiowrite(struct knote *kn, long hint) return AUDIO_FILTWRITE(sc); } + +#if NAUDIO > 0 && NWSKBD > 0 +int +wskbd_get_mixerdev(struct audio_softc *sc, int dir, int *index) +{ + mixer_devinfo_t mi; + int mixer_class; + int error; + + /* looking for ``outputs'' */ + for (mi.index = 0; ; mi.index++) { + error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi); + if (error != 0) + return (-1); + + if (mi.type == AUDIO_MIXER_CLASS && + strcmp(mi.label.name, AudioCoutputs) == 0) { + mixer_class = mi.mixer_class; + break; + } + } + + /* + * looking for ``outputs.master'' + * start mi.index from 0 because ''outputs.master'' can precede + * ''outputs''. + */ + for (mi.index = 0; ; mi.index++) { + error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi); + if (error != 0) + return (-1); + + if (mi.type == AUDIO_MIXER_VALUE && + mi.mixer_class == mixer_class && + strcmp(mi.label.name, AudioNmaster) == 0) { + if (dir == 0) { + /* looking for ``outputs.master.mute'' */ + if (mi.next < 0) + return (-1); + + mi.index = mi.next; + error = sc->hw_if->query_devinfo(sc->hw_hdl, + &mi); + if (error != 0) + return (-1); + + if (mi.type != AUDIO_MIXER_ENUM || + strcmp(mi.label.name, AudioNmute) != 0) + return (-1); + } + + *index = mi.index; + return (0); + } + } + + return (-1); +} + +int +wskbd_set_mixervolume(int dir) +{ + struct audio_softc *sc; + mixer_devinfo_t mi; + mixer_ctrl_t ct; + int l, r; + int error; + + if (audio_cd.cd_ndevs == 0 || (sc = audio_cd.cd_devs[0]) == NULL) { + DPRINTF(("wskbd_set_mixervolume: audio_cd\n")); + return (ENXIO); + } + + error = wskbd_get_mixerdev(sc, dir, &ct.dev); + if (error == -1) { + DPRINTF(("wskbd_set_mixervolume: wskbd_get_mixerdev\n")); + return (ENXIO); + } + + if (dir == 0) { + /* + * Mute. + * Use mixer_ioctl() for writing. It does many things for us. + */ + ct.type = AUDIO_MIXER_ENUM; + error = sc->hw_if->get_port(sc->hw_hdl, &ct); + if (error != 0) { + DPRINTF(("wskbd_set_mixervolume:" + " get_port: %d\n", error)); + return (error); + } + + ct.un.ord = !ct.un.ord; /* toggle */ + + error = mixer_ioctl(MIXER_DEVICE, + AUDIO_MIXER_WRITE, (caddr_t)&ct, FWRITE, curproc); + if (error != 0) { + DPRINTF(("wskbd_set_mixervolume:" + " mixer_ioctl: %d\n", error)); + return (error); + } + } else { + mi.index = ct.dev; + error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi); + if (error != 0) { + DPRINTF(("wskbd_set_mixervolume:" + " query_devinfo: %d\n", error)); + return (error); + } + + ct.type = AUDIO_MIXER_VALUE; + + error = au_get_lr_value(sc, &ct, &l, &r); + if (error != 0) { + DPRINTF(("wskbd_set_mixervolume:" + " au_get_lr_value: %d\n", error)); + return (error); + } + + if (dir > 0) { + /* + * Raise volume + */ + if (l > AUDIO_MAX_GAIN - mi.un.v.delta) + l = AUDIO_MAX_GAIN; + else + l += mi.un.v.delta; + + if (r > AUDIO_MAX_GAIN - mi.un.v.delta) + r = AUDIO_MAX_GAIN; + else + r += mi.un.v.delta; + + } else { + /* + * Lower volume + */ + if (l < AUDIO_MIN_GAIN + mi.un.v.delta) + l = AUDIO_MIN_GAIN; + else + l -= mi.un.v.delta; + + if (r < AUDIO_MIN_GAIN + mi.un.v.delta) + r = AUDIO_MIN_GAIN; + else + r -= mi.un.v.delta; + } + + error = au_set_lr_value(sc, &ct, l, r); + if (error != 0) { + DPRINTF(("wskbd_set_mixervolume:" + " au_set_lr_value: %d\n", error)); + return (error); + } + } + + return (0); +} +#endif /* NAUDIO > 0 && NWSKBD > 0 */ |