/* $OpenBSD: sunkbd.c,v 1.25 2009/01/12 21:11:58 miod Exp $ */ /* * Copyright (c) 2002 Jason L. Wright (jason@thought.net) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Effort sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F30602-01-2-0537. * */ #include #include #include #include #include #include #include #ifdef WSDISPLAY_COMPAT_RAWKBD #include #endif #include #include #ifdef __sparc64__ #define NTCTRL 0 #else #include "tctrl.h" #endif #if NTCTRL > 0 #include /* XXX for tadpole_bell() */ #endif void sunkbd_bell(struct sunkbd_softc *, u_int, u_int, u_int); void sunkbd_decode5(u_int8_t, u_int *, int *); int sunkbd_enable(void *, int); int sunkbd_getleds(struct sunkbd_softc *); int sunkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); void sunkbd_rawrepeat(void *); void sunkbd_setleds(void *, int); struct wskbd_accessops sunkbd_accessops = { sunkbd_enable, sunkbd_setleds, sunkbd_ioctl }; void sunkbd_attach(struct sunkbd_softc *sc, struct wskbddev_attach_args *waa) { #ifdef WSDISPLAY_COMPAT_RAWKBD timeout_set(&sc->sc_rawrepeat_tmo, sunkbd_rawrepeat, sc); #endif if (ISTYPE5(sc->sc_layout)) sc->sc_decode = sunkbd_decode5; else sc->sc_decode = sunkbd_decode; sc->sc_wskbddev = config_found((struct device *)sc, waa, wskbddevprint); } void sunkbd_bell(struct sunkbd_softc *sc, u_int period, u_int pitch, u_int volume) { int ticks, s; u_int8_t c = SKBD_CMD_BELLON; #if NTCTRL > 0 if (tadpole_bell(period / 10, pitch, volume) != 0) return; #endif s = spltty(); if (sc->sc_bellactive) { if (sc->sc_belltimeout == 0) timeout_del(&sc->sc_bellto); } if (pitch == 0 || period == 0) { sunkbd_bellstop(sc); splx(s); return; } if (sc->sc_bellactive == 0) { ticks = (period * hz) / 1000; if (ticks <= 0) ticks = 1; sc->sc_bellactive = 1; sc->sc_belltimeout = 1; (*sc->sc_sendcmd)(sc, &c, 1); timeout_add(&sc->sc_bellto, ticks); } splx(s); } void sunkbd_bellstop(void *v) { struct sunkbd_softc *sc = v; int s; u_int8_t c; s = spltty(); sc->sc_belltimeout = 0; c = SKBD_CMD_BELLOFF; (*sc->sc_sendcmd)(v, &c, 1); sc->sc_bellactive = 0; splx(s); } void sunkbd_decode(u_int8_t c, u_int *type, int *value) { switch (c) { case SKBD_RSP_IDLE: *type = WSCONS_EVENT_ALL_KEYS_UP; *value = 0; break; default: *type = (c & 0x80) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; *value = c & 0x7f; break; } } void sunkbd_decode5(u_int8_t c, u_int *type, int *value) { sunkbd_decode(c, type, value); /* * Scancode 0x2d is KS_KP_Equal on type 4, and KS_AudioMute on * type 5. Rather than provide two distinct maps, we remap the * scancode here. */ if (*value == 0x2d) *value = 0x7f; } int sunkbd_enable(void *v, int on) { return (0); } int sunkbd_getleds(struct sunkbd_softc *sc) { return (sc->sc_leds); } void sunkbd_input(struct sunkbd_softc *sc, u_int8_t *buf, u_int buflen) { u_int type; int value; int s; if (sc->sc_wskbddev == NULL) return; /* why bother */ #ifdef WSDISPLAY_COMPAT_RAWKBD if (sc->sc_rawkbd) { u_char rbuf[SUNKBD_MAX_INPUT_SIZE * 2]; int c, rlen, npress; timeout_del(&sc->sc_rawrepeat_tmo); npress = rlen = 0; while (buflen-- != 0) { (*sc->sc_decode)(*buf++, &type, &value); c = sunkbd_rawmap[value]; if (c == RAWKEY_Null) continue; /* fake extended scancode if necessary */ if (c & 0x80) rbuf[rlen++] = 0xe0; rbuf[rlen] = c & 0x7f; if (type == WSCONS_EVENT_KEY_UP) rbuf[rlen] |= 0x80; else { /* remember down keys for autorepeat */ if (c & 0x80) sc->sc_rep[npress++] = 0xe0; sc->sc_rep[npress++] = c & 0x7f; } rlen++; } s = spltty(); wskbd_rawinput(sc->sc_wskbddev, rbuf, rlen); splx(s); sc->sc_nrep = npress; if (npress != 0) timeout_add_msec(&sc->sc_rawrepeat_tmo, REP_DELAY1); } else #endif { s = spltty(); while (buflen-- != 0) { (*sc->sc_decode)(*buf++, &type, &value); wskbd_input(sc->sc_wskbddev, type, value); } splx(s); } } int sunkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { struct sunkbd_softc *sc = v; int *d_int = (int *)data; struct wskbd_bell_data *d_bell = (struct wskbd_bell_data *)data; switch (cmd) { case WSKBDIO_GTYPE: if (ISTYPE5(sc->sc_layout)) { *d_int = WSKBD_TYPE_SUN5; } else { *d_int = WSKBD_TYPE_SUN; } return (0); case WSKBDIO_SETLEDS: sunkbd_setleds(sc, *d_int); return (0); case WSKBDIO_GETLEDS: *d_int = sunkbd_getleds(sc); return (0); case WSKBDIO_COMPLEXBELL: sunkbd_bell(sc, d_bell->period, d_bell->pitch, d_bell->volume); return (0); #ifdef WSDISPLAY_COMPAT_RAWKBD case WSKBDIO_SETMODE: sc->sc_rawkbd = *(int *)data == WSKBD_RAW; timeout_del(&sc->sc_rawrepeat_tmo); return (0); #endif } return (-1); } void sunkbd_raw(struct sunkbd_softc *sc, u_int8_t c) { int claimed = 0; if (sc->sc_kbdstate == SKBD_STATE_LAYOUT) { sc->sc_kbdstate = SKBD_STATE_GETKEY; sc->sc_layout = c; return; } switch (c) { case SKBD_RSP_RESET: sc->sc_kbdstate = SKBD_STATE_RESET; claimed = 1; break; case SKBD_RSP_LAYOUT: sc->sc_kbdstate = SKBD_STATE_LAYOUT; claimed = 1; break; case SKBD_RSP_IDLE: sc->sc_kbdstate = SKBD_STATE_GETKEY; claimed = 1; } if (claimed) return; switch (sc->sc_kbdstate) { case SKBD_STATE_RESET: sc->sc_kbdstate = SKBD_STATE_GETKEY; if (c < KB_SUN2 || c > KB_SUN4) printf("%s: reset: invalid keyboard type 0x%02x\n", sc->sc_dev.dv_xname, c); else sc->sc_id = c; break; case SKBD_STATE_GETKEY: break; } } #ifdef WSDISPLAY_COMPAT_RAWKBD void sunkbd_rawrepeat(void *v) { struct sunkbd_softc *sc = v; int s; s = spltty(); wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); splx(s); timeout_add_msec(&sc->sc_rawrepeat_tmo, REP_DELAYN); } #endif int sunkbd_setclick(struct sunkbd_softc *sc, int click) { u_int8_t c; /* Type 2 keyboards do not support keyclick */ if (sc->sc_id == KB_SUN2) return (ENXIO); c = click ? SKBD_CMD_CLICKON : SKBD_CMD_CLICKOFF; (*sc->sc_sendcmd)(sc, &c, 1); return (0); } void sunkbd_setleds(void *v, int wled) { struct sunkbd_softc *sc = v; u_int8_t sled = 0; u_int8_t cmd[2]; sc->sc_leds = wled; if (wled & WSKBD_LED_CAPS) sled |= SKBD_LED_CAPSLOCK; if (wled & WSKBD_LED_NUM) sled |= SKBD_LED_NUMLOCK; if (wled & WSKBD_LED_SCROLL) sled |= SKBD_LED_SCROLLLOCK; if (wled & WSKBD_LED_COMPOSE) sled |= SKBD_LED_COMPOSE; cmd[0] = SKBD_CMD_SETLED; cmd[1] = sled; (*sc->sc_sendcmd)(sc, cmd, sizeof(cmd)); }