dtkbd.c revision 1.4
1/* $NetBSD: dtkbd.c,v 1.4 2005/01/08 18:48:34 mhitch 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.4 2005/01/08 18:48:34 mhitch 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 *, struct dt_msg *); 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; 104uint8_t 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 112 dta = aux; 113 return (dta->dta_addr == DT_ADDR_KBD); 114} 115 116void 117dtkbd_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 142void 143dtkbd_cnattach(void) 144{ 145 146 dtkbd_isconsole = 1; 147 dt_cninit(); 148 149 wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata); 150} 151 152int 153dtkbd_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 163void 164dtkbd_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 187void 188dtkbd_cnpollc(void *v, int on) 189{ 190 191 /* XXX */ 192} 193 194int 195dtkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 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 (-1); 208 } 209} 210 211void 212dtkbd_set_leds(void *v, int state) 213{ 214 215 /* XXX */ 216} 217 218void 219dtkbd_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 235int 236dtkbd_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