jcs's openbsd hax
openbsd
at jcs 325 lines 7.3 kB view raw
1/* $OpenBSD: sunkbd.c,v 1.28 2020/04/06 19:03:09 cheloha Exp $ */ 2 3/* 4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Effort sponsored in part by the Defense Advanced Research Projects 29 * Agency (DARPA) and Air Force Research Laboratory, Air Force 30 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 31 * 32 */ 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/device.h> 37#include <sys/kernel.h> 38#include <sys/timeout.h> 39 40#include <dev/wscons/wsconsio.h> 41#include <dev/wscons/wskbdvar.h> 42#ifdef WSDISPLAY_COMPAT_RAWKBD 43#include <dev/wscons/wskbdraw.h> 44#endif 45 46#include <dev/sun/sunkbdreg.h> 47#include <dev/sun/sunkbdvar.h> 48 49#ifdef __sparc64__ 50#define NTCTRL 0 51#else 52#include "tctrl.h" 53#endif 54 55#if NTCTRL > 0 56#include <sparc/dev/tctrlvar.h> /* XXX for tadpole_bell() */ 57#endif 58 59void sunkbd_bell(struct sunkbd_softc *, u_int, u_int, u_int); 60void sunkbd_decode5(u_int8_t, u_int *, int *); 61int sunkbd_enable(void *, int); 62int sunkbd_getleds(struct sunkbd_softc *); 63int sunkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 64void sunkbd_setleds(void *, int); 65 66struct wskbd_accessops sunkbd_accessops = { 67 sunkbd_enable, 68 sunkbd_setleds, 69 sunkbd_ioctl 70}; 71 72void 73sunkbd_attach(struct sunkbd_softc *sc, struct wskbddev_attach_args *waa) 74{ 75 if (ISTYPE5(sc->sc_layout)) 76 sc->sc_decode = sunkbd_decode5; 77 else 78 sc->sc_decode = sunkbd_decode; 79 80 sc->sc_wskbddev = config_found((struct device *)sc, waa, 81 wskbddevprint); 82} 83 84void 85sunkbd_bell(struct sunkbd_softc *sc, u_int period, u_int pitch, u_int volume) 86{ 87 int s; 88 u_int8_t c = SKBD_CMD_BELLON; 89 90#if NTCTRL > 0 91 if (tadpole_bell(period / 10, pitch, volume) != 0) 92 return; 93#endif 94 95 s = spltty(); 96 if (sc->sc_bellactive) { 97 if (sc->sc_belltimeout == 0) 98 timeout_del(&sc->sc_bellto); 99 } 100 if (pitch == 0 || period == 0) { 101 sunkbd_bellstop(sc); 102 splx(s); 103 return; 104 } 105 if (sc->sc_bellactive == 0) { 106 sc->sc_bellactive = 1; 107 sc->sc_belltimeout = 1; 108 (*sc->sc_sendcmd)(sc, &c, 1); 109 timeout_add_msec(&sc->sc_bellto, period); 110 } 111 splx(s); 112} 113 114void 115sunkbd_bellstop(void *v) 116{ 117 struct sunkbd_softc *sc = v; 118 int s; 119 u_int8_t c; 120 121 s = spltty(); 122 sc->sc_belltimeout = 0; 123 c = SKBD_CMD_BELLOFF; 124 (*sc->sc_sendcmd)(v, &c, 1); 125 sc->sc_bellactive = 0; 126 splx(s); 127} 128 129void 130sunkbd_decode(u_int8_t c, u_int *type, int *value) 131{ 132 switch (c) { 133 case SKBD_RSP_IDLE: 134 *type = WSCONS_EVENT_ALL_KEYS_UP; 135 *value = 0; 136 break; 137 default: 138 *type = (c & 0x80) ? 139 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 140 *value = c & 0x7f; 141 break; 142 } 143} 144 145void 146sunkbd_decode5(u_int8_t c, u_int *type, int *value) 147{ 148 sunkbd_decode(c, type, value); 149 /* 150 * Scancode 0x2d is KS_KP_Equal on type 4, and KS_AudioMute on 151 * type 5. Rather than provide two distinct maps, we remap the 152 * scancode here. 153 */ 154 if (*value == 0x2d) 155 *value = 0x7f; 156} 157 158int 159sunkbd_enable(void *v, int on) 160{ 161 return (0); 162} 163 164int 165sunkbd_getleds(struct sunkbd_softc *sc) 166{ 167 return (sc->sc_leds); 168} 169 170void 171sunkbd_input(struct sunkbd_softc *sc, u_int8_t *buf, u_int buflen) 172{ 173 u_int type; 174 int value; 175 int s; 176 177 if (sc->sc_wskbddev == NULL) 178 return; /* why bother */ 179 180#ifdef WSDISPLAY_COMPAT_RAWKBD 181 if (sc->sc_rawkbd) { 182 u_char rbuf[SUNKBD_MAX_INPUT_SIZE * 2]; 183 int c, rlen = 0; 184 185 while (buflen-- != 0) { 186 (*sc->sc_decode)(*buf++, &type, &value); 187 c = sunkbd_rawmap[value]; 188 if (c == RAWKEY_Null) 189 continue; 190 /* fake extended scancode if necessary */ 191 if (c & 0x80) 192 rbuf[rlen++] = 0xe0; 193 rbuf[rlen] = c & 0x7f; 194 if (type == WSCONS_EVENT_KEY_UP) 195 rbuf[rlen] |= 0x80; 196 rlen++; 197 } 198 199 s = spltty(); 200 wskbd_rawinput(sc->sc_wskbddev, rbuf, rlen); 201 splx(s); 202 } else 203#endif 204 { 205 s = spltty(); 206 while (buflen-- != 0) { 207 (*sc->sc_decode)(*buf++, &type, &value); 208 wskbd_input(sc->sc_wskbddev, type, value); 209 } 210 splx(s); 211 } 212} 213 214int 215sunkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 216{ 217 struct sunkbd_softc *sc = v; 218 int *d_int = (int *)data; 219 struct wskbd_bell_data *d_bell = (struct wskbd_bell_data *)data; 220 221 switch (cmd) { 222 case WSKBDIO_GTYPE: 223 if (ISTYPE5(sc->sc_layout)) { 224 *d_int = WSKBD_TYPE_SUN5; 225 } else { 226 *d_int = WSKBD_TYPE_SUN; 227 } 228 return (0); 229 case WSKBDIO_SETLEDS: 230 sunkbd_setleds(sc, *d_int); 231 return (0); 232 case WSKBDIO_GETLEDS: 233 *d_int = sunkbd_getleds(sc); 234 return (0); 235 case WSKBDIO_COMPLEXBELL: 236 sunkbd_bell(sc, d_bell->period, d_bell->pitch, d_bell->volume); 237 return (0); 238#ifdef WSDISPLAY_COMPAT_RAWKBD 239 case WSKBDIO_SETMODE: 240 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 241 return (0); 242#endif 243 } 244 245 return (-1); 246} 247 248void 249sunkbd_raw(struct sunkbd_softc *sc, u_int8_t c) 250{ 251 int claimed = 0; 252 253 if (sc->sc_kbdstate == SKBD_STATE_LAYOUT) { 254 sc->sc_kbdstate = SKBD_STATE_GETKEY; 255 sc->sc_layout = c; 256 return; 257 } 258 259 switch (c) { 260 case SKBD_RSP_RESET: 261 sc->sc_kbdstate = SKBD_STATE_RESET; 262 claimed = 1; 263 break; 264 case SKBD_RSP_LAYOUT: 265 sc->sc_kbdstate = SKBD_STATE_LAYOUT; 266 claimed = 1; 267 break; 268 case SKBD_RSP_IDLE: 269 sc->sc_kbdstate = SKBD_STATE_GETKEY; 270 claimed = 1; 271 } 272 273 if (claimed) 274 return; 275 276 switch (sc->sc_kbdstate) { 277 case SKBD_STATE_RESET: 278 sc->sc_kbdstate = SKBD_STATE_GETKEY; 279 if (c < KB_SUN2 || c > KB_SUN4) 280 printf("%s: reset: invalid keyboard type 0x%02x\n", 281 sc->sc_dev.dv_xname, c); 282 else 283 sc->sc_id = c; 284 break; 285 case SKBD_STATE_GETKEY: 286 break; 287 } 288} 289 290int 291sunkbd_setclick(struct sunkbd_softc *sc, int click) 292{ 293 u_int8_t c; 294 295 /* Type 2 keyboards do not support keyclick */ 296 if (sc->sc_id == KB_SUN2) 297 return (ENXIO); 298 299 c = click ? SKBD_CMD_CLICKON : SKBD_CMD_CLICKOFF; 300 (*sc->sc_sendcmd)(sc, &c, 1); 301 return (0); 302} 303 304void 305sunkbd_setleds(void *v, int wled) 306{ 307 struct sunkbd_softc *sc = v; 308 u_int8_t sled = 0; 309 u_int8_t cmd[2]; 310 311 sc->sc_leds = wled; 312 313 if (wled & WSKBD_LED_CAPS) 314 sled |= SKBD_LED_CAPSLOCK; 315 if (wled & WSKBD_LED_NUM) 316 sled |= SKBD_LED_NUMLOCK; 317 if (wled & WSKBD_LED_SCROLL) 318 sled |= SKBD_LED_SCROLLLOCK; 319 if (wled & WSKBD_LED_COMPOSE) 320 sled |= SKBD_LED_COMPOSE; 321 322 cmd[0] = SKBD_CMD_SETLED; 323 cmd[1] = sled; 324 (*sc->sc_sendcmd)(sc, cmd, sizeof(cmd)); 325}