1/* $NetBSD: ewskbd.c,v 1.8 2008/03/29 19:15:34 tsutsui Exp $ */ 2 3/*- 4 * Copyright (c) 2005 Izumi Tsutsui. 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 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* 28 * Copyright (c) 2004 Steve Rumble 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 3. The name of the author may not be used to endorse or promote products 40 * derived from this software without specific prior written permission. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 43 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 44 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 45 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 46 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 48 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 49 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 51 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 */ 53 54/* 55 * EWS4800 serial keyboard driver attached to zs channel 0 at 4800 bps. 56 * This layer is the parent of wskbd. 57 * 58 * This driver is taken from sgimips. 59 */ 60 61#include <sys/cdefs.h> 62__KERNEL_RCSID(0, "$NetBSD: ewskbd.c,v 1.8 2008/03/29 19:15:34 tsutsui Exp $"); 63 64#include <sys/param.h> 65#include <sys/malloc.h> 66#include <sys/systm.h> 67#include <sys/conf.h> 68#include <sys/device.h> 69 70#include <dev/wscons/wsconsio.h> 71#include <dev/wscons/wskbdvar.h> 72#include <dev/wscons/wsksymdef.h> 73#include <dev/wscons/wsksymvar.h> 74 75#include <dev/ic/z8530reg.h> 76#include <machine/z8530var.h> 77 78#include <ews4800mips/dev/ews4800keymap.h> 79 80#define EWSKBD_BAUD 4800 81 82#define EWSKBD_TXQ_LEN 16 /* power of 2 */ 83#define EWSKBD_TXQ_LEN_MASK (EWSKBD_TXQ_LEN - 1) 84#define EWSKBD_NEXTTXQ(x) (((x) + 1) & EWSKBD_TXQ_LEN_MASK) 85 86#define EWSKBD_RXQ_LEN 64 /* power of 2 */ 87#define EWSKBD_RXQ_LEN_MASK (EWSKBD_RXQ_LEN - 1) 88#define EWSKBD_NEXTRXQ(x) (((x) + 1) & EWSKBD_RXQ_LEN_MASK) 89 90#define EWSKBD_KEY_UP 0x80 91#define EWSKBD_KEY_MASK 0x7f 92 93#ifdef EWSKBD_DEBUG 94int ewskbd_debug = 0; 95#define DPRINTF(_x) if (ewskbd_debug) printf _x 96#else 97#define DPRINTF(_x) 98#endif 99 100struct ewskbd_softc { 101 device_t sc_dev; 102 struct ewskbd_devconfig *sc_dc; 103}; 104 105struct ewskbd_devconfig { 106 /* transmit tail-chasing fifo */ 107 uint8_t txq[EWSKBD_TXQ_LEN]; 108 u_int txq_head; 109 u_int txq_tail; 110 111 /* receive tail-chasing fifo */ 112 uint8_t rxq[EWSKBD_RXQ_LEN]; 113 u_int rxq_head; 114 u_int rxq_tail; 115 116 /* state */ 117 u_int state; 118#define TX_READY 0x01 119 120 /* LED status */ 121 uint8_t leds; 122#define EWSKBD_SETLEDS 0x90 123#define EWSKBD_CAPSLOCK 0x02 124#define EWSKBD_KANA 0x04 125 126 /* wscons glue */ 127 struct device *wskbddev; 128 int enabled; 129}; 130 131static int ewskbd_zsc_match(device_t, cfdata_t, void *); 132static void ewskbd_zsc_attach(device_t, device_t, void *); 133static int ewskbd_zsc_init(struct zs_chanstate *); 134static void ewskbd_zsc_rxint(struct zs_chanstate *); 135static void ewskbd_zsc_stint(struct zs_chanstate *, int); 136static void ewskbd_zsc_txint(struct zs_chanstate *); 137static void ewskbd_zsc_softint(struct zs_chanstate *); 138static void ewskbd_zsc_send(struct zs_chanstate *, uint8_t *, u_int); 139 140static void ewskbd_wskbd_input(struct zs_chanstate *, u_char); 141static int ewskbd_wskbd_enable(void *, int); 142static void ewskbd_wskbd_set_leds(void *, int); 143static int ewskbd_wskbd_get_leds(void *); 144static int ewskbd_wskbd_ioctl(void *, u_long, void *, int, struct lwp *); 145 146void ewskbd_zsc_cnattach(uint32_t, uint32_t, int); 147static void ewskbd_zsc_wskbd_getc(void *, u_int *, int *); 148static void ewskbd_wskbd_pollc(void *, int); 149static void ewskbd_wskbd_bell(void *, u_int, u_int, u_int); 150 151CFATTACH_DECL_NEW(ewskbd_zsc, sizeof(struct ewskbd_softc), 152 ewskbd_zsc_match, ewskbd_zsc_attach, NULL, NULL); 153 154static struct zsops ewskbd_zsops = { 155 ewskbd_zsc_rxint, 156 ewskbd_zsc_stint, 157 ewskbd_zsc_txint, 158 ewskbd_zsc_softint 159}; 160 161const struct wskbd_mapdata ews4800kbd_wskbd_keymapdata = { 162 ews4800kbd_keydesctab, 163 KB_JP 164}; 165 166const struct wskbd_accessops ewskbd_wskbd_accessops = { 167 ewskbd_wskbd_enable, 168 ewskbd_wskbd_set_leds, 169 ewskbd_wskbd_ioctl 170}; 171 172const struct wskbd_consops ewskbd_wskbd_consops = { 173 ewskbd_zsc_wskbd_getc, 174 ewskbd_wskbd_pollc, 175 ewskbd_wskbd_bell 176}; 177 178static struct ewskbd_devconfig ewskbd_console_dc; 179static struct zs_chanstate conschan; 180static int ewskbd_is_console; 181 182static int 183ewskbd_zsc_match(device_t parent, cfdata_t cf, void *aux) 184{ 185 struct zsc_attach_args *zsc_args = aux; 186 struct zsc_softc *zsc = device_private(parent); 187 188 /* keyboard is on channel B */ 189 if ((zsc->zsc_flags & 0x0001 /* kbms port */) != 0 && 190 zsc_args->channel == 1) 191 /* prior to generic zstty(4) */ 192 return 3; 193 194 return 0; 195} 196 197static void 198ewskbd_zsc_attach(struct device *parent, struct device *self, void *aux) 199{ 200 struct ewskbd_softc *sc; 201 struct zsc_softc *zsc; 202 struct zs_chanstate *cs; 203 struct zsc_attach_args *zsc_args; 204 struct wskbddev_attach_args wskaa; 205 int channel; 206 207 sc = device_private(self); 208 zsc = device_private(parent); 209 sc->sc_dev = self; 210 zsc_args = aux; 211 212 /* Establish ourself with the MD z8530 driver */ 213 channel = zsc_args->channel; 214 cs = zsc->zsc_cs[channel]; 215 216 if (ewskbd_is_console) { 217 sc->sc_dc = &ewskbd_console_dc; 218 wskaa.console = 1; 219 sc->sc_dc->enabled = 1; 220 } else { 221 wskaa.console = 0; 222 223 sc->sc_dc = malloc(sizeof(struct ewskbd_devconfig), M_DEVBUF, 224 M_WAITOK | M_ZERO); 225 if (sc->sc_dc == NULL) { 226 printf(": can't allocate memory\n"); 227 return; 228 } 229 sc->sc_dc->enabled = 0; 230 } 231 cs->cs_defspeed = EWSKBD_BAUD; 232 cs->cs_ops = &ewskbd_zsops; 233 cs->cs_private = sc; 234 235 sc->sc_dc->txq_head = 0; 236 sc->sc_dc->txq_tail = 0; 237 sc->sc_dc->rxq_head = 0; 238 sc->sc_dc->rxq_tail = 0; 239 sc->sc_dc->state = TX_READY; 240 sc->sc_dc->leds = 0; 241 242 ewskbd_zsc_init(cs); 243 244 /* set default LED */ 245 ewskbd_wskbd_set_leds(cs, 0); 246 247 printf(": baud rate %d\n", EWSKBD_BAUD); 248 249 /* attach wskbd */ 250 wskaa.keymap = &ews4800kbd_wskbd_keymapdata; 251 wskaa.accessops = &ewskbd_wskbd_accessops; 252 wskaa.accesscookie = cs; 253 sc->sc_dc->wskbddev = config_found(self, &wskaa, wskbddevprint); 254} 255 256static int 257ewskbd_zsc_init(struct zs_chanstate *cs) 258{ 259 int s; 260 261 s = splzs(); 262 263 zs_write_reg(cs, 9, ZSWR9_B_RESET); 264 DELAY(100); 265 zs_write_reg(cs, 9, ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR); 266 267 cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE; 268 cs->cs_preg[2] = 0; 269 cs->cs_preg[3] = ZSWR3_RX_8 | ZSWR3_RX_ENABLE; 270 cs->cs_preg[4] = ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_PARENB; 271 cs->cs_preg[5] = ZSWR5_TX_8 | ZSWR5_RTS | ZSWR5_TX_ENABLE; 272 cs->cs_preg[6] = 0; 273 cs->cs_preg[7] = 0; 274 cs->cs_preg[8] = 0; 275 cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR; 276 cs->cs_preg[10] = 0; 277 cs->cs_preg[11] = ZSWR11_RXCLK_BAUD | ZSWR11_TXCLK_BAUD | 278 ZSWR11_TRXC_OUT_ENA | ZSWR11_TRXC_BAUD; 279 /* reg[11] and reg[12] are set by zs_set_speed() with cs_brg_clk */ 280 zs_set_speed(cs, EWSKBD_BAUD); 281 cs->cs_preg[14] = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA; 282 cs->cs_preg[15] = 0; 283 284 zs_loadchannelregs(cs); 285 286 splx(s); 287 288 return 0; 289} 290 291static void 292ewskbd_zsc_rxint(struct zs_chanstate *cs) 293{ 294 struct ewskbd_softc *sc; 295 struct ewskbd_devconfig *dc; 296 uint8_t c, r; 297 298 sc = cs->cs_private; 299 dc = sc->sc_dc; 300 301 /* clear errors */ 302 r = zs_read_reg(cs, 1); 303 if (r & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) 304 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 305 306 /* read byte and append to our queue */ 307 c = zs_read_data(cs); 308 309 dc->rxq[dc->rxq_tail] = c; 310 dc->rxq_tail = EWSKBD_NEXTRXQ(dc->rxq_tail); 311 312 cs->cs_softreq = 1; 313} 314 315static void 316ewskbd_zsc_stint(struct zs_chanstate *cs, int force) 317{ 318 319 zs_write_csr(cs, ZSWR0_RESET_STATUS); 320 cs->cs_softreq = 1; 321} 322 323static void 324ewskbd_zsc_txint(struct zs_chanstate *cs) 325{ 326 struct ewskbd_softc *sc; 327 328 sc = cs->cs_private; 329 zs_write_reg(cs, 0, ZSWR0_RESET_TXINT); 330 sc->sc_dc->state |= TX_READY; 331 cs->cs_softreq = 1; 332} 333 334static void 335ewskbd_zsc_softint(struct zs_chanstate *cs) 336{ 337 struct ewskbd_softc *sc; 338 struct ewskbd_devconfig *dc; 339 340 sc = cs->cs_private; 341 dc = sc->sc_dc; 342 343 /* handle pending transmissions */ 344 if (dc->txq_head != dc->txq_tail && (dc->state & TX_READY)) { 345 int s; 346 347 dc->state &= ~TX_READY; 348 349 s = splzs(); 350 zs_write_data(cs, dc->txq[dc->txq_head]); 351 splx(s); 352 353 dc->txq_head = EWSKBD_NEXTTXQ(dc->txq_head); 354 } 355 356 /* don't bother if nobody is listening */ 357 if (!dc->enabled) { 358 dc->rxq_head = dc->rxq_tail; 359 return; 360 } 361 362 /* handle incoming keystrokes/config */ 363 while (dc->rxq_head != dc->rxq_tail) { 364 uint8_t key = dc->rxq[dc->rxq_head]; 365 366 /* toss wskbd a bone */ 367 ewskbd_wskbd_input(cs, key); 368 369 dc->rxq_head = EWSKBD_NEXTRXQ(dc->rxq_head); 370 } 371} 372 373/* expects to be in splzs() */ 374static void 375ewskbd_zsc_send(struct zs_chanstate *cs, uint8_t *c, u_int len) 376{ 377 struct ewskbd_softc *sc; 378 struct ewskbd_devconfig *dc; 379 int i; 380 381 sc = cs->cs_private; 382 dc = sc->sc_dc; 383 384 for (i = 0; i < len; i++) { 385 if (dc->state & TX_READY) { 386 zs_write_data(cs, c[i]); 387 dc->state &= ~TX_READY; 388 } else { 389 dc->txq[dc->txq_tail] = c[i]; 390 dc->txq_tail = EWSKBD_NEXTTXQ(dc->txq_tail); 391 cs->cs_softreq = 1; 392 } 393 } 394} 395 396/****************************************************************************** 397 * wskbd glue 398 ******************************************************************************/ 399 400static void 401ewskbd_wskbd_input(struct zs_chanstate *cs, uint8_t key) 402{ 403 struct ewskbd_softc *sc; 404 u_int type; 405 406 sc = cs->cs_private; 407 408 if (key & EWSKBD_KEY_UP) 409 type = WSCONS_EVENT_KEY_UP; 410 else 411 type = WSCONS_EVENT_KEY_DOWN; 412 413 wskbd_input(sc->sc_dc->wskbddev, type, (key & EWSKBD_KEY_MASK)); 414 415 DPRINTF(("ewskbd_wskbd_input: inputted key 0x%x\n", key)); 416 417#ifdef WSDISPLAY_COMPAT_RAWKBD 418 wskbd_rawinput(sc->sc_dc->wskbddev, &key, 1); 419#endif 420} 421 422static int 423ewskbd_wskbd_enable(void *cookie, int on) 424{ 425 struct zs_chanstate *cs; 426 struct ewskbd_softc *sc; 427 428 cs = cookie; 429 sc = cs->cs_private; 430 431 if (on) { 432 if (sc->sc_dc->enabled) 433 return EBUSY; 434 else 435 sc->sc_dc->enabled = 1; 436 } else 437 sc->sc_dc->enabled = 0; 438 439 DPRINTF(("ewskbd_wskbd_enable: %s\n", on ? "enabled" : "disabled")); 440 441 return 0; 442} 443 444static void 445ewskbd_wskbd_set_leds(void *cookie, int leds) 446{ 447 struct zs_chanstate *cs; 448 struct ewskbd_softc *sc; 449 int s; 450 uint8_t cmd; 451 452 cs = cookie; 453 sc = cs->cs_private; 454 cmd = 0; 455 456 if (leds & WSKBD_LED_CAPS) 457 cmd |= EWSKBD_CAPSLOCK; 458 459 sc->sc_dc->leds = cmd; 460 461 cmd |= EWSKBD_SETLEDS; 462 463 s = splzs(); 464 ewskbd_zsc_send(cs, &cmd, 1); 465 splx(s); 466} 467 468static int 469ewskbd_wskbd_get_leds(void *cookie) 470{ 471 struct zs_chanstate *cs; 472 struct ewskbd_softc *sc; 473 int leds; 474 475 cs = cookie; 476 sc = cs->cs_private; 477 leds = 0; 478 479 if (sc->sc_dc->leds & EWSKBD_CAPSLOCK) 480 leds |= WSKBD_LED_CAPS; 481 482 return leds; 483} 484 485static int 486ewskbd_wskbd_ioctl(void *cookie, u_long cmd, void *data, int flag, 487 struct lwp *l) 488{ 489 490 switch (cmd) { 491 case WSKBDIO_GTYPE: 492 *(int *)data = WSKBD_TYPE_EWS4800; 493 break; 494 495#ifdef notyet 496 case WSKBDIO_BELL: 497 case WSKBDIO_COMPLEXBELL: 498 case WSKBDIO_SETBELL: 499 case WSKBDIO_GETBELL: 500 case WSKBDIO_SETDEFAULTBELL: 501 case WSKBDIO_GETDEFAULTBELL: 502 case WSKBDIO_SETKEYREPEAT: 503 case WSKBDIO_GETKEYREPEAT: 504 case WSKBDIO_SETDEFAULTKEYREPEAT: 505 case WSKBDIO_GETDEFAULTKEYREPEAT: 506#endif 507 508 case WSKBDIO_SETLEDS: 509 ewskbd_wskbd_set_leds(cookie, *(int *)data); 510 break; 511 512 case WSKBDIO_GETLEDS: 513 *(int *)data = ewskbd_wskbd_get_leds(cookie); 514 break; 515 516#ifdef notyet 517 case WSKBDIO_GETMAP: 518 case WSKBDIO_SETMAP: 519 case WSKBDIO_GETENCODING: 520 case WSKBDIO_SETENCODING: 521 case WSKBDIO_SETMODE: 522 case WSKBDIO_GETMODE: 523 case WSKBDIO_SETKEYCLICK: 524 case WSKBDIO_GETKEYCLICK: 525#endif 526 527 default: 528 return EPASSTHROUGH; 529 } 530 531 return 0; 532} 533 534/* 535 * console routines 536 */ 537void 538ewskbd_zsc_cnattach(uint32_t csr, uint32_t data, int pclk) 539{ 540 struct zs_chanstate *cs; 541 542 cs = &conschan; 543 544 cs->cs_reg_csr = (void *)csr; 545 cs->cs_reg_data = (void *)data; 546 cs->cs_brg_clk = pclk / 16; 547 cs->cs_defspeed = EWSKBD_BAUD; 548 549 ewskbd_zsc_init(cs); 550 551 zs_putc(cs, EWSKBD_SETLEDS); 552 553 wskbd_cnattach(&ewskbd_wskbd_consops, cs, &ews4800kbd_wskbd_keymapdata); 554 ewskbd_is_console = 1; 555} 556 557static void 558ewskbd_zsc_wskbd_getc(void *cookie, u_int *type, int *data) 559{ 560 int key; 561 562 key = zs_getc(cookie); 563 564 if (key & EWSKBD_KEY_UP) 565 *type = WSCONS_EVENT_KEY_UP; 566 else 567 *type = WSCONS_EVENT_KEY_DOWN; 568 569 *data = key & EWSKBD_KEY_MASK; 570} 571 572static void 573ewskbd_wskbd_pollc(void *cookie, int on) 574{ 575 576 static bool __polling = false; 577 static int s; 578 579 if (on && !__polling) { 580 /* disable interrupt driven I/O */ 581 s = splhigh(); 582 __polling = true; 583 } else if (!on && __polling) { 584 /* enable interrupt driven I/O */ 585 __polling = false; 586 splx(s); 587 } 588} 589 590static void 591ewskbd_wskbd_bell(void *cookie, u_int pitch, u_int period, u_int volume) 592{ 593 594 /* nothing */ 595} 596