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