pckbd.c revision 117167
1/* 2 * Copyright (c) 1999 FreeBSD(98) port team. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 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. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD: head/sys/pc98/cbus/pckbd.c 117167 2003-07-02 16:09:02Z jhb $ 29 */ 30 31#include "opt_kbd.h" 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/kernel.h> 36#include <sys/module.h> 37#include <sys/bus.h> 38#include <machine/bus.h> 39#include <sys/rman.h> 40#include <sys/kbio.h> 41 42#include <machine/resource.h> 43 44#include <dev/kbd/kbdreg.h> 45 46#include <pc98/pc98/pc98.h> 47 48#include <isa/isavar.h> 49 50#define DRIVER_NAME "pckbd" 51 52/* device configuration flags */ 53#define KB_CONF_FAIL_IF_NO_KBD (1 << 0) /* don't install if no kbd is found */ 54 55static devclass_t pckbd_devclass; 56 57static int pckbdprobe(device_t dev); 58static int pckbdattach(device_t dev); 59static int pckbdresume(device_t dev); 60static void pckbd_isa_intr(void *arg); 61 62static device_method_t pckbd_methods[] = { 63 /* Device interface */ 64 DEVMETHOD(device_probe, pckbdprobe), 65 DEVMETHOD(device_attach, pckbdattach), 66 DEVMETHOD(device_resume, pckbdresume), 67 { 0, 0 } 68}; 69 70static driver_t pckbd_driver = { 71 DRIVER_NAME, 72 pckbd_methods, 73 1, 74}; 75 76DRIVER_MODULE(pckbd, isa, pckbd_driver, pckbd_devclass, 0, 0); 77 78static bus_addr_t pckbd_iat[] = {0, 2}; 79 80static int pckbd_probe_unit(int unit, int port, int irq, 81 int flags); 82static int pckbd_attach_unit(int unit, keyboard_t **kbd, 83 int port, int irq, int flags); 84static timeout_t pckbd_timeout; 85 86 87static int 88pckbdprobe(device_t dev) 89{ 90 struct resource *res; 91 int error, rid; 92 93 /* Check isapnp ids */ 94 if (isa_get_vendorid(dev)) 95 return (ENXIO); 96 97 device_set_desc(dev, "PC-98 Keyboard"); 98 99 rid = 0; 100 res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2, 101 RF_ACTIVE); 102 if (res == NULL) 103 return ENXIO; 104 isa_load_resourcev(res, pckbd_iat, 2); 105 106 error = pckbd_probe_unit(device_get_unit(dev), 107 isa_get_port(dev), 108 (1 << isa_get_irq(dev)), 109 device_get_flags(dev)); 110 111 bus_release_resource(dev, SYS_RES_IOPORT, rid, res); 112 113 return (error); 114} 115 116static int 117pckbdattach(device_t dev) 118{ 119 keyboard_t *kbd; 120 void *ih; 121 struct resource *res; 122 int error, rid; 123 124 rid = 0; 125 res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2, 126 RF_ACTIVE); 127 if (res == NULL) 128 return ENXIO; 129 isa_load_resourcev(res, pckbd_iat, 2); 130 131 error = pckbd_attach_unit(device_get_unit(dev), &kbd, 132 isa_get_port(dev), 133 (1 << isa_get_irq(dev)), 134 device_get_flags(dev)); 135 136 rid = 0; 137 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); 138 if (res == NULL) 139 return ENXIO; 140 BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY, 141 pckbd_isa_intr, kbd, &ih); 142 143 return 0; 144} 145 146static int 147pckbdresume(device_t dev) 148{ 149 keyboard_t *kbd; 150 151 kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, 152 device_get_unit(dev))); 153 if (kbd) 154 (*kbdsw[kbd->kb_index]->clear_state)(kbd); 155 156 return (0); 157} 158 159static void 160pckbd_isa_intr(void *arg) 161{ 162 keyboard_t *kbd = arg; 163 164 (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 165} 166 167static int 168pckbd_probe_unit(int unit, int port, int irq, int flags) 169{ 170 keyboard_switch_t *sw; 171 int args[2]; 172 int error; 173 174 sw = kbd_get_switch(DRIVER_NAME); 175 if (sw == NULL) 176 return ENXIO; 177 178 args[0] = port; 179 args[1] = irq; 180 error = (*sw->probe)(unit, args, flags); 181 if (error) 182 return error; 183 return 0; 184} 185 186static int 187pckbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags) 188{ 189 keyboard_switch_t *sw; 190 int args[2]; 191 int error; 192 193 sw = kbd_get_switch(DRIVER_NAME); 194 if (sw == NULL) 195 return ENXIO; 196 197 /* reset, initialize and enable the device */ 198 args[0] = port; 199 args[1] = irq; 200 *kbd = NULL; 201 error = (*sw->probe)(unit, args, flags); 202 if (error) 203 return error; 204 error = (*sw->init)(unit, kbd, args, flags); 205 if (error) 206 return error; 207 (*sw->enable)(*kbd); 208 209#ifdef KBD_INSTALL_CDEV 210 /* attach a virtual keyboard cdev */ 211 error = kbd_attach(*kbd); 212 if (error) 213 return error; 214#endif /* KBD_INSTALL_CDEV */ 215 216 /* 217 * This is a kludge to compensate for lost keyboard interrupts. 218 * A similar code used to be in syscons. See below. XXX 219 */ 220 pckbd_timeout(*kbd); 221 222 if (bootverbose) 223 (*sw->diag)(*kbd, bootverbose); 224 225 return 0; 226} 227 228static void 229pckbd_timeout(void *arg) 230{ 231 keyboard_t *kbd; 232 int s; 233 234 /* The following comments are extracted from syscons.c (1.287) */ 235 /* 236 * With release 2.1 of the Xaccel server, the keyboard is left 237 * hanging pretty often. Apparently an interrupt from the 238 * keyboard is lost, and I don't know why (yet). 239 * This ugly hack calls scintr if input is ready for the keyboard 240 * and conveniently hides the problem. XXX 241 */ 242 /* 243 * Try removing anything stuck in the keyboard controller; whether 244 * it's a keyboard scan code or mouse data. `scintr()' doesn't 245 * read the mouse data directly, but `kbdio' routines will, as a 246 * side effect. 247 */ 248 s = spltty(); 249 kbd = (keyboard_t *)arg; 250 if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) { 251 /* 252 * We have seen the lock flag is not set. Let's reset 253 * the flag early, otherwise the LED update routine fails 254 * which may want the lock during the interrupt routine. 255 */ 256 (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); 257 if ((*kbdsw[kbd->kb_index]->check_char)(kbd)) 258 (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 259 } 260 splx(s); 261 timeout(pckbd_timeout, arg, hz/10); 262} 263 264/* LOW-LEVEL */ 265 266#include <sys/limits.h> 267 268#define PC98KBD_DEFAULT 0 269 270typedef caddr_t KBDC; 271 272typedef struct pckbd_state { 273 KBDC kbdc; /* keyboard controller */ 274 int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 275 int ks_flags; /* flags */ 276#define COMPOSE (1 << 0) 277 int ks_state; /* shift/lock key state */ 278 int ks_accents; /* accent key index (> 0) */ 279 u_int ks_composed_char; /* composed char code (> 0) */ 280} pckbd_state_t; 281 282/* keyboard driver declaration */ 283static int pckbd_configure(int flags); 284static kbd_probe_t pckbd_probe; 285static kbd_init_t pckbd_init; 286static kbd_term_t pckbd_term; 287static kbd_intr_t pckbd_intr; 288static kbd_test_if_t pckbd_test_if; 289static kbd_enable_t pckbd_enable; 290static kbd_disable_t pckbd_disable; 291static kbd_read_t pckbd_read; 292static kbd_check_t pckbd_check; 293static kbd_read_char_t pckbd_read_char; 294static kbd_check_char_t pckbd_check_char; 295static kbd_ioctl_t pckbd_ioctl; 296static kbd_lock_t pckbd_lock; 297static kbd_clear_state_t pckbd_clear_state; 298static kbd_get_state_t pckbd_get_state; 299static kbd_set_state_t pckbd_set_state; 300static kbd_poll_mode_t pckbd_poll; 301 302keyboard_switch_t pckbdsw = { 303 pckbd_probe, 304 pckbd_init, 305 pckbd_term, 306 pckbd_intr, 307 pckbd_test_if, 308 pckbd_enable, 309 pckbd_disable, 310 pckbd_read, 311 pckbd_check, 312 pckbd_read_char, 313 pckbd_check_char, 314 pckbd_ioctl, 315 pckbd_lock, 316 pckbd_clear_state, 317 pckbd_get_state, 318 pckbd_set_state, 319 genkbd_get_fkeystr, 320 pckbd_poll, 321 genkbd_diag, 322}; 323 324KEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure); 325 326struct kbdc_softc { 327 int port; /* base port address */ 328 int lock; /* FIXME: XXX not quite a semaphore... */ 329}; 330 331/* local functions */ 332static int probe_keyboard(KBDC kbdc, int flags); 333static int init_keyboard(KBDC kbdc, int *type, int flags); 334static KBDC kbdc_open(int port); 335static int kbdc_lock(KBDC kbdc, int lock); 336static int kbdc_data_ready(KBDC kbdc); 337static int read_kbd_data(KBDC kbdc); 338static int read_kbd_data_no_wait(KBDC kbdc); 339static int wait_for_kbd_data(struct kbdc_softc *kbdc); 340 341/* local variables */ 342 343/* the initial key map, accent map and fkey strings */ 344#include <dev/kbd/kbdtables.h> 345 346/* structures for the default keyboard */ 347static keyboard_t default_kbd; 348static pckbd_state_t default_kbd_state; 349static keymap_t default_keymap; 350static accentmap_t default_accentmap; 351static fkeytab_t default_fkeytab[NUM_FKEYS]; 352 353/* 354 * The back door to the keyboard driver! 355 * This function is called by the console driver, via the kbdio module, 356 * to tickle keyboard drivers when the low-level console is being initialized. 357 * Almost nothing in the kernel has been initialied yet. Try to probe 358 * keyboards if possible. 359 * NOTE: because of the way the low-level conole is initialized, this routine 360 * may be called more than once!! 361 */ 362static int 363pckbd_configure(int flags) 364{ 365 keyboard_t *kbd; 366 int arg[2]; 367 int i; 368 369 /* XXX: a kludge to obtain the device configuration flags */ 370 if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) { 371 flags |= i; 372 /* if the driver is disabled, unregister the keyboard if any */ 373 if (resource_disabled(DRIVER_NAME, 0)) { 374 i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT); 375 if (i >= 0) { 376 kbd = kbd_get_keyboard(i); 377 kbd_unregister(kbd); 378 kbd->kb_flags &= ~KB_REGISTERED; 379 return 0; 380 } 381 } 382 } 383 384 /* probe the default keyboard */ 385 arg[0] = -1; 386 arg[1] = -1; 387 kbd = NULL; 388 if (pckbd_probe(PC98KBD_DEFAULT, arg, flags)) 389 return 0; 390 if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags)) 391 return 0; 392 393 /* return the number of found keyboards */ 394 return 1; 395} 396 397/* low-level functions */ 398 399/* detect a keyboard */ 400static int 401pckbd_probe(int unit, void *arg, int flags) 402{ 403 KBDC kbdc; 404 int *data = (int *)arg; 405 406 if (unit != PC98KBD_DEFAULT) 407 return ENXIO; 408 if (KBD_IS_PROBED(&default_kbd)) 409 return 0; 410 411 kbdc = kbdc_open(data[0]); 412 if (kbdc == NULL) 413 return ENXIO; 414 if (probe_keyboard(kbdc, flags)) { 415 if (flags & KB_CONF_FAIL_IF_NO_KBD) 416 return ENXIO; 417 } 418 return 0; 419} 420 421/* reset and initialize the device */ 422static int 423pckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 424{ 425 keyboard_t *kbd; 426 pckbd_state_t *state; 427 keymap_t *keymap; 428 accentmap_t *accmap; 429 fkeytab_t *fkeymap; 430 int fkeymap_size; 431 int *data = (int *)arg; 432 433 if (unit != PC98KBD_DEFAULT) /* shouldn't happen */ 434 return ENXIO; 435 436 *kbdp = kbd = &default_kbd; 437 state = &default_kbd_state; 438 if (!KBD_IS_PROBED(kbd)) { 439 keymap = &default_keymap; 440 accmap = &default_accentmap; 441 fkeymap = default_fkeytab; 442 fkeymap_size = 443 sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 444 445 state->kbdc = kbdc_open(data[0]); 446 if (state->kbdc == NULL) 447 return ENXIO; 448 kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags, 449 data[0], IO_KBDSIZE); 450 bcopy(&key_map, keymap, sizeof(key_map)); 451 bcopy(&accent_map, accmap, sizeof(accent_map)); 452 bcopy(fkey_tab, fkeymap, 453 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 454 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 455 kbd->kb_data = (void *)state; 456 457 if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */ 458 if (flags & KB_CONF_FAIL_IF_NO_KBD) 459 return ENXIO; 460 } else { 461 KBD_FOUND_DEVICE(kbd); 462 } 463 pckbd_clear_state(kbd); 464 state->ks_mode = K_XLATE; 465 KBD_PROBE_DONE(kbd); 466 } 467 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 468 if (KBD_HAS_DEVICE(kbd) 469 && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 470 && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) 471 return ENXIO; 472 pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 473 KBD_INIT_DONE(kbd); 474 } 475 if (!KBD_IS_CONFIGURED(kbd)) { 476 if (kbd_register(kbd) < 0) 477 return ENXIO; 478 KBD_CONFIG_DONE(kbd); 479 } 480 481 return 0; 482} 483 484/* finish using this keyboard */ 485static int 486pckbd_term(keyboard_t *kbd) 487{ 488 kbd_unregister(kbd); 489 return 0; 490} 491 492/* keyboard interrupt routine */ 493static int 494pckbd_intr(keyboard_t *kbd, void *arg) 495{ 496 int c; 497 498 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 499 /* let the callback function to process the input */ 500 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 501 kbd->kb_callback.kc_arg); 502 } else { 503 /* read and discard the input; no one is waiting for input */ 504 do { 505 c = pckbd_read_char(kbd, FALSE); 506 } while (c != NOKEY); 507 } 508 return 0; 509} 510 511/* test the interface to the device */ 512static int 513pckbd_test_if(keyboard_t *kbd) 514{ 515 return 0; 516} 517 518/* 519 * Enable the access to the device; until this function is called, 520 * the client cannot read from the keyboard. 521 */ 522static int 523pckbd_enable(keyboard_t *kbd) 524{ 525 int s; 526 527 s = spltty(); 528 KBD_ACTIVATE(kbd); 529 splx(s); 530 return 0; 531} 532 533/* disallow the access to the device */ 534static int 535pckbd_disable(keyboard_t *kbd) 536{ 537 int s; 538 539 s = spltty(); 540 KBD_DEACTIVATE(kbd); 541 splx(s); 542 return 0; 543} 544 545/* read one byte from the keyboard if it's allowed */ 546static int 547pckbd_read(keyboard_t *kbd, int wait) 548{ 549 int c; 550 551 if (wait) 552 c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc); 553 else 554 c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc); 555 if (c != -1) 556 ++kbd->kb_count; 557 return (KBD_IS_ACTIVE(kbd) ? c : -1); 558} 559 560/* check if data is waiting */ 561static int 562pckbd_check(keyboard_t *kbd) 563{ 564 if (!KBD_IS_ACTIVE(kbd)) 565 return FALSE; 566 return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc); 567} 568 569/* read char from the keyboard */ 570static u_int 571pckbd_read_char(keyboard_t *kbd, int wait) 572{ 573 pckbd_state_t *state; 574 u_int action; 575 int scancode; 576 int keycode; 577 578 state = (pckbd_state_t *)kbd->kb_data; 579next_code: 580 /* do we have a composed char to return? */ 581 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 582 action = state->ks_composed_char; 583 state->ks_composed_char = 0; 584 if (action > UCHAR_MAX) 585 return ERRKEY; 586 return action; 587 } 588 589 /* see if there is something in the keyboard port */ 590 if (wait) { 591 do { 592 scancode = read_kbd_data(state->kbdc); 593 } while (scancode == -1); 594 } else { 595 scancode = read_kbd_data_no_wait(state->kbdc); 596 if (scancode == -1) 597 return NOKEY; 598 } 599 ++kbd->kb_count; 600 601#if 0 602 printf("pckbd_read_char(): scancode:0x%x\n", scancode); 603#endif 604 605 /* return the byte as is for the K_RAW mode */ 606 if (state->ks_mode == K_RAW) 607 return scancode; 608 609 /* translate the scan code into a keycode */ 610 keycode = scancode & 0x7F; 611 switch(scancode) { 612 case 0xF3: /* GRPH (compose key) released */ 613 if (state->ks_flags & COMPOSE) { 614 state->ks_flags &= ~COMPOSE; 615 if (state->ks_composed_char > UCHAR_MAX) 616 state->ks_composed_char = 0; 617 } 618 break; 619 case 0x73: /* GRPH (compose key) pressed */ 620 if (!(state->ks_flags & COMPOSE)) { 621 state->ks_flags |= COMPOSE; 622 state->ks_composed_char = 0; 623 } 624 break; 625 } 626 627 /* return the key code in the K_CODE mode */ 628 if (state->ks_mode == K_CODE) 629 return (keycode | (scancode & 0x80)); 630 631 /* compose a character code */ 632 if (state->ks_flags & COMPOSE) { 633 switch (scancode) { 634 /* key pressed, process it */ 635 case 0x42: case 0x43: case 0x44: /* keypad 7,8,9 */ 636 state->ks_composed_char *= 10; 637 state->ks_composed_char += scancode - 0x3B; 638 if (state->ks_composed_char > UCHAR_MAX) 639 return ERRKEY; 640 goto next_code; 641 case 0x46: case 0x47: case 0x48: /* keypad 4,5,6 */ 642 state->ks_composed_char *= 10; 643 state->ks_composed_char += scancode - 0x42; 644 if (state->ks_composed_char > UCHAR_MAX) 645 return ERRKEY; 646 goto next_code; 647 case 0x4A: case 0x4B: case 0x4C: /* keypad 1,2,3 */ 648 state->ks_composed_char *= 10; 649 state->ks_composed_char += scancode - 0x49; 650 if (state->ks_composed_char > UCHAR_MAX) 651 return ERRKEY; 652 goto next_code; 653 case 0x4E: /* keypad 0 */ 654 state->ks_composed_char *= 10; 655 if (state->ks_composed_char > UCHAR_MAX) 656 return ERRKEY; 657 goto next_code; 658 659 /* key released, no interest here */ 660 case 0xC2: case 0xC3: case 0xC4: /* keypad 7,8,9 */ 661 case 0xC6: case 0xC7: case 0xC8: /* keypad 4,5,6 */ 662 case 0xCA: case 0xCB: case 0xCC: /* keypad 1,2,3 */ 663 case 0xCE: /* keypad 0 */ 664 goto next_code; 665 666 case 0x73: /* GRPH key */ 667 break; 668 669 default: 670 if (state->ks_composed_char > 0) { 671 state->ks_flags &= ~COMPOSE; 672 state->ks_composed_char = 0; 673 return ERRKEY; 674 } 675 break; 676 } 677 } 678 679 /* keycode to key action */ 680 action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 681 &state->ks_state, &state->ks_accents); 682 if (action == NOKEY) 683 goto next_code; 684 else 685 return action; 686} 687 688/* check if char is waiting */ 689static int 690pckbd_check_char(keyboard_t *kbd) 691{ 692 pckbd_state_t *state; 693 694 if (!KBD_IS_ACTIVE(kbd)) 695 return FALSE; 696 state = (pckbd_state_t *)kbd->kb_data; 697 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 698 return TRUE; 699 return kbdc_data_ready(state->kbdc); 700} 701 702/* some useful control functions */ 703static int 704pckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 705{ 706 pckbd_state_t *state = kbd->kb_data; 707 int s; 708 int i; 709 710 s = spltty(); 711 switch (cmd) { 712 713 case KDGKBMODE: /* get keyboard mode */ 714 *(int *)arg = state->ks_mode; 715 break; 716 case KDSKBMODE: /* set keyboard mode */ 717 switch (*(int *)arg) { 718 case K_XLATE: 719 if (state->ks_mode != K_XLATE) { 720 /* make lock key state and LED state match */ 721 state->ks_state &= ~LOCK_MASK; 722 state->ks_state |= KBD_LED_VAL(kbd); 723 } 724 /* FALLTHROUGH */ 725 case K_RAW: 726 case K_CODE: 727 if (state->ks_mode != *(int *)arg) { 728 pckbd_clear_state(kbd); 729 state->ks_mode = *(int *)arg; 730 } 731 break; 732 default: 733 splx(s); 734 return EINVAL; 735 } 736 break; 737 738 case KDGETLED: /* get keyboard LED */ 739 *(int *)arg = KBD_LED_VAL(kbd); 740 break; 741 case KDSETLED: /* set keyboard LED */ 742 /* NOTE: lock key state in ks_state won't be changed */ 743 if (*(int *)arg & ~LOCK_MASK) { 744 splx(s); 745 return EINVAL; 746 } 747 i = *(int *)arg; 748 /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 749 if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 750 if (i & ALKED) 751 i |= CLKED; 752 else 753 i &= ~CLKED; 754 } 755 KBD_LED_VAL(kbd) = *(int *)arg; 756 break; 757 758 case KDGKBSTATE: /* get lock key state */ 759 *(int *)arg = state->ks_state & LOCK_MASK; 760 break; 761 case KDSKBSTATE: /* set lock key state */ 762 if (*(int *)arg & ~LOCK_MASK) { 763 splx(s); 764 return EINVAL; 765 } 766 state->ks_state &= ~LOCK_MASK; 767 state->ks_state |= *(int *)arg; 768 splx(s); 769 /* set LEDs and quit */ 770 return pckbd_ioctl(kbd, KDSETLED, arg); 771 772 case KDSETRAD: /* set keyboard repeat rate (old interface)*/ 773 break; 774 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 775 break; 776 777 case PIO_KEYMAP: /* set keyboard translation table */ 778 case PIO_KEYMAPENT: /* set keyboard translation table entry */ 779 case PIO_DEADKEYMAP: /* set accent key translation table */ 780 state->ks_accents = 0; 781 /* FALLTHROUGH */ 782 default: 783 splx(s); 784 return genkbd_commonioctl(kbd, cmd, arg); 785 } 786 787 splx(s); 788 return 0; 789} 790 791/* lock the access to the keyboard */ 792static int 793pckbd_lock(keyboard_t *kbd, int lock) 794{ 795 return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock); 796} 797 798/* clear the internal state of the keyboard */ 799static void 800pckbd_clear_state(keyboard_t *kbd) 801{ 802 pckbd_state_t *state; 803 804 state = (pckbd_state_t *)kbd->kb_data; 805 state->ks_flags = 0; 806 state->ks_state &= LOCK_MASK; /* preserve locking key state */ 807 state->ks_accents = 0; 808 state->ks_composed_char = 0; 809} 810 811/* save the internal state */ 812static int 813pckbd_get_state(keyboard_t *kbd, void *buf, size_t len) 814{ 815 if (len == 0) 816 return sizeof(pckbd_state_t); 817 if (len < sizeof(pckbd_state_t)) 818 return -1; 819 bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t)); 820 return 0; 821} 822 823/* set the internal state */ 824static int 825pckbd_set_state(keyboard_t *kbd, void *buf, size_t len) 826{ 827 if (len < sizeof(pckbd_state_t)) 828 return ENOMEM; 829 if (((pckbd_state_t *)kbd->kb_data)->kbdc 830 != ((pckbd_state_t *)buf)->kbdc) 831 return ENOMEM; 832 bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t)); 833 return 0; 834} 835 836/* set polling mode */ 837static int 838pckbd_poll(keyboard_t *kbd, int on) 839{ 840 return 0; 841} 842 843/* local functions */ 844 845static int 846probe_keyboard(KBDC kbdc, int flags) 847{ 848 return 0; 849} 850 851static int 852init_keyboard(KBDC kbdc, int *type, int flags) 853{ 854 *type = KB_OTHER; 855 return 0; 856} 857 858/* keyboard I/O routines */ 859 860/* retry count */ 861#ifndef KBD_MAXRETRY 862#define KBD_MAXRETRY 3 863#endif 864 865/* timing parameters */ 866#ifndef KBD_RESETDELAY 867#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ 868#endif 869#ifndef KBD_MAXWAIT 870#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ 871#endif 872 873/* I/O recovery time */ 874#define KBDC_DELAYTIME 37 875#define KBDD_DELAYTIME 37 876 877/* I/O ports */ 878#define KBD_STATUS_PORT 2 /* status port, read */ 879#define KBD_DATA_PORT 0 /* data port, read */ 880 881/* status bits (KBD_STATUS_PORT) */ 882#define KBDS_BUFFER_FULL 0x0002 883 884/* macros */ 885 886#define kbdcp(p) ((struct kbdc_softc *)(p)) 887 888/* local variables */ 889 890static struct kbdc_softc kbdc_softc[1] = { { 0 }, }; 891 892/* associate a port number with a KBDC */ 893 894static KBDC 895kbdc_open(int port) 896{ 897 if (port <= 0) 898 port = IO_KBD; 899 900 /* PC-98 has only one keyboard I/F */ 901 kbdc_softc[0].port = port; 902 kbdc_softc[0].lock = FALSE; 903 return (KBDC)&kbdc_softc[0]; 904} 905 906/* set/reset polling lock */ 907static int 908kbdc_lock(KBDC p, int lock) 909{ 910 int prevlock; 911 912 prevlock = kbdcp(p)->lock; 913 kbdcp(p)->lock = lock; 914 915 return (prevlock != lock); 916} 917 918/* check if any data is waiting to be processed */ 919static int 920kbdc_data_ready(KBDC p) 921{ 922 return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL); 923} 924 925/* wait for data from the keyboard */ 926static int 927wait_for_kbd_data(struct kbdc_softc *kbdc) 928{ 929 /* CPU will stay inside the loop for 200msec at most */ 930 int retry = 10000; 931 int port = kbdc->port; 932 933 while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) { 934 DELAY(KBDD_DELAYTIME); 935 DELAY(KBDC_DELAYTIME); 936 if (--retry < 0) 937 return 0; 938 } 939 DELAY(KBDD_DELAYTIME); 940 return 1; 941} 942 943/* read one byte from the keyboard */ 944static int 945read_kbd_data(KBDC p) 946{ 947 if (!wait_for_kbd_data(kbdcp(p))) 948 return -1; /* timeout */ 949 DELAY(KBDC_DELAYTIME); 950 return inb(kbdcp(p)->port + KBD_DATA_PORT); 951} 952 953/* read one byte from the keyboard, but return immediately if 954 * no data is waiting 955 */ 956static int 957read_kbd_data_no_wait(KBDC p) 958{ 959 if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) { 960 DELAY(KBDD_DELAYTIME); 961 return inb(kbdcp(p)->port + KBD_DATA_PORT); 962 } 963 return -1; /* no data */ 964} 965