summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormiod <miod@openbsd.org>2006-05-29 20:23:10 +0000
committermiod <miod@openbsd.org>2006-05-29 20:23:10 +0000
commitdc6aea2c41c662de9e656ba10a098edcb7bcf8f6 (patch)
treef3f0573b08bca58af148fa3f1408507a1df23c04 /sys
parentenable lists. (diff)
downloadwireguard-openbsd-dc6aea2c41c662de9e656ba10a098edcb7bcf8f6.tar.xz
wireguard-openbsd-dc6aea2c41c662de9e656ba10a098edcb7bcf8f6.zip
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')
-rw-r--r--sys/dev/audio.c169
-rw-r--r--sys/dev/pckbc/wskbdmap_mfii.c5
-rw-r--r--sys/dev/wscons/files.wscons3
-rw-r--r--sys/dev/wscons/wskbd.c25
-rw-r--r--sys/dev/wscons/wskbd_hotkey.c162
-rw-r--r--sys/dev/wscons/wsksymdef.h6
-rw-r--r--sys/dev/wscons/wsksymvar.h8
7 files changed, 372 insertions, 6 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 */
diff --git a/sys/dev/pckbc/wskbdmap_mfii.c b/sys/dev/pckbc/wskbdmap_mfii.c
index e35197644aa..1be6e1e8f01 100644
--- a/sys/dev/pckbc/wskbdmap_mfii.c
+++ b/sys/dev/pckbc/wskbdmap_mfii.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wskbdmap_mfii.c,v 1.30 2005/05/09 05:08:57 miod Exp $ */
+/* $OpenBSD: wskbdmap_mfii.c,v 1.31 2006/05/29 20:23:13 miod Exp $ */
/* $NetBSD: wskbdmap_mfii.c,v 1.15 2000/05/19 16:40:04 drochner Exp $ */
/*
@@ -141,7 +141,10 @@ static const keysym_t pckbd_keydesc_us[] = {
KC(127), KS_Pause, /* Break */
KC(156), KS_KP_Enter,
KC(157), KS_Cmd1, KS_Control_R,
+ KC(160), KS_AudioMute,
KC(170), KS_Print_Screen,
+ KC(174), KS_AudioLower,
+ KC(176), KS_AudioRaise,
KC(181), KS_KP_Divide,
KC(183), KS_Print_Screen,
KC(184), KS_Cmd2, KS_Alt_R, KS_Multi_key,
diff --git a/sys/dev/wscons/files.wscons b/sys/dev/wscons/files.wscons
index b746e42def4..69718f82d56 100644
--- a/sys/dev/wscons/files.wscons
+++ b/sys/dev/wscons/files.wscons
@@ -1,4 +1,4 @@
-# $OpenBSD: files.wscons,v 1.10 2005/06/02 07:34:14 miod Exp $
+# $OpenBSD: files.wscons,v 1.11 2006/05/29 20:23:13 miod Exp $
# $NetBSD: files.wscons,v 1.34 2005/05/04 01:52:16 augustss Exp $
#
@@ -33,6 +33,7 @@ file dev/wscons/wsevent.c wsdisplay | wskbd |
wsmouse | wsmux
file dev/wscons/wskbd.c wskbd needs-flag
file dev/wscons/wskbdutil.c wskbd
+file dev/wscons/wskbd_hotkey.c wskbd & !small_kernel
file dev/wscons/wsmouse.c wsmouse needs-flag
file dev/rcons/raster_op.c wsrasteremulops
diff --git a/sys/dev/wscons/wskbd.c b/sys/dev/wscons/wskbd.c
index ac472a09a8f..6c6218a2dbd 100644
--- a/sys/dev/wscons/wskbd.c
+++ b/sys/dev/wscons/wskbd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: wskbd.c,v 1.46 2005/08/14 11:00:15 miod Exp $ */
+/* $OpenBSD: wskbd.c,v 1.47 2006/05/29 20:23:13 miod Exp $ */
/* $NetBSD: wskbd.c,v 1.80 2005/05/04 01:52:16 augustss Exp $ */
/*
@@ -82,6 +82,7 @@
#ifndef SMALL_KERNEL
#define BURNER_SUPPORT
#define SCROLLBACK_SUPPORT
+#define HOTKEY_SUPPORT
#endif
#include <sys/param.h>
@@ -110,6 +111,7 @@
#include <dev/wscons/wseventvar.h>
#include <dev/wscons/wscons_callbacks.h>
+#include "audio.h" /* NAUDIO (mixer tuning) */
#include "wsdisplay.h"
#include "wsmux.h"
@@ -429,6 +431,10 @@ wskbd_attach(struct device *parent, struct device *self, void *aux)
sc->sc_base.me_dv.dv_xname, error);
}
#endif
+
+#ifdef HOTKEY_SUPPORT
+ wskbd_hotkey_init();
+#endif
}
void
@@ -1612,6 +1618,23 @@ wskbd_translate(struct wskbd_internal *id, u_int type, int value)
}
}
+#ifdef HOTKEY_SUPPORT
+ /* Submit Audio keys for hotkey processing */
+ if (KS_GROUP(ksym) == KS_GROUP_Function) {
+ switch (ksym) {
+#if NAUDIO > 0
+ case KS_AudioMute:
+ case KS_AudioLower:
+ case KS_AudioRaise:
+ wskbd_hotkey_put(ksym);
+ return (0);
+#endif
+ default:
+ break;
+ }
+ }
+#endif
+
/* Process compose sequence and dead accents */
res = KS_voidSymbol;
diff --git a/sys/dev/wscons/wskbd_hotkey.c b/sys/dev/wscons/wskbd_hotkey.c
new file mode 100644
index 00000000000..ad7e168c185
--- /dev/null
+++ b/sys/dev/wscons/wskbd_hotkey.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2006 Alexey Vatchenko <avv@mail.zp.ua>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Processing of special key symbols.
+ */
+#include "audio.h" /* NAUDIO (mixer tuning) */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kthread.h>
+#include <sys/proc.h>
+
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+
+#define WSKBD_HOTKEY_MAXEVENTS 8
+
+static keysym_t ksym_queue[WSKBD_HOTKEY_MAXEVENTS];
+static u_int queue_head, queue_tail;
+static struct simplelock queue_lock;
+static int wskbd_hotkey_initted = 0;
+
+void init_hotkey_thread(void *);
+void hotkey_thread(void *);
+void process_hotkey(keysym_t);
+int wskbd_hotkey_get(keysym_t *);
+
+#if NAUDIO > 0
+extern int wskbd_set_mixervolume(int dir);
+#endif
+
+/* ARGSUSED */
+void
+init_hotkey_thread(void *ctx)
+{
+ int error;
+
+ error = kthread_create(hotkey_thread, ctx, NULL, "wskbd_hotkey");
+#ifdef DIAGNOSTIC
+ if (error != 0)
+ printf("init_hotkey_thread: cannot create process\n");
+#endif
+}
+
+/* ARGSUSED */
+void
+hotkey_thread(void *ctx)
+{
+ keysym_t sym;
+ int error;
+
+ for (;;) {
+ error = wskbd_hotkey_get(&sym);
+ if (error == 0)
+ process_hotkey(sym);
+ else
+ (void) tsleep(ksym_queue, PZERO, "wait", 0);
+ }
+
+ /* NOTREACHED */
+}
+
+void
+process_hotkey(keysym_t sym)
+{
+ /* Process Audio tuning keys */
+ switch (sym) {
+#if NAUDIO > 0
+ case KS_AudioMute:
+ (void) wskbd_set_mixervolume(0);
+ break;
+ case KS_AudioLower:
+ (void) wskbd_set_mixervolume(-1);
+ break;
+ case KS_AudioRaise:
+ (void) wskbd_set_mixervolume(1);
+ break;
+#endif
+ default:
+#ifdef DEBUG
+ printf("process_hotkey: unsupported hotkey\n");
+#endif
+ break;
+ }
+}
+
+void
+wskbd_hotkey_init(void)
+{
+
+ if (wskbd_hotkey_initted == 0) {
+ simple_lock_init(&queue_lock);
+ queue_head = queue_tail = 0;
+ kthread_create_deferred(init_hotkey_thread, NULL);
+ wskbd_hotkey_initted = 1;
+ }
+}
+
+void
+wskbd_hotkey_put(keysym_t sym)
+{
+ int s, changed;
+ u_int nxtpos;
+
+ changed = 0;
+
+ s = spltty();
+ simple_lock(&queue_lock);
+
+ nxtpos = (queue_head + 1) % WSKBD_HOTKEY_MAXEVENTS;
+ if (nxtpos != queue_tail) {
+ ksym_queue[queue_head] = sym;
+ queue_head = nxtpos;
+ changed = 1;
+ }
+#ifdef DEBUG
+ else
+ printf("wskbd_hotkey_put: losing hotkey\n");
+#endif
+
+ simple_unlock(&queue_lock);
+ splx(s);
+
+ if (changed != 0)
+ wakeup(ksym_queue);
+}
+
+int
+wskbd_hotkey_get(keysym_t *sym)
+{
+ int s, error;
+
+ s = spltty();
+ simple_lock(&queue_lock);
+
+ error = 0;
+
+ if (queue_head != queue_tail) {
+ *sym = ksym_queue[queue_tail];
+ queue_tail = (queue_tail + 1) % WSKBD_HOTKEY_MAXEVENTS;
+ } else
+ error = EAGAIN;
+
+ simple_unlock(&queue_lock);
+ splx(s);
+
+ return (error);
+}
diff --git a/sys/dev/wscons/wsksymdef.h b/sys/dev/wscons/wsksymdef.h
index a61c39d04c9..af4ee0759f0 100644
--- a/sys/dev/wscons/wsksymdef.h
+++ b/sys/dev/wscons/wsksymdef.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsksymdef.h,v 1.29 2006/05/19 20:55:05 miod Exp $ */
+/* $OpenBSD: wsksymdef.h,v 1.30 2006/05/29 20:23:13 miod Exp $ */
/* $NetBSD: wsksymdef.h,v 1.34.4.1 2000/07/07 09:49:54 hannken Exp $ */
/*-
@@ -629,6 +629,10 @@
#define KS_Pause 0xf3c1
#define KS_Print_Screen 0xf3c2
+#define KS_AudioMute 0xf3d1
+#define KS_AudioLower 0xf3d2
+#define KS_AudioRaise 0xf3d3
+
/*
* Group 4 (command)
*/
diff --git a/sys/dev/wscons/wsksymvar.h b/sys/dev/wscons/wsksymvar.h
index 07dcc77fc17..544a4a4cf6f 100644
--- a/sys/dev/wscons/wsksymvar.h
+++ b/sys/dev/wscons/wsksymvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wsksymvar.h,v 1.4 2002/03/14 01:27:03 millert Exp $ */
+/* $OpenBSD: wsksymvar.h,v 1.5 2006/05/29 20:23:13 miod Exp $ */
/* $NetBSD: wsksymvar.h,v 1.8.4.1 2000/07/07 09:50:21 hannken Exp $ */
/*-
@@ -79,6 +79,12 @@ int wskbd_load_keymap(const struct wskbd_mapdata *,
struct wscons_keymap **, int *);
keysym_t wskbd_compose_value(keysym_t *);
+/*
+ * keysym_t hotkey functions.
+ */
+void wskbd_hotkey_init(void);
+void wskbd_hotkey_put(keysym_t);
+
#endif
#endif /* !_DEV_WSCONS_WSKSYMVAR_H_ */