1 /* $NetBSD: nextkbd.c,v 1.7 2002/10/02 04:22:53 thorpej Exp $ */ 2 /* 3 * Copyright (c) 1998 Matt DeBergalis 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Matt DeBergalis 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/proc.h> 38 #include <sys/device.h> 39 #include <sys/malloc.h> 40 #include <sys/errno.h> 41 #include <sys/queue.h> 42 #include <sys/lock.h> 43 44 #include <machine/autoconf.h> 45 #include <machine/bus.h> 46 #include <machine/cpu.h> 47 #include <machine/intr.h> 48 49 #include <next68k/dev/nextkbdvar.h> 50 #include <next68k/dev/wskbdmap_next.h> 51 52 #include <dev/wscons/wsconsio.h> 53 #include <dev/wscons/wskbdvar.h> 54 #include <dev/wscons/wsksymdef.h> 55 #include <dev/wscons/wsksymvar.h> 56 57 #include <next68k/next68k/isr.h> 58 59 #include <next68k/dev/intiovar.h> 60 61 struct nextkbd_internal { 62 int num_ints; /* interrupt total */ 63 int polling; 64 int isconsole; 65 66 bus_space_tag_t iot; 67 bus_space_handle_t ioh; 68 struct nextkbd_softc *t_sc; /* back pointer */ 69 u_int32_t mods; 70 }; 71 72 struct mon_regs { 73 u_int32_t mon_csr; 74 u_int32_t mon_1; 75 u_int32_t mon_data; 76 }; 77 78 static int attached = 0; 79 80 int nextkbd_match __P((struct device *, struct cfdata *, void *)); 81 void nextkbd_attach __P((struct device *, struct device *, void *)); 82 83 int nextkbc_cnattach __P((bus_space_tag_t)); 84 85 CFATTACH_DECL(nextkbd, sizeof(struct nextkbd_softc), 86 nextkbd_match, nextkbd_attach, NULL, NULL); 87 88 int nextkbd_enable __P((void *, int)); 89 void nextkbd_set_leds __P((void *, int)); 90 int nextkbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 91 92 const struct wskbd_accessops nextkbd_accessops = { 93 nextkbd_enable, 94 nextkbd_set_leds, 95 nextkbd_ioctl, 96 }; 97 98 void nextkbd_cngetc __P((void *, u_int *, int *)); 99 void nextkbd_cnpollc __P((void *, int)); 100 101 const struct wskbd_consops nextkbd_consops = { 102 nextkbd_cngetc, 103 nextkbd_cnpollc, 104 }; 105 106 const struct wskbd_mapdata nextkbd_keymapdata = { 107 nextkbd_keydesctab, 108 KB_US, 109 }; 110 111 static int nextkbd_read_data __P((struct nextkbd_internal *)); 112 static int nextkbd_decode __P((struct nextkbd_internal *, int, u_int *, int *)); 113 114 static struct nextkbd_internal nextkbd_consdata; 115 static int nextkbd_is_console __P((bus_space_tag_t bst)); 116 117 int nextkbdhard __P((void *)); 118 119 static int 120 nextkbd_is_console(bst) 121 bus_space_tag_t bst; 122 { 123 return (nextkbd_consdata.isconsole 124 && (bst == nextkbd_consdata.iot)); 125 } 126 127 int 128 nextkbd_match(parent, match, aux) 129 struct device *parent; 130 struct cfdata *match; 131 void *aux; 132 { 133 struct intio_attach_args *ia = (struct intio_attach_args *)aux; 134 135 if (attached) 136 return(0); 137 138 ia->ia_addr = (void *)NEXT_P_MON; 139 140 return(1); 141 } 142 143 void 144 nextkbd_attach(parent, self, aux) 145 struct device *parent, *self; 146 void *aux; 147 { 148 struct nextkbd_softc *sc = (struct nextkbd_softc *)self; 149 struct intio_attach_args *ia = (struct intio_attach_args *)aux; 150 int isconsole; 151 struct wskbddev_attach_args a; 152 153 printf("\n"); 154 155 isconsole = nextkbd_is_console(ia->ia_bst); /* XXX */ 156 157 if (isconsole) { 158 sc->id = &nextkbd_consdata; 159 } else { 160 sc->id = malloc(sizeof(struct nextkbd_internal), 161 M_DEVBUF, M_WAITOK); 162 163 memset(sc->id, 0, sizeof(struct nextkbd_internal)); 164 sc->id->iot = ia->ia_bst; 165 if (bus_space_map(sc->id->iot, NEXT_P_MON, 166 sizeof(struct mon_regs), 167 0, &sc->id->ioh)) { 168 printf("%s: can't map mon status control register\n", 169 sc->sc_dev.dv_xname); 170 return; 171 } 172 } 173 174 sc->id->t_sc = sc; /* set back pointer */ 175 176 isrlink_autovec(nextkbdhard, sc, NEXT_I_IPL(NEXT_I_KYBD_MOUSE), 0, NULL); 177 178 INTR_ENABLE(NEXT_I_KYBD_MOUSE); 179 180 a.console = isconsole; 181 a.keymap = &nextkbd_keymapdata; 182 a.accessops = &nextkbd_accessops; 183 a.accesscookie = sc; 184 185 /* 186 * Attach the wskbd, saving a handle to it. 187 * XXX XXX XXX 188 */ 189 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 190 191 attached = 1; 192 } 193 194 int 195 nextkbd_enable(v, on) 196 void *v; 197 int on; 198 { 199 /* XXX not sure if this should do anything */ 200 /* printf("nextkbd_enable %d\n", on); */ 201 return 0; 202 } 203 204 void 205 nextkbd_set_leds(v, leds) 206 void *v; 207 int leds; 208 { 209 struct nextkbd_softc *sc = v; 210 uint32_t hw_leds = 0; 211 int s; 212 213 sc->sc_leds &= ~ NEXT_WSKBD_LEDS; 214 sc->sc_leds |= (leds & NEXT_WSKBD_LEDS); 215 216 if (sc->sc_leds & WSKBD_LED_CAPS) { 217 hw_leds |= 0x30000; 218 } 219 220 s = spltty(); 221 bus_space_write_1(sc->id->iot, sc->id->ioh, 3, 0xc5); 222 /* @@@ need to add: 223 if bit 7 of @ioh+0 set: 224 repeat 2 225 wait until bit 6 of @ioh+2 clears 226 */ 227 bus_space_write_4(sc->id->iot, sc->id->ioh, 4, hw_leds); 228 /* @@@ need to add: 229 wait until bit 4 of @ioh+0 (@ioh+2 if bit 7 was set above) 230 clears 231 */ 232 splx(s); 233 234 return; 235 } 236 237 int 238 nextkbd_ioctl(v, cmd, data, flag, p) 239 void *v; 240 u_long cmd; 241 caddr_t data; 242 int flag; 243 struct proc *p; 244 { 245 struct nextkbd_softc *sc = v; 246 247 switch (cmd) { 248 case WSKBDIO_GTYPE: 249 /* XXX */ 250 *(int *)data = WSKBD_TYPE_NEXT; 251 return (0); 252 case WSKBDIO_SETLEDS: 253 nextkbd_set_leds (sc, *(int *)data); 254 return (0); 255 case WSKBDIO_GETLEDS: 256 *(int *)data = sc->sc_leds & NEXT_WSKBD_LEDS; 257 return (0); 258 case WSKBDIO_COMPLEXBELL: 259 return (0); 260 } 261 return EPASSTHROUGH; 262 } 263 264 int 265 nextkbdhard(arg) 266 void *arg; 267 { 268 register struct nextkbd_softc *sc = arg; 269 int type, key, val; 270 271 if (!INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) return 0; 272 273 #define CSR_INT 0x00800000 274 #define CSR_DATA 0x00400000 275 276 #define KD_KEYMASK 0x007f 277 #define KD_DIRECTION 0x0080 /* pressed or released */ 278 #define KD_CNTL 0x0100 279 #define KD_LSHIFT 0x0200 280 #define KD_RSHIFT 0x0400 281 #define KD_LCOMM 0x0800 282 #define KD_RCOMM 0x1000 283 #define KD_LALT 0x2000 284 #define KD_RALT 0x4000 285 #define KD_VALID 0x8000 /* only set for scancode keys ? */ 286 #define KD_MODS 0x4f00 287 288 val = nextkbd_read_data(sc->id); 289 if ((val != -1) && nextkbd_decode(sc->id, val, &type, &key)) { 290 wskbd_input(sc->sc_wskbddev, type, key); 291 } 292 return(1); 293 } 294 295 int 296 nextkbd_cnattach(bst) 297 bus_space_tag_t bst; 298 { 299 bus_space_handle_t bsh; 300 301 if (bus_space_map(bst, NEXT_P_MON, sizeof(struct mon_regs), 302 0, &bsh)) 303 return (ENXIO); 304 305 memset(&nextkbd_consdata, 0, sizeof(nextkbd_consdata)); 306 307 nextkbd_consdata.iot = bst; 308 nextkbd_consdata.ioh = bsh; 309 nextkbd_consdata.isconsole = 1; 310 311 wskbd_cnattach(&nextkbd_consops, &nextkbd_consdata, 312 &nextkbd_keymapdata); 313 314 return (0); 315 } 316 317 void 318 nextkbd_cngetc(v, type, data) 319 void *v; 320 u_int *type; 321 int *data; 322 { 323 struct nextkbd_internal *t = v; 324 int val; 325 326 for (;;) { 327 if (INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) { 328 val = nextkbd_read_data(t); 329 if ((val != -1) && nextkbd_decode(t, val, type, data)) 330 return; 331 } 332 } 333 } 334 335 void 336 nextkbd_cnpollc(v, on) 337 void *v; 338 int on; 339 { 340 struct nextkbd_internal *t = v; 341 342 t->polling = on; 343 if (on) { 344 INTR_DISABLE(NEXT_I_KYBD_MOUSE); 345 } else { 346 INTR_ENABLE(NEXT_I_KYBD_MOUSE); 347 } 348 349 } 350 351 static int 352 nextkbd_read_data(struct nextkbd_internal *id) 353 { 354 unsigned char device; 355 struct mon_regs stat; 356 357 bus_space_read_region_4(id->iot, id->ioh, 0, &stat, 3); 358 if ((stat.mon_csr & CSR_INT) && (stat.mon_csr & CSR_DATA)) { 359 stat.mon_csr &= ~CSR_INT; 360 id->num_ints++; 361 bus_space_write_4(id->iot, id->ioh, 0, stat.mon_csr); 362 device = stat.mon_data >> 28; 363 if (device != 1) return (-1); /* XXX: mouse */ 364 return (stat.mon_data & 0xffff); 365 } 366 return (-1); 367 } 368 369 static int 370 nextkbd_decode(id, datain, type, dataout) 371 struct nextkbd_internal *id; 372 int datain; 373 u_int *type; 374 int *dataout; 375 { 376 /* printf("datain %08x mods %08x\n", datain, id->mods); */ 377 378 if ((datain ^ id->mods) & KD_LSHIFT) { 379 id->mods ^= KD_LSHIFT; 380 *dataout = 90; 381 if (datain & KD_LSHIFT) 382 *type = WSCONS_EVENT_KEY_DOWN; 383 else 384 *type = WSCONS_EVENT_KEY_UP; 385 } else if ((datain ^ id->mods) & KD_RSHIFT) { 386 id->mods ^= KD_RSHIFT; 387 *dataout = 91; 388 if (datain & KD_RSHIFT) 389 *type = WSCONS_EVENT_KEY_DOWN; 390 else 391 *type = WSCONS_EVENT_KEY_UP; 392 } else if ((datain ^ id->mods) & KD_LALT) { 393 id->mods ^= KD_LALT; 394 *dataout = 92; 395 if (datain & KD_LALT) 396 *type = WSCONS_EVENT_KEY_DOWN; 397 else 398 *type = WSCONS_EVENT_KEY_UP; 399 } else if ((datain ^ id->mods) & KD_RALT) { 400 id->mods ^= KD_RALT; 401 *dataout = 93; 402 if (datain & KD_RALT) 403 *type = WSCONS_EVENT_KEY_DOWN; 404 else 405 *type = WSCONS_EVENT_KEY_UP; 406 } else if ((datain ^ id->mods) & KD_CNTL) { 407 id->mods ^= KD_CNTL; 408 *dataout = 94; 409 if (datain & KD_CNTL) 410 *type = WSCONS_EVENT_KEY_DOWN; 411 else 412 *type = WSCONS_EVENT_KEY_UP; 413 } else if ((datain ^ id->mods) & KD_LCOMM) { 414 id->mods ^= KD_LCOMM; 415 *dataout = 95; 416 if (datain & KD_LCOMM) 417 *type = WSCONS_EVENT_KEY_DOWN; 418 else 419 *type = WSCONS_EVENT_KEY_UP; 420 } else if ((datain ^ id->mods) & KD_RCOMM) { 421 id->mods ^= KD_RCOMM; 422 *dataout = 96; 423 if (datain & KD_RCOMM) 424 *type = WSCONS_EVENT_KEY_DOWN; 425 else 426 *type = WSCONS_EVENT_KEY_UP; 427 } else if (datain & KD_KEYMASK) { 428 if (datain & KD_DIRECTION) 429 *type = WSCONS_EVENT_KEY_UP; 430 else 431 *type = WSCONS_EVENT_KEY_DOWN; 432 433 *dataout = (datain & KD_KEYMASK); 434 } else { 435 *dataout = 0; 436 } 437 438 return 1; 439 } 440