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