1 /* $OpenBSD: sunkbd.c,v 1.21 2005/11/11 16:44:51 miod 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 43 #include <dev/sun/sunkbdreg.h> 44 #include <dev/sun/sunkbdvar.h> 45 46 #ifdef __sparc64__ 47 #define NTCTRL 0 48 #else 49 #include "tctrl.h" 50 #endif 51 52 #if NTCTRL > 0 53 #include <sparc/dev/tctrlvar.h> /* XXX for tadpole_bell() */ 54 #endif 55 56 void sunkbd_bell(struct sunkbd_softc *, u_int, u_int, u_int); 57 int sunkbd_enable(void *, int); 58 int sunkbd_getleds(struct sunkbd_softc *); 59 int sunkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 60 void sunkbd_setleds(void *, int); 61 62 struct wskbd_accessops sunkbd_accessops = { 63 sunkbd_enable, 64 sunkbd_setleds, 65 sunkbd_ioctl 66 }; 67 68 void 69 sunkbd_bell(struct sunkbd_softc *sc, u_int period, u_int pitch, u_int volume) 70 { 71 int ticks, s; 72 u_int8_t c = SKBD_CMD_BELLON; 73 74 #if NTCTRL > 0 75 if (tadpole_bell(period / 10, pitch, volume) != 0) 76 return; 77 #endif 78 79 s = spltty(); 80 if (sc->sc_bellactive) { 81 if (sc->sc_belltimeout == 0) 82 timeout_del(&sc->sc_bellto); 83 } 84 if (pitch == 0 || period == 0) { 85 sunkbd_bellstop(sc); 86 splx(s); 87 return; 88 } 89 if (sc->sc_bellactive == 0) { 90 ticks = (period * hz) / 1000; 91 if (ticks <= 0) 92 ticks = 1; 93 94 sc->sc_bellactive = 1; 95 sc->sc_belltimeout = 1; 96 (*sc->sc_sendcmd)(sc, &c, 1); 97 timeout_add(&sc->sc_bellto, ticks); 98 } 99 splx(s); 100 } 101 102 void 103 sunkbd_bellstop(void *v) 104 { 105 struct sunkbd_softc *sc = v; 106 int s; 107 u_int8_t c; 108 109 s = spltty(); 110 sc->sc_belltimeout = 0; 111 c = SKBD_CMD_BELLOFF; 112 (*sc->sc_sendcmd)(v, &c, 1); 113 sc->sc_bellactive = 0; 114 splx(s); 115 } 116 117 void 118 sunkbd_decode(u_int8_t c, u_int *type, int *value) 119 { 120 switch (c) { 121 case SKBD_RSP_IDLE: 122 *type = WSCONS_EVENT_ALL_KEYS_UP; 123 *value = 0; 124 break; 125 default: 126 *type = (c & 0x80) ? 127 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 128 *value = c & 0x7f; 129 break; 130 } 131 } 132 133 int 134 sunkbd_enable(void *v, int on) 135 { 136 return (0); 137 } 138 139 int 140 sunkbd_getleds(struct sunkbd_softc *sc) 141 { 142 return (sc->sc_leds); 143 } 144 145 int 146 sunkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 147 { 148 struct sunkbd_softc *sc = v; 149 int *d_int = (int *)data; 150 struct wskbd_bell_data *d_bell = (struct wskbd_bell_data *)data; 151 152 switch (cmd) { 153 case WSKBDIO_GTYPE: 154 if (ISTYPE5(sc->sc_layout)) { 155 *d_int = WSKBD_TYPE_SUN5; 156 } else { 157 *d_int = WSKBD_TYPE_SUN; 158 } 159 return (0); 160 case WSKBDIO_SETLEDS: 161 sunkbd_setleds(sc, *d_int); 162 return (0); 163 case WSKBDIO_GETLEDS: 164 *d_int = sunkbd_getleds(sc); 165 return (0); 166 case WSKBDIO_COMPLEXBELL: 167 sunkbd_bell(sc, d_bell->period, d_bell->pitch, d_bell->volume); 168 return (0); 169 } 170 171 return (-1); 172 } 173 174 void 175 sunkbd_raw(struct sunkbd_softc *sc, u_int8_t c) 176 { 177 int claimed = 0; 178 179 if (sc->sc_kbdstate == SKBD_STATE_LAYOUT) { 180 sc->sc_kbdstate = SKBD_STATE_GETKEY; 181 sc->sc_layout = c; 182 return; 183 } 184 185 switch (c) { 186 case SKBD_RSP_RESET: 187 sc->sc_kbdstate = SKBD_STATE_RESET; 188 claimed = 1; 189 break; 190 case SKBD_RSP_LAYOUT: 191 sc->sc_kbdstate = SKBD_STATE_LAYOUT; 192 claimed = 1; 193 break; 194 case SKBD_RSP_IDLE: 195 sc->sc_kbdstate = SKBD_STATE_GETKEY; 196 claimed = 1; 197 } 198 199 if (claimed) 200 return; 201 202 switch (sc->sc_kbdstate) { 203 case SKBD_STATE_RESET: 204 sc->sc_kbdstate = SKBD_STATE_GETKEY; 205 if (c < KB_SUN2 || c > KB_SUN4) 206 printf("%s: reset: invalid keyboard type 0x%02x\n", 207 sc->sc_dev.dv_xname, c); 208 else 209 sc->sc_id = c; 210 break; 211 case SKBD_STATE_GETKEY: 212 break; 213 } 214 } 215 216 int 217 sunkbd_setclick(struct sunkbd_softc *sc, int click) 218 { 219 u_int8_t c; 220 221 /* Type 2 keyboards do not support keyclick */ 222 if (sc->sc_id == KB_SUN2) 223 return (ENXIO); 224 225 c = click ? SKBD_CMD_CLICKON : SKBD_CMD_CLICKOFF; 226 (*sc->sc_sendcmd)(sc, &c, 1); 227 return (0); 228 } 229 230 void 231 sunkbd_setleds(void *v, int wled) 232 { 233 struct sunkbd_softc *sc = v; 234 u_int8_t sled = 0; 235 u_int8_t cmd[2]; 236 237 sc->sc_leds = wled; 238 239 if (wled & WSKBD_LED_CAPS) 240 sled |= SKBD_LED_CAPSLOCK; 241 if (wled & WSKBD_LED_NUM) 242 sled |= SKBD_LED_NUMLOCK; 243 if (wled & WSKBD_LED_SCROLL) 244 sled |= SKBD_LED_SCROLLLOCK; 245 if (wled & WSKBD_LED_COMPOSE) 246 sled |= SKBD_LED_COMPOSE; 247 248 cmd[0] = SKBD_CMD_SETLED; 249 cmd[1] = sled; 250 (*sc->sc_sendcmd)(sc, cmd, sizeof(cmd)); 251 } 252