diff options
author | 2006-05-29 20:23:10 +0000 | |
---|---|---|
committer | 2006-05-29 20:23:10 +0000 | |
commit | dc6aea2c41c662de9e656ba10a098edcb7bcf8f6 (patch) | |
tree | f3f0573b08bca58af148fa3f1408507a1df23c04 /sys | |
parent | enable lists. (diff) | |
download | wireguard-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.c | 169 | ||||
-rw-r--r-- | sys/dev/pckbc/wskbdmap_mfii.c | 5 | ||||
-rw-r--r-- | sys/dev/wscons/files.wscons | 3 | ||||
-rw-r--r-- | sys/dev/wscons/wskbd.c | 25 | ||||
-rw-r--r-- | sys/dev/wscons/wskbd_hotkey.c | 162 | ||||
-rw-r--r-- | sys/dev/wscons/wsksymdef.h | 6 | ||||
-rw-r--r-- | sys/dev/wscons/wsksymvar.h | 8 |
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_ */ |