1 /* $OpenBSD: sunkbd.c,v 1.26 2011/11/09 14:22:37 shadchin 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 59 void sunkbd_bell(struct sunkbd_softc *, u_int, u_int, u_int); 60 void sunkbd_decode5(u_int8_t, u_int *, int *); 61 int sunkbd_enable(void *, int); 62 int sunkbd_getleds(struct sunkbd_softc *); 63 int sunkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 64 void sunkbd_setleds(void *, int); 65 66 struct wskbd_accessops sunkbd_accessops = { 67 sunkbd_enable, 68 sunkbd_setleds, 69 sunkbd_ioctl 70 }; 71 72 void 73 sunkbd_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 84 void 85 sunkbd_bell(struct sunkbd_softc *sc, u_int period, u_int pitch, u_int volume) 86 { 87 int ticks, 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 ticks = (period * hz) / 1000; 107 if (ticks <= 0) 108 ticks = 1; 109 110 sc->sc_bellactive = 1; 111 sc->sc_belltimeout = 1; 112 (*sc->sc_sendcmd)(sc, &c, 1); 113 timeout_add(&sc->sc_bellto, ticks); 114 } 115 splx(s); 116 } 117 118 void 119 sunkbd_bellstop(void *v) 120 { 121 struct sunkbd_softc *sc = v; 122 int s; 123 u_int8_t c; 124 125 s = spltty(); 126 sc->sc_belltimeout = 0; 127 c = SKBD_CMD_BELLOFF; 128 (*sc->sc_sendcmd)(v, &c, 1); 129 sc->sc_bellactive = 0; 130 splx(s); 131 } 132 133 void 134 sunkbd_decode(u_int8_t c, u_int *type, int *value) 135 { 136 switch (c) { 137 case SKBD_RSP_IDLE: 138 *type = WSCONS_EVENT_ALL_KEYS_UP; 139 *value = 0; 140 break; 141 default: 142 *type = (c & 0x80) ? 143 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 144 *value = c & 0x7f; 145 break; 146 } 147 } 148 149 void 150 sunkbd_decode5(u_int8_t c, u_int *type, int *value) 151 { 152 sunkbd_decode(c, type, value); 153 /* 154 * Scancode 0x2d is KS_KP_Equal on type 4, and KS_AudioMute on 155 * type 5. Rather than provide two distinct maps, we remap the 156 * scancode here. 157 */ 158 if (*value == 0x2d) 159 *value = 0x7f; 160 } 161 162 int 163 sunkbd_enable(void *v, int on) 164 { 165 return (0); 166 } 167 168 int 169 sunkbd_getleds(struct sunkbd_softc *sc) 170 { 171 return (sc->sc_leds); 172 } 173 174 void 175 sunkbd_input(struct sunkbd_softc *sc, u_int8_t *buf, u_int buflen) 176 { 177 u_int type; 178 int value; 179 int s; 180 181 if (sc->sc_wskbddev == NULL) 182 return; /* why bother */ 183 184 #ifdef WSDISPLAY_COMPAT_RAWKBD 185 if (sc->sc_rawkbd) { 186 u_char rbuf[SUNKBD_MAX_INPUT_SIZE * 2]; 187 int c, rlen = 0; 188 189 while (buflen-- != 0) { 190 (*sc->sc_decode)(*buf++, &type, &value); 191 c = sunkbd_rawmap[value]; 192 if (c == RAWKEY_Null) 193 continue; 194 /* fake extended scancode if necessary */ 195 if (c & 0x80) 196 rbuf[rlen++] = 0xe0; 197 rbuf[rlen] = c & 0x7f; 198 if (type == WSCONS_EVENT_KEY_UP) 199 rbuf[rlen] |= 0x80; 200 rlen++; 201 } 202 203 s = spltty(); 204 wskbd_rawinput(sc->sc_wskbddev, rbuf, rlen); 205 splx(s); 206 } else 207 #endif 208 { 209 s = spltty(); 210 while (buflen-- != 0) { 211 (*sc->sc_decode)(*buf++, &type, &value); 212 wskbd_input(sc->sc_wskbddev, type, value); 213 } 214 splx(s); 215 } 216 } 217 218 int 219 sunkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 220 { 221 struct sunkbd_softc *sc = v; 222 int *d_int = (int *)data; 223 struct wskbd_bell_data *d_bell = (struct wskbd_bell_data *)data; 224 225 switch (cmd) { 226 case WSKBDIO_GTYPE: 227 if (ISTYPE5(sc->sc_layout)) { 228 *d_int = WSKBD_TYPE_SUN5; 229 } else { 230 *d_int = WSKBD_TYPE_SUN; 231 } 232 return (0); 233 case WSKBDIO_SETLEDS: 234 sunkbd_setleds(sc, *d_int); 235 return (0); 236 case WSKBDIO_GETLEDS: 237 *d_int = sunkbd_getleds(sc); 238 return (0); 239 case WSKBDIO_COMPLEXBELL: 240 sunkbd_bell(sc, d_bell->period, d_bell->pitch, d_bell->volume); 241 return (0); 242 #ifdef WSDISPLAY_COMPAT_RAWKBD 243 case WSKBDIO_SETMODE: 244 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 245 return (0); 246 #endif 247 } 248 249 return (-1); 250 } 251 252 void 253 sunkbd_raw(struct sunkbd_softc *sc, u_int8_t c) 254 { 255 int claimed = 0; 256 257 if (sc->sc_kbdstate == SKBD_STATE_LAYOUT) { 258 sc->sc_kbdstate = SKBD_STATE_GETKEY; 259 sc->sc_layout = c; 260 return; 261 } 262 263 switch (c) { 264 case SKBD_RSP_RESET: 265 sc->sc_kbdstate = SKBD_STATE_RESET; 266 claimed = 1; 267 break; 268 case SKBD_RSP_LAYOUT: 269 sc->sc_kbdstate = SKBD_STATE_LAYOUT; 270 claimed = 1; 271 break; 272 case SKBD_RSP_IDLE: 273 sc->sc_kbdstate = SKBD_STATE_GETKEY; 274 claimed = 1; 275 } 276 277 if (claimed) 278 return; 279 280 switch (sc->sc_kbdstate) { 281 case SKBD_STATE_RESET: 282 sc->sc_kbdstate = SKBD_STATE_GETKEY; 283 if (c < KB_SUN2 || c > KB_SUN4) 284 printf("%s: reset: invalid keyboard type 0x%02x\n", 285 sc->sc_dev.dv_xname, c); 286 else 287 sc->sc_id = c; 288 break; 289 case SKBD_STATE_GETKEY: 290 break; 291 } 292 } 293 294 int 295 sunkbd_setclick(struct sunkbd_softc *sc, int click) 296 { 297 u_int8_t c; 298 299 /* Type 2 keyboards do not support keyclick */ 300 if (sc->sc_id == KB_SUN2) 301 return (ENXIO); 302 303 c = click ? SKBD_CMD_CLICKON : SKBD_CMD_CLICKOFF; 304 (*sc->sc_sendcmd)(sc, &c, 1); 305 return (0); 306 } 307 308 void 309 sunkbd_setleds(void *v, int wled) 310 { 311 struct sunkbd_softc *sc = v; 312 u_int8_t sled = 0; 313 u_int8_t cmd[2]; 314 315 sc->sc_leds = wled; 316 317 if (wled & WSKBD_LED_CAPS) 318 sled |= SKBD_LED_CAPSLOCK; 319 if (wled & WSKBD_LED_NUM) 320 sled |= SKBD_LED_NUMLOCK; 321 if (wled & WSKBD_LED_SCROLL) 322 sled |= SKBD_LED_SCROLLLOCK; 323 if (wled & WSKBD_LED_COMPOSE) 324 sled |= SKBD_LED_COMPOSE; 325 326 cmd[0] = SKBD_CMD_SETLED; 327 cmd[1] = sled; 328 (*sc->sc_sendcmd)(sc, cmd, sizeof(cmd)); 329 } 330