1 /* $NetBSD: zs_kbd.c,v 1.10 2012/10/29 12:51:38 chs Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Steve Rumble 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * IP12/IP20 serial keyboard driver attached to zs channel 0 at 600bps. 32 * This layer is the parent of wskbd. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: zs_kbd.c,v 1.10 2012/10/29 12:51:38 chs Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/malloc.h> 40 #include <sys/systm.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wscons/wskbdvar.h> 46 #include <dev/wscons/wsksymdef.h> 47 #include <dev/wscons/wsksymvar.h> 48 49 #include <dev/ic/z8530reg.h> 50 #include <machine/machtype.h> 51 #include <machine/z8530var.h> 52 53 #define ZSKBD_BAUD 600 54 #define ZSKBD_TXQ_LEN 16 /* power of 2 */ 55 #define ZSKBD_RXQ_LEN 64 /* power of 2 */ 56 57 #define ZSKBD_DIP_SYNC 0x6E 58 #define ZSKBD_KEY_UP 0x80 59 60 #ifdef ZSKBD_DEBUG 61 int zskbd_debug = 0; 62 63 #define DPRINTF(_x) if (zskbd_debug) printf _x 64 #else 65 #define DPRINTF(_x) 66 #endif 67 68 struct zskbd_softc { 69 device_t sc_dev; 70 71 struct zskbd_devconfig *sc_dc; 72 }; 73 74 struct zskbd_devconfig { 75 /* transmit tail-chasing fifo */ 76 uint8_t txq[ZSKBD_TXQ_LEN]; 77 u_int txq_head; 78 u_int txq_tail; 79 80 /* receive tail-chasing fifo */ 81 uint8_t rxq[ZSKBD_RXQ_LEN]; 82 u_int rxq_head; 83 u_int rxq_tail; 84 85 /* state */ 86 #define TX_READY 0x1 87 #define RX_DIP 0x2 88 u_int state; 89 90 /* keyboard configuration */ 91 #define ZSKBD_CTRL_A 0x0 92 #define ZSKBD_CTRL_A_SBEEP 0x2 /* 200 ms */ 93 #define ZSKBD_CTRL_A_LBEEP 0x4 /* 1000 ms */ 94 #define ZSKBD_CTRL_A_NOCLICK 0x8 /* turn off keyboard click */ 95 #define ZSKBD_CTRL_A_RCB 0x10 /* request config byte */ 96 #define ZSKBD_CTRL_A_NUMLK 0x20 /* num lock led */ 97 #define ZSKBD_CTRL_A_CAPSLK 0x40 /* caps lock led */ 98 #define ZSKBD_CTRL_A_AUTOREP 0x80 /* auto-repeat after 650 ms, 28x/sec */ 99 100 #define ZSKBD_CTRL_B 0x1 101 #define ZSKBD_CTRL_B_CMPL_DS1_2 0x2 /* complement of ds1+ds2 (num+capslk) */ 102 #define ZSKBD_CTRL_B_SCRLK 0x4 /* scroll lock light */ 103 #define ZSKBD_CTRL_B_L1 0x8 /* user-configurable lights */ 104 #define ZSKBD_CTRL_B_L2 0x10 105 #define ZSKBD_CTRL_B_L3 0x20 106 #define ZSKBD_CTRL_B_L4 0x40 107 uint8_t kbd_conf[2]; 108 109 /* dip switch settings */ 110 uint8_t dip; 111 112 /* wscons glue */ 113 device_t wskbddev; 114 int enabled; 115 }; 116 117 static int zskbd_match(device_t, cfdata_t, void *); 118 static void zskbd_attach(device_t, device_t, void *); 119 static void zskbd_rxint(struct zs_chanstate *); 120 static void zskbd_stint(struct zs_chanstate *, int); 121 static void zskbd_txint(struct zs_chanstate *); 122 static void zskbd_softint(struct zs_chanstate *); 123 static void zskbd_send(struct zs_chanstate *, uint8_t *, u_int); 124 static void zskbd_ctrl(struct zs_chanstate *, uint8_t, uint8_t, 125 uint8_t, uint8_t); 126 127 static void zskbd_wskbd_input(struct zs_chanstate *, uint8_t); 128 static int zskbd_wskbd_enable(void *, int); 129 static void zskbd_wskbd_set_leds(void *, int); 130 static int zskbd_wskbd_get_leds(void *); 131 static void zskbd_wskbd_set_keyclick(void *, int); 132 static int zskbd_wskbd_get_keyclick(void *); 133 static int zskbd_wskbd_ioctl(void *, u_long, void *, int, struct lwp *); 134 135 void zskbd_cnattach(int, int); 136 static void zskbd_wskbd_getc(void *, u_int *, int *); 137 static void zskbd_wskbd_pollc(void *, int); 138 static void zskbd_wskbd_bell(void *, u_int, u_int, u_int); 139 140 extern struct zschan *zs_get_chan_addr(int, int); 141 extern int zs_getc(void *); 142 extern void zs_putc(void *, int); 143 144 CFATTACH_DECL_NEW(zskbd, sizeof(struct zskbd_softc), 145 zskbd_match, zskbd_attach, NULL, NULL); 146 147 static struct zsops zskbd_zsops = { 148 zskbd_rxint, 149 zskbd_stint, 150 zskbd_txint, 151 zskbd_softint 152 }; 153 154 extern const struct wscons_keydesc wssgi_keydesctab[]; 155 const struct wskbd_mapdata sgikbd_wskbd_keymapdata = { 156 wssgi_keydesctab, KB_US 157 }; 158 159 const struct wskbd_accessops zskbd_wskbd_accessops = { 160 zskbd_wskbd_enable, 161 zskbd_wskbd_set_leds, 162 zskbd_wskbd_ioctl 163 }; 164 165 const struct wskbd_consops zskbd_wskbd_consops = { 166 zskbd_wskbd_getc, 167 zskbd_wskbd_pollc, 168 zskbd_wskbd_bell 169 }; 170 171 static struct zskbd_devconfig zskbd_console_dc; 172 static int zskbd_is_console = 0; 173 174 static int 175 zskbd_match(device_t parent, cfdata_t cf, void *aux) 176 { 177 178 if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20) { 179 struct zsc_attach_args *args = aux; 180 181 if (args->channel == 0) 182 return (1); 183 } 184 185 return (0); 186 } 187 188 static void 189 zskbd_attach(device_t parent, device_t self, void *aux) 190 { 191 struct zskbd_softc *sc; 192 struct zs_chanstate *cs; 193 struct zsc_softc *zsc; 194 struct zsc_attach_args *args; 195 struct wskbddev_attach_args wskaa; 196 int s, channel; 197 198 zsc = device_private(parent); 199 sc = device_private(self); 200 sc->sc_dev = self; 201 args = aux; 202 203 /* Establish ourself with the MD z8530 driver */ 204 channel = args->channel; 205 cs = zsc->zsc_cs[channel]; 206 cs->cs_ops = &zskbd_zsops; 207 cs->cs_private = sc; 208 209 if (zskbd_is_console) { 210 sc->sc_dc = &zskbd_console_dc; 211 wskaa.console = 1; 212 sc->sc_dc->enabled = 1; 213 } else { 214 wskaa.console = 0; 215 216 sc->sc_dc = malloc(sizeof(struct zskbd_devconfig), M_DEVBUF, 217 M_WAITOK); 218 if (sc->sc_dc == NULL) 219 panic("zskbd out of memory"); 220 221 sc->sc_dc->enabled = 0; 222 } 223 224 sc->sc_dc->txq_head = 0; 225 sc->sc_dc->txq_tail = 0; 226 sc->sc_dc->rxq_head = 0; 227 sc->sc_dc->rxq_tail = 0; 228 sc->sc_dc->state = TX_READY; 229 sc->sc_dc->dip = 0; 230 sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] = 0; 231 sc->sc_dc->kbd_conf[ZSKBD_CTRL_B] = 0; 232 233 aprint_normal(": baud rate %d\n", ZSKBD_BAUD); 234 235 s = splzs(); 236 zs_write_reg(cs, 9, (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET); 237 cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE; 238 cs->cs_preg[4] = (cs->cs_preg[4] & ZSWR4_CLK_MASK) | 239 (ZSWR4_ONESB | ZSWR4_PARENB); /* 1 stop, odd parity */ 240 zs_set_speed(cs, ZSKBD_BAUD); 241 zs_loadchannelregs(cs); 242 243 /* request DIP switch settings just in case */ 244 zskbd_ctrl(cs, ZSKBD_CTRL_A_RCB, 0, 0, 0); 245 246 splx(s); 247 248 /* attach wskbd */ 249 wskaa.keymap = &sgikbd_wskbd_keymapdata; 250 wskaa.accessops = &zskbd_wskbd_accessops; 251 wskaa.accesscookie = cs; 252 sc->sc_dc->wskbddev = config_found(self, &wskaa, wskbddevprint); 253 } 254 255 static void 256 zskbd_rxint(struct zs_chanstate *cs) 257 { 258 struct zskbd_softc *sc; 259 struct zskbd_devconfig *dc; 260 uint8_t c, r; 261 262 sc = cs->cs_private; 263 dc = sc->sc_dc; 264 265 /* clear errors */ 266 r = zs_read_reg(cs, 1); 267 if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) 268 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 269 270 /* read byte and append to our queue */ 271 c = zs_read_data(cs); 272 273 dc->rxq[dc->rxq_tail] = c; 274 dc->rxq_tail = (dc->rxq_tail + 1) & ~ZSKBD_RXQ_LEN; 275 276 cs->cs_softreq = 1; 277 } 278 279 static void 280 zskbd_stint(struct zs_chanstate *cs, int force) 281 { 282 283 zs_write_csr(cs, ZSWR0_RESET_STATUS); 284 cs->cs_softreq = 1; 285 } 286 287 static void 288 zskbd_txint(struct zs_chanstate *cs) 289 { 290 struct zskbd_softc *sc; 291 292 sc = cs->cs_private; 293 zs_write_reg(cs, 0, ZSWR0_RESET_TXINT); 294 sc->sc_dc->state |= TX_READY; 295 cs->cs_softreq = 1; 296 } 297 298 static void 299 zskbd_softint(struct zs_chanstate *cs) 300 { 301 struct zskbd_softc *sc; 302 struct zskbd_devconfig *dc; 303 304 sc = cs->cs_private; 305 dc = sc->sc_dc; 306 307 /* handle pending transmissions */ 308 if (dc->txq_head != dc->txq_tail && (dc->state & TX_READY)) { 309 int s; 310 311 dc->state &= ~TX_READY; 312 313 s = splzs(); 314 zs_write_data(cs, dc->txq[dc->txq_head]); 315 splx(s); 316 317 dc->txq_head = (dc->txq_head + 1) & ~ZSKBD_TXQ_LEN; 318 } 319 320 /* don't bother if nobody is listening */ 321 if (!dc->enabled) { 322 dc->rxq_head = dc->rxq_tail; 323 return; 324 } 325 326 /* handle incoming keystrokes/config */ 327 while (dc->rxq_head != dc->rxq_tail) { 328 uint8_t key = dc->rxq[dc->rxq_head]; 329 330 if (dc->state & RX_DIP) { 331 dc->dip = key; 332 dc->state &= ~RX_DIP; 333 } else if (key == ZSKBD_DIP_SYNC) { 334 dc->state |= RX_DIP; 335 } else { 336 /* toss wskbd a bone */ 337 zskbd_wskbd_input(cs, key); 338 } 339 340 dc->rxq_head = (dc->rxq_head + 1) & ~ZSKBD_RXQ_LEN; 341 } 342 } 343 344 /* expects to be in splzs() */ 345 static void 346 zskbd_send(struct zs_chanstate *cs, uint8_t *c, u_int len) 347 { 348 u_int i; 349 struct zskbd_softc *sc; 350 struct zskbd_devconfig *dc; 351 352 sc = cs->cs_private; 353 dc = sc->sc_dc; 354 355 for (i = 0; i < len; i++) { 356 if (dc->state & TX_READY) { 357 zs_write_data(cs, c[i]); 358 dc->state &= ~TX_READY; 359 } else { 360 dc->txq[dc->txq_tail] = c[i]; 361 dc->txq_tail = (dc->txq_tail + 1) & ~ZSKBD_TXQ_LEN; 362 cs->cs_softreq = 1; 363 } 364 } 365 } 366 367 /* expects to be in splzs() */ 368 static void 369 zskbd_ctrl(struct zs_chanstate *cs, uint8_t a_on, uint8_t a_off, 370 uint8_t b_on, uint8_t b_off) 371 { 372 struct zskbd_softc *sc; 373 struct zskbd_devconfig *dc; 374 375 sc = cs->cs_private; 376 dc = sc->sc_dc; 377 378 dc->kbd_conf[ZSKBD_CTRL_A] |= a_on; 379 dc->kbd_conf[ZSKBD_CTRL_A] &= ~(a_off | ZSKBD_CTRL_B); 380 dc->kbd_conf[ZSKBD_CTRL_B] &= ~b_off; 381 dc->kbd_conf[ZSKBD_CTRL_B] |= (b_on | ZSKBD_CTRL_B); 382 383 zskbd_send(cs, dc->kbd_conf, 2); 384 385 /* make sure we don't resend these each time */ 386 dc->kbd_conf[ZSKBD_CTRL_A] &= ~(ZSKBD_CTRL_A_RCB | ZSKBD_CTRL_A_SBEEP | 387 ZSKBD_CTRL_A_LBEEP); 388 } 389 390 /****************************************************************************** 391 * wskbd glue 392 ******************************************************************************/ 393 394 static void 395 zskbd_wskbd_input(struct zs_chanstate *cs, uint8_t key) 396 { 397 struct zskbd_softc *sc; 398 u_int type; 399 400 sc = cs->cs_private; 401 402 if (key & ZSKBD_KEY_UP) 403 type = WSCONS_EVENT_KEY_UP; 404 else 405 type = WSCONS_EVENT_KEY_DOWN; 406 407 wskbd_input(sc->sc_dc->wskbddev, type, (key & ~ZSKBD_KEY_UP)); 408 409 DPRINTF(("zskbd_wskbd_input: inputted key 0x%x\n", key)); 410 411 #ifdef WSDISPLAY_COMPAT_RAWKBD 412 wskbd_rawinput(sc->sc_dc->wskbddev, &key, 1); 413 #endif 414 } 415 416 static int 417 zskbd_wskbd_enable(void *cookie, int on) 418 { 419 struct zskbd_softc *sc; 420 struct zs_chanstate *cs; 421 422 cs = cookie; 423 sc = cs->cs_private; 424 425 if (on) { 426 if (sc->sc_dc->enabled) 427 return (EBUSY); 428 else 429 sc->sc_dc->enabled = 1; 430 } else 431 sc->sc_dc->enabled = 0; 432 433 DPRINTF(("zskbd_wskbd_enable: %s\n", on ? "enabled" : "disabled")); 434 435 return (0); 436 } 437 438 static void 439 zskbd_wskbd_set_leds(void *cookie, int leds) 440 { 441 struct zs_chanstate *cs; 442 int s; 443 uint8_t a_on, a_off, b_on, b_off; 444 445 a_on = a_off = b_on = b_off = 0; 446 447 if (leds & WSKBD_LED_CAPS) 448 a_on |= ZSKBD_CTRL_A_CAPSLK; 449 else 450 a_off |= ZSKBD_CTRL_A_CAPSLK; 451 452 if (leds & WSKBD_LED_NUM) 453 a_on |= ZSKBD_CTRL_A_NUMLK; 454 else 455 a_off |= ZSKBD_CTRL_A_NUMLK; 456 457 if (leds & WSKBD_LED_SCROLL) 458 b_on |= ZSKBD_CTRL_B_SCRLK; 459 else 460 b_off |= ZSKBD_CTRL_B_SCRLK; 461 462 cs = cookie; 463 s = splzs(); 464 zskbd_ctrl(cs, a_on, a_off, b_on, b_off); 465 splx(s); 466 } 467 468 static int 469 zskbd_wskbd_get_leds(void *cookie) 470 { 471 struct zskbd_softc *sc; 472 struct zs_chanstate *cs; 473 int leds; 474 475 cs = cookie; 476 sc = cs->cs_private; 477 leds = 0; 478 479 if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_NUMLK) 480 leds |= WSKBD_LED_NUM; 481 482 if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_CAPSLK) 483 leds |= WSKBD_LED_CAPS; 484 485 if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_B] & ZSKBD_CTRL_B_SCRLK) 486 leds |= WSKBD_LED_SCROLL; 487 488 return (leds); 489 } 490 491 static void 492 zskbd_wskbd_set_keyclick(void *cookie, int on) 493 { 494 int s; 495 struct zs_chanstate *cs; 496 497 cs = cookie; 498 499 if (on) { 500 if (!zskbd_wskbd_get_keyclick(cookie)) { 501 s = splzs(); 502 zskbd_ctrl(cs, 0, ZSKBD_CTRL_A_NOCLICK, 0, 0); 503 splx(s); 504 } 505 } else { 506 if (zskbd_wskbd_get_keyclick(cookie)) { 507 s = splzs(); 508 zskbd_ctrl(cs, ZSKBD_CTRL_A_NOCLICK, 0, 0, 0); 509 splx(s); 510 } 511 } 512 } 513 514 static int 515 zskbd_wskbd_get_keyclick(void *cookie) 516 { 517 struct zskbd_softc *sc; 518 struct zs_chanstate *cs; 519 520 cs = cookie; 521 sc = cs->cs_private; 522 523 if (sc->sc_dc->kbd_conf[ZSKBD_CTRL_A] & ZSKBD_CTRL_A_NOCLICK) 524 return (0); 525 else 526 return (1); 527 } 528 529 static int 530 zskbd_wskbd_ioctl(void *cookie, u_long cmd, 531 void *data, int flag, struct lwp *l) 532 { 533 534 switch (cmd) { 535 case WSKBDIO_GTYPE: 536 *(int *)data = WSKBD_TYPE_SGI; 537 break; 538 539 #ifdef notyet 540 case WSKBDIO_BELL: 541 case WSKBDIO_COMPLEXBELL: 542 case WSKBDIO_SETBELL: 543 case WSKBDIO_GETBELL: 544 case WSKBDIO_SETDEFAULTBELL: 545 case WSKBDIO_GETDEFAULTBELL: 546 case WSKBDIO_SETKEYREPEAT: 547 case WSKBDIO_GETKEYREPEAT: 548 case WSKBDIO_SETDEFAULTKEYREPEAT: 549 case WSKBDIO_GETDEFAULTKEYREPEAT: 550 #endif 551 552 case WSKBDIO_SETLEDS: 553 zskbd_wskbd_set_leds(cookie, *(int *)data); 554 break; 555 556 case WSKBDIO_GETLEDS: 557 *(int *)data = zskbd_wskbd_get_leds(cookie); 558 break; 559 560 #ifdef notyet 561 case WSKBDIO_GETMAP: 562 case WSKBDIO_SETMAP: 563 case WSKBDIO_GETENCODING: 564 case WSKBDIO_SETENCODING: 565 case WSKBDIO_SETMODE: 566 case WSKBDIO_GETMODE: 567 #endif 568 569 case WSKBDIO_SETKEYCLICK: 570 zskbd_wskbd_set_keyclick(cookie, *(int *)data); 571 break; 572 573 case WSKBDIO_GETKEYCLICK: 574 *(int *)data = zskbd_wskbd_get_keyclick(cookie); 575 break; 576 577 default: 578 return (EPASSTHROUGH); 579 } 580 581 return (0); 582 } 583 584 /* 585 * console routines 586 */ 587 void 588 zskbd_cnattach(int zsunit, int zschan) 589 { 590 591 wskbd_cnattach(&zskbd_wskbd_consops, zs_get_chan_addr(zsunit, zschan), 592 &sgikbd_wskbd_keymapdata); 593 zskbd_is_console = 1; 594 } 595 596 static void 597 zskbd_wskbd_getc(void *cookie, u_int *type, int *data) 598 { 599 int key; 600 601 key = zs_getc(cookie); 602 603 if (key & ZSKBD_KEY_UP) 604 *type = WSCONS_EVENT_KEY_UP; 605 else 606 *type = WSCONS_EVENT_KEY_DOWN; 607 608 *data = key & ~ZSKBD_KEY_UP; 609 } 610 611 static void 612 zskbd_wskbd_pollc(void *cookie, int on) 613 { 614 } 615 616 static void 617 zskbd_wskbd_bell(void *cookie, u_int pitch, u_int period, u_int volume) 618 { 619 620 /* 621 * Since we don't have any state, this'll nuke our lights, 622 * key click, and other bits in ZSKBD_CTRL_A. 623 */ 624 if (period >= 1000) 625 zs_putc(cookie, ZSKBD_CTRL_A_LBEEP); 626 else 627 zs_putc(cookie, ZSKBD_CTRL_A_SBEEP); 628 } 629