1 /* $NetBSD: vrkiu.c,v 1.31 2002/03/10 07:24:54 takemura Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 SASAKI Takesi All rights reserved. 5 * Copyright (c) 1999, 2000, 2002 TAKEMRUA, Shin All rights reserved. 6 * Copyright (c) 1999 PocketBSD Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the PocketBSD project 19 * and its contributors. 20 * 4. Neither the name of the project nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 */ 37 38 #include <sys/param.h> 39 #include <sys/tty.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 #include <sys/conf.h> 43 #include <sys/kernel.h> 44 #include <sys/proc.h> 45 46 #include <machine/intr.h> 47 #include <machine/cpu.h> 48 #include <machine/bus.h> 49 #include <machine/platid.h> 50 #include <machine/platid_mask.h> 51 52 #include <dev/hpc/hpckbdvar.h> 53 54 #include <hpcmips/vr/vr.h> 55 #include <hpcmips/vr/vripif.h> 56 #include <hpcmips/vr/vrkiureg.h> 57 #include <hpcmips/vr/vrkiuvar.h> 58 #include <hpcmips/vr/icureg.h> 59 60 #include "opt_wsdisplay_compat.h" 61 #include "opt_pckbd_layout.h" 62 #include <dev/wscons/wsconsio.h> 63 #include <dev/wscons/wskbdvar.h> 64 #include <dev/wscons/wsksymdef.h> 65 #include <dev/wscons/wsksymvar.h> 66 #include <dev/pckbc/wskbdmap_mfii.h> 67 #ifdef WSDISPLAY_COMPAT_RAWKBD 68 #include <dev/hpc/pckbd_encode.h> 69 #endif 70 71 #define VRKIUDEBUG 72 #ifdef VRKIUDEBUG 73 int vrkiu_debug = 0; 74 #define DPRINTF(arg) if (vrkiu_debug) printf arg; 75 #else 76 #define DPRINTF(arg) 77 #endif 78 79 static int vrkiumatch(struct device *, struct cfdata *, void *); 80 static void vrkiuattach(struct device *, struct device *, void *); 81 82 int vrkiu_intr(void *); 83 84 static int vrkiu_init(struct vrkiu_chip *, bus_space_tag_t, bus_space_handle_t); 85 static void vrkiu_write(struct vrkiu_chip *, int, unsigned short); 86 static unsigned short vrkiu_read(struct vrkiu_chip *, int); 87 static int vrkiu_is_console(bus_space_tag_t, bus_space_handle_t); 88 static void vrkiu_scan(struct vrkiu_chip *); 89 static int countbits(int); 90 static void eliminate_phantom_keys(struct vrkiu_chip *, unsigned short *); 91 static int vrkiu_poll(void*); 92 static int vrkiu_input_establish(void*, struct hpckbd_if*); 93 94 struct cfattach vrkiu_ca = { 95 sizeof(struct vrkiu_softc), vrkiumatch, vrkiuattach 96 }; 97 98 struct vrkiu_chip *vrkiu_consdata = NULL; 99 100 static inline void 101 vrkiu_write(struct vrkiu_chip *chip, int port, unsigned short val) 102 { 103 104 bus_space_write_2(chip->kc_iot, chip->kc_ioh, port, val); 105 } 106 107 static inline unsigned short 108 vrkiu_read(struct vrkiu_chip *chip, int port) 109 { 110 111 return (bus_space_read_2(chip->kc_iot, chip->kc_ioh, port)); 112 } 113 114 static inline int 115 vrkiu_is_console(bus_space_tag_t iot, bus_space_handle_t ioh) 116 { 117 118 if (vrkiu_consdata && 119 vrkiu_consdata->kc_iot == iot && 120 vrkiu_consdata->kc_ioh == ioh) { 121 return (1); 122 } else { 123 return (0); 124 } 125 } 126 127 static int 128 vrkiumatch(struct device *parent, struct cfdata *cf, void *aux) 129 { 130 131 return (1); 132 } 133 134 static void 135 vrkiuattach(struct device *parent, struct device *self, void *aux) 136 { 137 struct vrkiu_softc *sc = (struct vrkiu_softc *)self; 138 struct vrip_attach_args *va = aux; 139 struct hpckbd_attach_args haa; 140 int isconsole, res; 141 142 bus_space_tag_t iot = va->va_iot; 143 bus_space_handle_t ioh; 144 145 if (va->va_parent_ioh != NULL) 146 res = bus_space_subregion(iot, va->va_parent_ioh, va->va_addr, 147 va->va_size, &ioh); 148 else 149 res = bus_space_map(iot, va->va_addr, 1, 0, &ioh); 150 if (res != 0) { 151 printf(": can't map bus space\n"); 152 return; 153 } 154 155 isconsole = vrkiu_is_console(iot, ioh); 156 if (isconsole) { 157 sc->sc_chip = vrkiu_consdata; 158 } else { 159 sc->sc_chip = &sc->sc_chip_body; 160 vrkiu_init(sc->sc_chip, iot, ioh); 161 } 162 sc->sc_chip->kc_sc = sc; 163 164 if (!(sc->sc_handler = 165 vrip_intr_establish(va->va_vc, va->va_unit, 0, IPL_TTY, 166 vrkiu_intr, sc))) { 167 printf (": can't map interrupt line.\n"); 168 return; 169 } 170 /* Level2 register setting */ 171 vrip_intr_setmask2(va->va_vc, sc->sc_handler, KIUINT_KDATRDY, 1); 172 173 printf("\n"); 174 175 /* attach hpckbd */ 176 haa.haa_ic = &sc->sc_chip->kc_if; 177 config_found(self, &haa, hpckbd_print); 178 } 179 180 /* 181 * initialize device 182 */ 183 static int 184 vrkiu_init(struct vrkiu_chip *chip, bus_space_tag_t iot, 185 bus_space_handle_t ioh) 186 { 187 188 memset(chip, 0, sizeof(struct vrkiu_chip)); 189 chip->kc_iot = iot; 190 chip->kc_ioh = ioh; 191 chip->kc_enabled = 0; 192 193 chip->kc_if.hii_ctx = chip; 194 chip->kc_if.hii_establish = vrkiu_input_establish; 195 chip->kc_if.hii_poll = vrkiu_poll; 196 197 /* set KIU */ 198 vrkiu_write(chip, KIURST, 1); /* reset */ 199 vrkiu_write(chip, KIUSCANLINE, 0); /* 96keys */ 200 vrkiu_write(chip, KIUWKS, 0x18a4); /* XXX: scan timing! */ 201 vrkiu_write(chip, KIUWKI, 450); 202 vrkiu_write(chip, KIUSCANREP, 0x8023); 203 /* KEYEN | STPREP = 2 | ATSTP | ATSCAN */ 204 205 return (0); 206 } 207 208 int 209 vrkiu_intr(void *arg) 210 { 211 struct vrkiu_softc *sc = arg; 212 213 /* When key scan finisshed, this entry is called. */ 214 #if 0 215 DPRINTF(("vrkiu_intr: intr=%x scan=%x\n", 216 vrkiu_read(sc->sc_chip, KIUINT) & 7, 217 vrkiu_read(sc->sc_chip, KIUSCANS) & KIUSCANS_SSTAT_MASK)); 218 #endif 219 220 /* 221 * First, we must clear the interrupt register because 222 * vrkiu_scan() may takes long time if a bitmap screen 223 * scrolls up and it makes us to miss some key release 224 * event. 225 */ 226 vrkiu_write(sc->sc_chip, KIUINT, 0x7); /* Clear all interrupt */ 227 228 #if 1 229 /* just return if kiu is scanning keyboard. */ 230 if ((vrkiu_read(sc->sc_chip, KIUSCANS) & KIUSCANS_SSTAT_MASK) == 231 KIUSCANS_SSTAT_SCANNING) 232 return (0); 233 #endif 234 vrkiu_scan(sc->sc_chip); 235 236 return (0); 237 } 238 239 static int 240 countbits(int d) 241 { 242 int i, n; 243 244 for (i = 0, n = 0; i < NBBY; i++) 245 if (d & (1 << i)) 246 n++; 247 return (n); 248 } 249 250 static void 251 eliminate_phantom_keys(struct vrkiu_chip *chip, unsigned short *scandata) 252 { 253 unsigned char inkey[KIU_NSCANLINE], *prevkey, *reskey; 254 int i, j; 255 #ifdef VRKIUDEBUG 256 int modified = 0; 257 static int prevmod = 0; 258 #endif 259 260 reskey = (unsigned char *)scandata; 261 for (i = 0; i < KIU_NSCANLINE; i++) 262 inkey[i] = reskey[i]; 263 prevkey = (unsigned char *)chip->kc_scandata; 264 265 for (i = 0; i < KIU_NSCANLINE; i++) { 266 if (countbits(inkey[i]) > 1) { 267 for (j = 0; j < KIU_NSCANLINE; j++) { 268 if (i != j && (inkey[i] & inkey[j])) { 269 #ifdef VRKIUDEBUG 270 modified = 1; 271 if (!prevmod) { 272 DPRINTF(("vrkiu_scan: %x:%02x->%02x", 273 i, inkey[i], prevkey[i])); 274 DPRINTF((" %x:%02x->%02x\n", 275 j, inkey[j], prevkey[j])); 276 } 277 #endif 278 reskey[i] = prevkey[i]; 279 reskey[j] = prevkey[j]; 280 } 281 } 282 } 283 } 284 #ifdef VRKIUDEBUG 285 prevmod = modified; 286 #endif 287 } 288 289 static void 290 vrkiu_scan(struct vrkiu_chip* chip) 291 { 292 int i, j, modified, mask; 293 unsigned short scandata[KIU_NSCANLINE/2]; 294 295 if (!chip->kc_enabled) 296 return; 297 298 for (i = 0; i < KIU_NSCANLINE / 2; i++) { 299 scandata[i] = vrkiu_read(chip, KIUDATP + i * 2); 300 } 301 eliminate_phantom_keys(chip, scandata); 302 303 for (i = 0; i < KIU_NSCANLINE / 2; i++) { 304 modified = scandata[i] ^ chip->kc_scandata[i]; 305 chip->kc_scandata[i] = scandata[i]; 306 mask = 1; 307 for (j = 0; j < 16; j++, mask <<= 1) { 308 /* 309 * Simultaneous keypresses are resolved by registering 310 * the one with the lowest bit index first. 311 */ 312 if (modified & mask) { 313 int key = i * 16 + j; 314 DPRINTF(("vrkiu_scan: %s(%d,%d)\n", 315 (scandata[i] & mask) ? "down" : "up", 316 i, j)); 317 hpckbd_input(chip->kc_hpckbd, 318 (scandata[i] & mask), key); 319 } 320 } 321 } 322 } 323 324 /* called from bicons.c */ 325 int 326 vrkiu_getc() 327 { 328 static int flag = 1; 329 330 /* 331 * XXX, currently 332 */ 333 if (flag) { 334 flag = 0; 335 printf("%s(%d): vrkiu_getc() is not implemented\n", 336 __FILE__, __LINE__); 337 } 338 return (0); 339 } 340 341 /* 342 * hpckbd interface routines 343 */ 344 int 345 vrkiu_input_establish(void *ic, struct hpckbd_if *kbdif) 346 { 347 struct vrkiu_chip *kc = ic; 348 349 /* save hpckbd interface */ 350 kc->kc_hpckbd = kbdif; 351 352 kc->kc_enabled = 1; 353 354 return (0); 355 } 356 357 int 358 vrkiu_poll(void *ic) 359 { 360 struct vrkiu_chip *kc = ic; 361 362 #if 1 363 /* wait until kiu completes keyboard scan. */ 364 while ((vrkiu_read(kc, KIUSCANS) & KIUSCANS_SSTAT_MASK) == 365 KIUSCANS_SSTAT_SCANNING) 366 /* wait until kiu completes keyboard scan */; 367 #endif 368 369 vrkiu_scan(kc); 370 371 return (0); 372 } 373 374 /* 375 * console support routine 376 */ 377 int 378 vrkiu_cnattach(bus_space_tag_t iot, int iobase) 379 { 380 static struct vrkiu_chip vrkiu_consdata_body; 381 bus_space_handle_t ioh; 382 383 if (vrkiu_consdata) { 384 panic("vrkiu is already attached as the console"); 385 } 386 if (bus_space_map(iot, iobase, 1, 0, &ioh)) { 387 printf("%s(%d): can't map bus space\n", __FILE__, __LINE__); 388 return (-1); 389 } 390 391 if (vrkiu_init(&vrkiu_consdata_body, iot, ioh) != 0) { 392 DPRINTF(("%s(%d): vrkiu_init() failed\n", __FILE__, __LINE__)); 393 return (-1); 394 } 395 vrkiu_consdata = &vrkiu_consdata_body; 396 397 hpckbd_cnattach(&vrkiu_consdata_body.kc_if); 398 399 return (0); 400 } 401