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