1 /* $NetBSD: dtkbd.c,v 1.6 2005/12/11 12:18:41 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: dtkbd.c,v 1.6 2005/12/11 12:18:41 christos Exp $"); 41 42 #include "locators.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/device.h> 47 #include <sys/ioctl.h> 48 #include <sys/callout.h> 49 50 #include <dev/wscons/wsconsio.h> 51 #include <dev/wscons/wskbdvar.h> 52 #include <dev/wscons/wsksymdef.h> 53 #include <dev/wscons/wsksymvar.h> 54 #include <dev/dec/wskbdmap_lk201.h> 55 #include <dev/tc/tcvar.h> 56 57 #include <machine/bus.h> 58 59 #include <pmax/tc/dtreg.h> 60 #include <pmax/tc/dtvar.h> 61 62 #include <pmax/pmax/cons.h> 63 64 struct dtkbd_softc { 65 struct device sc_dv; 66 struct device *sc_wskbddev; 67 int sc_enabled; 68 }; 69 70 int dtkbd_match(struct device *, struct cfdata *, void *); 71 void dtkbd_attach(struct device *, struct device *, void *); 72 int dtkbd_enable(void *, int); 73 int dtkbd_ioctl(void *, u_long, caddr_t, int, struct lwp *); 74 void dtkbd_cngetc(void *, u_int *, int *); 75 void dtkbd_cnpollc(void *, int); 76 int dtkbd_process_msg(struct dt_msg *, u_int *, int *); 77 void dtkbd_handler(void *, struct dt_msg *); 78 void dtkbd_set_leds(void *, int); 79 80 const struct wskbd_accessops dtkbd_accessops = { 81 dtkbd_enable, 82 dtkbd_set_leds, 83 dtkbd_ioctl, 84 }; 85 86 const struct wskbd_consops dtkbd_consops = { 87 dtkbd_cngetc, 88 dtkbd_cnpollc, 89 }; 90 91 CFATTACH_DECL(dtkbd, sizeof(struct dtkbd_softc), 92 dtkbd_match, dtkbd_attach, NULL, NULL); 93 94 const struct wskbd_mapdata dtkbd_keymapdata = { 95 lkkbd_keydesctab, 96 #ifdef DTKBD_LAYOUT 97 DTKBD_LAYOUT, 98 #else 99 KB_US | KB_LK401, 100 #endif 101 }; 102 103 int dtkbd_isconsole; 104 uint8_t dtkbd_map[10]; 105 int dtkbd_maplen; 106 107 int 108 dtkbd_match(struct device *parent, struct cfdata *cf, void *aux) 109 { 110 struct dt_attach_args *dta; 111 112 dta = aux; 113 return (dta->dta_addr == DT_ADDR_KBD); 114 } 115 116 void 117 dtkbd_attach(struct device *parent, struct device *self, void *aux) 118 { 119 struct dt_softc *dt; 120 struct dtkbd_softc *sc; 121 struct wskbddev_attach_args a; 122 123 dt = (struct dt_softc *)parent; 124 sc = (struct dtkbd_softc *)self; 125 126 printf("\n"); 127 128 if (dt_establish_handler(dt, &dt_kbd_dv, self, dtkbd_handler)) { 129 printf("%s: unable to establish handler\n", self->dv_xname); 130 return; 131 } 132 133 sc->sc_enabled = 1; 134 135 a.console = dtkbd_isconsole; 136 a.keymap = &dtkbd_keymapdata; 137 a.accessops = &dtkbd_accessops; 138 a.accesscookie = sc; 139 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 140 } 141 142 void 143 dtkbd_cnattach(void) 144 { 145 146 dtkbd_isconsole = 1; 147 dt_cninit(); 148 149 wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata); 150 } 151 152 int 153 dtkbd_enable(void *v, int on) 154 { 155 struct dtkbd_softc *sc; 156 157 sc = v; 158 sc->sc_enabled = on; 159 160 return (0); 161 } 162 163 void 164 dtkbd_cngetc(void *v, u_int *type, int *data) 165 { 166 struct dt_msg msg; 167 static u_int types[20]; 168 static int cnt, i, vals[20]; 169 170 while (i >= cnt) { 171 for (;;) { 172 if (dt_msg_get(&msg, 0) == DT_GET_DONE) 173 if (msg.src == dt_kbd_addr && 174 !DT_CTL_P(msg.ctl)) 175 break; 176 DELAY(1000); 177 } 178 179 cnt = dtkbd_process_msg(&msg, types, vals); 180 i = 0; 181 } 182 183 *type = types[i++]; 184 *data = vals[i++]; 185 } 186 187 void 188 dtkbd_cnpollc(void *v, int on) 189 { 190 191 /* XXX */ 192 } 193 194 int 195 dtkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l) 196 { 197 struct dtkbd_softc *sc; 198 199 sc = (struct dtkbd_softc *)v; 200 201 switch (cmd) { 202 case WSKBDIO_GTYPE: 203 *(int *)data = WSKBD_TYPE_LK201; 204 return 0; 205 default: 206 /* XXX */ 207 return (EPASSTHROUGH); 208 } 209 } 210 211 void 212 dtkbd_set_leds(void *v, int state) 213 { 214 215 /* XXX */ 216 } 217 218 void 219 dtkbd_handler(void *cookie, struct dt_msg *msg) 220 { 221 struct dtkbd_softc *sc; 222 u_int types[20]; 223 int i, cnt, vals[20]; 224 225 sc = cookie; 226 227 if (!sc->sc_enabled) 228 return; 229 230 cnt = dtkbd_process_msg(msg, types, vals); 231 for (i = 0; i < cnt; i++) 232 wskbd_input(sc->sc_wskbddev, types[i], vals[i]); 233 } 234 235 int 236 dtkbd_process_msg(struct dt_msg *msg, u_int *types, int *vals) 237 { 238 u_int len, c, count; 239 int i, j; 240 241 len = DT_CTL_LEN(msg->ctl); 242 243 if ((msg->body[0] < DT_KBD_KEY_MIN && msg->body[0] != DT_KBD_EMPTY) || 244 len > 10) { 245 printf("dtkbd0: error: %x %x %x\n", len, msg->body[0], 246 msg->body[1]); 247 248 /* 249 * Fake an "all ups" to avoid the stuck key syndrome. 250 */ 251 msg->body[0] = DT_KBD_EMPTY; 252 len = 1; 253 } 254 255 if (msg->body[0] == DT_KBD_EMPTY) { 256 types[0] = WSCONS_EVENT_ALL_KEYS_UP; 257 vals[0] = 0; 258 dtkbd_maplen = 0; 259 return (1); 260 } 261 262 count = 0; 263 264 for (i = 0; i < len; i++) { 265 c = msg->body[i]; 266 267 for (j = 0; j < dtkbd_maplen; j++) 268 if (dtkbd_map[j] == c) 269 break; 270 271 if (j == dtkbd_maplen) { 272 types[count] = WSCONS_EVENT_KEY_DOWN; 273 vals[count] = c - MIN_LK201_KEY; 274 count++; 275 } 276 } 277 278 for (j = 0; j < dtkbd_maplen; j++) { 279 c = dtkbd_map[j]; 280 281 for (i = 0; i < len; i++) 282 if (msg->body[i] == c) 283 break; 284 285 if (i == len) { 286 types[count] = WSCONS_EVENT_KEY_UP; 287 vals[count] = c - MIN_LK201_KEY; 288 count++; 289 } 290 } 291 292 memcpy(dtkbd_map, msg->body, len); 293 dtkbd_maplen = len; 294 295 return (count); 296 } 297