dtkbd.c revision 1.2
1/* $NetBSD: dtkbd.c,v 1.2 2003/12/13 23:04:38 ad 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.2 2003/12/13 23:04:38 ad 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 64struct dtkbd_softc { 65 struct device sc_dv; 66 struct device *sc_wskbddev; 67 int sc_enabled; 68}; 69 70int dtkbd_match(struct device *, struct cfdata *, void *); 71void dtkbd_attach(struct device *, struct device *, void *); 72int dtkbd_enable(void *, int); 73int dtkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 74void dtkbd_cngetc(void *, u_int *, int *); 75void dtkbd_cnpollc(void *, int); 76int dtkbd_process_msg(struct dt_msg *, u_int *, int *); 77void dtkbd_handler(void *); 78void dtkbd_set_leds(void *, int); 79 80const struct wskbd_accessops dtkbd_accessops = { 81 dtkbd_enable, 82 dtkbd_set_leds, 83 dtkbd_ioctl, 84}; 85 86const struct wskbd_consops dtkbd_consops = { 87 dtkbd_cngetc, 88 dtkbd_cnpollc, 89}; 90 91CFATTACH_DECL(dtkbd, sizeof(struct dtkbd_softc), 92 dtkbd_match, dtkbd_attach, NULL, NULL); 93 94const 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 103int dtkbd_isconsole; 104int dtkbd_map[10]; 105int dtkbd_maplen; 106 107int 108dtkbd_match(struct device *parent, struct cfdata *cf, void *aux) 109{ 110 struct dt_attach_args *dta; 111 struct dt_ident ident; 112 113 dta = aux; 114 115 /* 116 * Allow hard-wiring of addresses. 117 */ 118 if (cf->cf_loc[DTCF_ADDR] == dta->dta_addr) 119 return (2); 120 121 /* 122 * The keyboard and mouse addresses are often swapped. So, we 123 * accept the standard address for either, and ask the device to 124 * identify itself. 125 */ 126 if (cf->cf_loc[DTCF_ADDR] == DTCF_ADDR_DEFAULT && 127 (dta->dta_addr == DT_ADDR_KBD || dta->dta_addr == DT_ADDR_MOUSE)) { 128 if (dt_identify(dta->dta_addr, &ident)) 129 return (dta->dta_addr == DT_ADDR_KBD); 130 return (strncmp(ident.vendor, "DEC ", 8) == 0 && 131 strncmp(ident.module, "LK501-", 6) == 0); 132 } 133 134 return (0); 135} 136 137void 138dtkbd_attach(struct device *parent, struct device *self, void *aux) 139{ 140 struct dt_softc *dt; 141 struct dtkbd_softc *sc; 142 struct dt_attach_args *dta; 143 struct wskbddev_attach_args a; 144 145 dt = (struct dt_softc *)parent; 146 sc = (struct dtkbd_softc *)self; 147 dta = aux; 148 149 printf("\n"); 150 151 if (dt_establish_handler(dt, dta->dta_addr, self, dtkbd_handler)) { 152 printf("%s: unable to establish handler\n", self->dv_xname); 153 return; 154 } 155 156 sc->sc_enabled = 1; 157 dt_kbd_addr = dta->dta_addr; 158 159 a.console = dtkbd_isconsole; 160 a.keymap = &dtkbd_keymapdata; 161 a.accessops = &dtkbd_accessops; 162 a.accesscookie = sc; 163 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 164} 165 166void 167dtkbd_cnattach(void) 168{ 169 170 dtkbd_isconsole = 1; 171 dt_cninit(); 172 173 wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata); 174} 175 176int 177dtkbd_enable(void *v, int on) 178{ 179 struct dtkbd_softc *sc; 180 181 sc = v; 182 sc->sc_enabled = on; 183 184 return (0); 185} 186 187void 188dtkbd_cngetc(void *v, u_int *type, int *data) 189{ 190 struct dt_msg msg; 191 static u_int types[20]; 192 static int cnt, i, vals[20]; 193 194 if (i >= cnt) { 195 for (;;) { 196 if (dt_msg_get(&msg, 0) == DT_GET_DONE) 197 if (msg.src == DT_ADDR_KBD && 198 !msg.code.val.P) 199 break; 200 DELAY(1000); 201 } 202 203 cnt = dtkbd_process_msg(&msg, types, vals); 204 i = 0; 205 } 206 207 *type = types[i++]; 208 *data = vals[i++]; 209} 210 211void 212dtkbd_cnpollc(void *v, int on) 213{ 214 215 /* XXX */ 216} 217 218int 219dtkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 220{ 221 struct dtkbd_softc *sc; 222 223 sc = (struct dtkbd_softc *)v; 224 225 switch (cmd) { 226 case WSKBDIO_GTYPE: 227 *(int *)data = WSKBD_TYPE_LK201; 228 return 0; 229 default: 230 /* XXX */ 231 return (-1); 232 } 233} 234 235void 236dtkbd_set_leds(void *v, int state) 237{ 238 239 /* XXX */ 240} 241 242void 243dtkbd_handler(void *cookie) 244{ 245 struct dtkbd_softc *sc; 246 struct dt_softc *dt; 247 struct dt_device *dtdv; 248 struct dt_msg *msg; 249 u_int types[20]; 250 int i, cnt, vals[20]; 251 252 dtdv = cookie; 253 sc = (struct dtkbd_softc *)dtdv->dtdv_dv; 254 dt = (struct dt_softc *)sc->sc_dv.dv_parent; 255 256 while ((msg = dt_msg_dequeue(dtdv)) != NULL) { 257 if (sc->sc_enabled) { 258 if (!msg->code.val.P) { 259 cnt = dtkbd_process_msg(msg, types, vals); 260 for (i = 0; i < cnt; i++) 261 wskbd_input(sc->sc_wskbddev, types[i], 262 vals[i]); 263 } 264 } 265 266 dt_msg_release(dt, msg); 267 } 268} 269 270int 271dtkbd_process_msg(struct dt_msg *msg, u_int *types, int *vals) 272{ 273 u_int len, c, count; 274 int i, j; 275 276 len = msg->code.val.len; 277 278 if ((msg->body[0] < DT_KBD_KEY_MIN && msg->body[0] != DT_KBD_EMPTY) || 279 len > 10) { 280 printf("dtkbd0: error: %x %x %x\n", len, msg->body[0], 281 msg->body[1]); 282 283 /* 284 * Fake an "all ups" to avoid the stuck key syndrome. 285 */ 286 msg->body[0] = DT_KBD_EMPTY; 287 len = 1; 288 } 289 290 if (msg->body[0] == DT_KBD_EMPTY) { 291 types[0] = WSCONS_EVENT_ALL_KEYS_UP; 292 vals[0] = 0; 293 dtkbd_maplen = 0; 294 return (1); 295 } 296 297 count = 0; 298 299 for (i = 0; i < len; i++) { 300 c = msg->body[i]; 301 302 for (j = 0; j < dtkbd_maplen; j++) 303 if (dtkbd_map[j] == c) 304 break; 305 306 if (j == dtkbd_maplen) { 307 types[count] = WSCONS_EVENT_KEY_DOWN; 308 vals[count] = c - MIN_LK201_KEY; 309 count++; 310 } 311 } 312 313 for (j = 0; j < dtkbd_maplen; j++) { 314 c = dtkbd_map[j]; 315 316 for (i = 0; i < len; i++) 317 if (msg->body[i] == c) 318 break; 319 320 if (i == len) { 321 types[count] = WSCONS_EVENT_KEY_UP; 322 vals[count] = c - MIN_LK201_KEY; 323 count++; 324 } 325 } 326 327 memcpy(dtkbd_map, msg->body, len); 328 dtkbd_maplen = len; 329 330 return (count); 331} 332