1 /* $NetBSD: nextkbd.c,v 1.16 2020/11/21 17:49:20 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> 33 __KERNEL_RCSID(0, "$NetBSD: nextkbd.c,v 1.16 2020/11/21 17:49:20 thorpej Exp $"); 34 35 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/proc.h> 41 #include <sys/device.h> 42 #include <sys/kmem.h> 43 #include <sys/errno.h> 44 #include <sys/queue.h> 45 #include <sys/bus.h> 46 #include <sys/cpu.h> 47 #include <sys/intr.h> 48 49 #include <machine/autoconf.h> 50 51 #include <dev/wscons/wsconsio.h> 52 #include <dev/wscons/wskbdvar.h> 53 #include <dev/wscons/wsksymdef.h> 54 #include <dev/wscons/wsksymvar.h> 55 56 #include <next68k/dev/nextkbdvar.h> 57 #include <next68k/dev/wskbdmap_next.h> 58 59 #include <next68k/next68k/isr.h> 60 61 #include <next68k/dev/intiovar.h> 62 63 struct nextkbd_internal { 64 int num_ints; /* interrupt total */ 65 int polling; 66 int isconsole; 67 68 bus_space_tag_t iot; 69 bus_space_handle_t ioh; 70 struct nextkbd_softc *t_sc; /* back pointer */ 71 u_int32_t mods; 72 }; 73 74 struct mon_regs { 75 u_int32_t mon_csr; 76 u_int32_t mon_1; 77 u_int32_t mon_data; 78 }; 79 80 static int attached = 0; 81 82 int nextkbd_match(device_t, cfdata_t, void *); 83 void nextkbd_attach(device_t, device_t, void *); 84 85 int nextkbc_cnattach(bus_space_tag_t); 86 87 CFATTACH_DECL_NEW(nextkbd, sizeof(struct nextkbd_softc), 88 nextkbd_match, nextkbd_attach, NULL, NULL); 89 90 int nextkbd_enable(void *, int); 91 void nextkbd_set_leds(void *, int); 92 int nextkbd_ioctl(void *, u_long, void *, int, struct lwp *); 93 94 const struct wskbd_accessops nextkbd_accessops = { 95 nextkbd_enable, 96 nextkbd_set_leds, 97 nextkbd_ioctl, 98 }; 99 100 void nextkbd_cngetc(void *, u_int *, int *); 101 void nextkbd_cnpollc(void *, int); 102 103 const struct wskbd_consops nextkbd_consops = { 104 nextkbd_cngetc, 105 nextkbd_cnpollc, 106 }; 107 108 const struct wskbd_mapdata nextkbd_keymapdata = { 109 nextkbd_keydesctab, 110 KB_US, 111 }; 112 113 static int nextkbd_read_data(struct nextkbd_internal *); 114 static int nextkbd_decode(struct nextkbd_internal *, int, u_int *, int *); 115 116 static struct nextkbd_internal nextkbd_consdata; 117 static int nextkbd_is_console(bus_space_tag_t); 118 119 int nextkbdhard(void *); 120 121 static int 122 nextkbd_is_console(bus_space_tag_t bst) 123 { 124 return (nextkbd_consdata.isconsole && (bst == nextkbd_consdata.iot)); 125 } 126 127 int 128 nextkbd_match(device_t parent, cfdata_t match, void *aux) 129 { 130 struct intio_attach_args *ia = (struct intio_attach_args *)aux; 131 132 if (attached) 133 return(0); 134 135 ia->ia_addr = (void *)NEXT_P_MON; 136 137 return(1); 138 } 139 140 void 141 nextkbd_attach(device_t parent, device_t self, void *aux) 142 { 143 struct nextkbd_softc *sc = device_private(self); 144 struct intio_attach_args *ia = (struct intio_attach_args *)aux; 145 int isconsole; 146 struct wskbddev_attach_args a; 147 148 printf("\n"); 149 150 isconsole = nextkbd_is_console(ia->ia_bst); /* XXX */ 151 152 if (isconsole) { 153 sc->id = &nextkbd_consdata; 154 } else { 155 sc->id = kmem_zalloc(sizeof(struct nextkbd_internal), 156 KM_SLEEP); 157 158 sc->id->iot = ia->ia_bst; 159 if (bus_space_map(sc->id->iot, NEXT_P_MON, 160 sizeof(struct mon_regs), 161 0, &sc->id->ioh)) { 162 printf("%s: can't map mon status control register\n", 163 device_xname(self)); 164 return; 165 } 166 } 167 168 sc->id->t_sc = sc; /* set back pointer */ 169 170 isrlink_autovec(nextkbdhard, sc, NEXT_I_IPL(NEXT_I_KYBD_MOUSE), 0, NULL); 171 172 INTR_ENABLE(NEXT_I_KYBD_MOUSE); 173 174 a.console = isconsole; 175 a.keymap = &nextkbd_keymapdata; 176 a.accessops = &nextkbd_accessops; 177 a.accesscookie = sc; 178 179 /* 180 * Attach the wskbd, saving a handle to it. 181 * XXX XXX XXX 182 */ 183 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 184 185 attached = 1; 186 } 187 188 int 189 nextkbd_enable(void *v, int on) 190 { 191 /* XXX not sure if this should do anything */ 192 /* printf("nextkbd_enable %d\n", on); */ 193 return 0; 194 } 195 196 void 197 nextkbd_set_leds(void *v, int leds) 198 { 199 struct nextkbd_softc *sc = v; 200 uint32_t hw_leds = 0; 201 int s; 202 203 sc->sc_leds &= ~ NEXT_WSKBD_LEDS; 204 sc->sc_leds |= (leds & NEXT_WSKBD_LEDS); 205 206 if (sc->sc_leds & WSKBD_LED_CAPS) { 207 hw_leds |= 0x30000; 208 } 209 210 s = spltty(); 211 bus_space_write_1(sc->id->iot, sc->id->ioh, 3, 0xc5); 212 /* @@@ need to add: 213 if bit 7 of @ioh+0 set: 214 repeat 2 215 wait until bit 6 of @ioh+2 clears 216 */ 217 bus_space_write_4(sc->id->iot, sc->id->ioh, 4, hw_leds); 218 /* @@@ need to add: 219 wait until bit 4 of @ioh+0 (@ioh+2 if bit 7 was set above) 220 clears 221 */ 222 splx(s); 223 224 return; 225 } 226 227 int 228 nextkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 229 { 230 struct nextkbd_softc *sc = v; 231 232 switch (cmd) { 233 case WSKBDIO_GTYPE: 234 /* XXX */ 235 *(int *)data = WSKBD_TYPE_NEXT; 236 return (0); 237 case WSKBDIO_SETLEDS: 238 nextkbd_set_leds (sc, *(int *)data); 239 return (0); 240 case WSKBDIO_GETLEDS: 241 *(int *)data = sc->sc_leds & NEXT_WSKBD_LEDS; 242 return (0); 243 case WSKBDIO_COMPLEXBELL: 244 return (0); 245 } 246 return EPASSTHROUGH; 247 } 248 249 int 250 nextkbdhard(void *arg) 251 { 252 struct nextkbd_softc *sc = arg; 253 int type, key, val; 254 255 if (!INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) return 0; 256 257 #define CSR_INT 0x00800000 258 #define CSR_DATA 0x00400000 259 260 #define KD_KEYMASK 0x007f 261 #define KD_DIRECTION 0x0080 /* pressed or released */ 262 #define KD_CNTL 0x0100 263 #define KD_LSHIFT 0x0200 264 #define KD_RSHIFT 0x0400 265 #define KD_LCOMM 0x0800 266 #define KD_RCOMM 0x1000 267 #define KD_LALT 0x2000 268 #define KD_RALT 0x4000 269 #define KD_VALID 0x8000 /* only set for scancode keys ? */ 270 #define KD_MODS 0x4f00 271 272 val = nextkbd_read_data(sc->id); 273 if ((val != -1) && nextkbd_decode(sc->id, val, &type, &key)) { 274 wskbd_input(sc->sc_wskbddev, type, key); 275 } 276 return(1); 277 } 278 279 int 280 nextkbd_cnattach(bus_space_tag_t bst) 281 { 282 bus_space_handle_t bsh; 283 284 if (bus_space_map(bst, NEXT_P_MON, sizeof(struct mon_regs), 285 0, &bsh)) 286 return (ENXIO); 287 288 memset(&nextkbd_consdata, 0, sizeof(nextkbd_consdata)); 289 290 nextkbd_consdata.iot = bst; 291 nextkbd_consdata.ioh = bsh; 292 nextkbd_consdata.isconsole = 1; 293 294 wskbd_cnattach(&nextkbd_consops, &nextkbd_consdata, 295 &nextkbd_keymapdata); 296 297 return (0); 298 } 299 300 void 301 nextkbd_cngetc(void *v, u_int *type, int *data) 302 { 303 struct nextkbd_internal *t = v; 304 int val; 305 306 for (;;) { 307 if (INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) { 308 val = nextkbd_read_data(t); 309 if ((val != -1) && nextkbd_decode(t, val, type, data)) 310 return; 311 } 312 } 313 } 314 315 void 316 nextkbd_cnpollc(void *v, int on) 317 { 318 struct nextkbd_internal *t = v; 319 320 t->polling = on; 321 if (on) { 322 INTR_DISABLE(NEXT_I_KYBD_MOUSE); 323 } else { 324 INTR_ENABLE(NEXT_I_KYBD_MOUSE); 325 } 326 327 } 328 329 static int 330 nextkbd_read_data(struct nextkbd_internal *id) 331 { 332 unsigned char device; 333 struct mon_regs stat = { 0 }; 334 335 bus_space_read_region_4(id->iot, id->ioh, 0, &stat, 3); 336 if ((stat.mon_csr & CSR_INT) && (stat.mon_csr & CSR_DATA)) { 337 stat.mon_csr &= ~CSR_INT; 338 id->num_ints++; 339 bus_space_write_4(id->iot, id->ioh, 0, stat.mon_csr); 340 device = stat.mon_data >> 28; 341 if (device != 1) return (-1); /* XXX: mouse */ 342 return (stat.mon_data & 0xffff); 343 } 344 return (-1); 345 } 346 347 static int 348 nextkbd_decode(struct nextkbd_internal *id, int datain, u_int *type, 349 int *dataout) 350 { 351 /* printf("datain %08x mods %08x\n", datain, id->mods); */ 352 353 if ((datain ^ id->mods) & KD_LSHIFT) { 354 id->mods ^= KD_LSHIFT; 355 *dataout = 90; 356 if (datain & KD_LSHIFT) 357 *type = WSCONS_EVENT_KEY_DOWN; 358 else 359 *type = WSCONS_EVENT_KEY_UP; 360 } else if ((datain ^ id->mods) & KD_RSHIFT) { 361 id->mods ^= KD_RSHIFT; 362 *dataout = 91; 363 if (datain & KD_RSHIFT) 364 *type = WSCONS_EVENT_KEY_DOWN; 365 else 366 *type = WSCONS_EVENT_KEY_UP; 367 } else if ((datain ^ id->mods) & KD_LALT) { 368 id->mods ^= KD_LALT; 369 *dataout = 92; 370 if (datain & KD_LALT) 371 *type = WSCONS_EVENT_KEY_DOWN; 372 else 373 *type = WSCONS_EVENT_KEY_UP; 374 } else if ((datain ^ id->mods) & KD_RALT) { 375 id->mods ^= KD_RALT; 376 *dataout = 93; 377 if (datain & KD_RALT) 378 *type = WSCONS_EVENT_KEY_DOWN; 379 else 380 *type = WSCONS_EVENT_KEY_UP; 381 } else if ((datain ^ id->mods) & KD_CNTL) { 382 id->mods ^= KD_CNTL; 383 *dataout = 94; 384 if (datain & KD_CNTL) 385 *type = WSCONS_EVENT_KEY_DOWN; 386 else 387 *type = WSCONS_EVENT_KEY_UP; 388 } else if ((datain ^ id->mods) & KD_LCOMM) { 389 id->mods ^= KD_LCOMM; 390 *dataout = 95; 391 if (datain & KD_LCOMM) 392 *type = WSCONS_EVENT_KEY_DOWN; 393 else 394 *type = WSCONS_EVENT_KEY_UP; 395 } else if ((datain ^ id->mods) & KD_RCOMM) { 396 id->mods ^= KD_RCOMM; 397 *dataout = 96; 398 if (datain & KD_RCOMM) 399 *type = WSCONS_EVENT_KEY_DOWN; 400 else 401 *type = WSCONS_EVENT_KEY_UP; 402 } else if (datain & KD_KEYMASK) { 403 if (datain & KD_DIRECTION) 404 *type = WSCONS_EVENT_KEY_UP; 405 else 406 *type = WSCONS_EVENT_KEY_DOWN; 407 408 *dataout = (datain & KD_KEYMASK); 409 } else { 410 *dataout = 0; 411 } 412 413 return 1; 414 } 415