1139825Simp/*- 242805Skato * Copyright (c) 1999 FreeBSD(98) port team. 342805Skato * All rights reserved. 442805Skato * 542805Skato * Redistribution and use in source and binary forms, with or without 642805Skato * modification, are permitted provided that the following conditions 742805Skato * are met: 842805Skato * 1. Redistributions of source code must retain the above copyright 942805Skato * notice, this list of conditions and the following disclaimer as 1042805Skato * the first lines of this file unmodified. 1142805Skato * 2. Redistributions in binary form must reproduce the above copyright 1242805Skato * notice, this list of conditions and the following disclaimer in the 1342805Skato * documentation and/or other materials provided with the distribution. 1442805Skato * 3. The name of the author may not be used to endorse or promote products 1542805Skato * derived from this software without specific prior written permission. 1642805Skato * 1742805Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1842805Skato * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1942805Skato * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2042805Skato * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2142805Skato * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2242805Skato * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2342805Skato * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2442805Skato * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2542805Skato * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2642805Skato * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2742805Skato * 2850477Speter * $FreeBSD$ 2942795Skato */ 3042795Skato 31162711Sru#include "opt_compat.h" 3242795Skato#include "opt_kbd.h" 3342795Skato 3442795Skato#include <sys/param.h> 3542795Skato#include <sys/systm.h> 3642795Skato#include <sys/kernel.h> 3745783Skato#include <sys/module.h> 3842795Skato#include <sys/bus.h> 3945783Skato#include <machine/bus.h> 4045783Skato#include <sys/rman.h> 4167370Skato#include <sys/kbio.h> 4242795Skato 4342795Skato#include <machine/resource.h> 4442795Skato 4542795Skato#include <dev/kbd/kbdreg.h> 4642795Skato 47146049Snyan#include <pc98/cbus/cbus.h> 4845783Skato#include <isa/isavar.h> 4945783Skato 5042795Skato#define DRIVER_NAME "pckbd" 5142795Skato 5242795Skato/* device configuration flags */ 5342795Skato#define KB_CONF_FAIL_IF_NO_KBD (1 << 0) /* don't install if no kbd is found */ 5442795Skato 5545783Skatostatic devclass_t pckbd_devclass; 5642795Skato 5745783Skatostatic int pckbdprobe(device_t dev); 5845783Skatostatic int pckbdattach(device_t dev); 5979702Snyanstatic int pckbdresume(device_t dev); 6045783Skatostatic void pckbd_isa_intr(void *arg); 6142795Skato 6245783Skatostatic device_method_t pckbd_methods[] = { 6345783Skato /* Device interface */ 6445783Skato DEVMETHOD(device_probe, pckbdprobe), 6545783Skato DEVMETHOD(device_attach, pckbdattach), 6679702Snyan DEVMETHOD(device_resume, pckbdresume), 6745783Skato { 0, 0 } 6845783Skato}; 6942795Skato 7045783Skatostatic driver_t pckbd_driver = { 7142795Skato DRIVER_NAME, 7245783Skato pckbd_methods, 7350236Skato 1, 7442795Skato}; 7542795Skato 7645783SkatoDRIVER_MODULE(pckbd, isa, pckbd_driver, pckbd_devclass, 0, 0); 7745783Skato 7878385Snyanstatic bus_addr_t pckbd_iat[] = {0, 2}; 7978385Snyan 80245317Simpstatic int pckbd_probe_unit(device_t dev, int port, int irq, 8144635Skato int flags); 82245317Simpstatic int pckbd_attach_unit(device_t dev, keyboard_t **kbd, 8344635Skato int port, int irq, int flags); 8442795Skatostatic timeout_t pckbd_timeout; 8542795Skato 8642795Skato 8742795Skatostatic int 8845783Skatopckbdprobe(device_t dev) 8942795Skato{ 9078385Snyan struct resource *res; 9178385Snyan int error, rid; 9278385Snyan 9351276Snyan /* Check isapnp ids */ 9451276Snyan if (isa_get_vendorid(dev)) 9551276Snyan return (ENXIO); 9651276Snyan 9745783Skato device_set_desc(dev, "PC-98 Keyboard"); 9845783Skato 9978385Snyan rid = 0; 10078385Snyan res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2, 10178385Snyan RF_ACTIVE); 10278385Snyan if (res == NULL) 10378385Snyan return ENXIO; 10478385Snyan isa_load_resourcev(res, pckbd_iat, 2); 10578385Snyan 106245317Simp error = pckbd_probe_unit(dev, 10778385Snyan isa_get_port(dev), 10878385Snyan (1 << isa_get_irq(dev)), 10978385Snyan device_get_flags(dev)); 11078385Snyan 11178385Snyan bus_release_resource(dev, SYS_RES_IOPORT, rid, res); 11278385Snyan 11378385Snyan return (error); 11442795Skato} 11542795Skato 11642795Skatostatic int 11745783Skatopckbdattach(device_t dev) 11842795Skato{ 11950236Skato keyboard_t *kbd; 12045783Skato void *ih; 12145783Skato struct resource *res; 12278385Snyan int error, rid; 12342795Skato 12478385Snyan rid = 0; 12578385Snyan res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, pckbd_iat, 2, 12678385Snyan RF_ACTIVE); 12778385Snyan if (res == NULL) 12878385Snyan return ENXIO; 12978385Snyan isa_load_resourcev(res, pckbd_iat, 2); 13045783Skato 131245317Simp error = pckbd_attach_unit(dev, &kbd, 13278385Snyan isa_get_port(dev), 13378385Snyan (1 << isa_get_irq(dev)), 13478385Snyan device_get_flags(dev)); 13578385Snyan 13678385Snyan rid = 0; 137127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 13878385Snyan if (res == NULL) 13978385Snyan return ENXIO; 140166901Spiso bus_setup_intr(dev, res, INTR_TYPE_TTY, NULL, pckbd_isa_intr, kbd, &ih); 14145783Skato 14279702Snyan return 0; 14379702Snyan} 14479702Snyan 14579702Snyanstatic int 14679702Snyanpckbdresume(device_t dev) 14779702Snyan{ 14879702Snyan keyboard_t *kbd; 14979702Snyan 15079702Snyan kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, 15179702Snyan device_get_unit(dev))); 15279702Snyan if (kbd) 153175001Snyan kbdd_clear_state(kbd); 15479702Snyan 15545783Skato return (0); 15642795Skato} 15742795Skato 15842795Skatostatic void 15945783Skatopckbd_isa_intr(void *arg) 16042795Skato{ 16150236Skato keyboard_t *kbd = arg; 16242795Skato 163175001Snyan kbdd_intr(kbd, NULL); 16442795Skato} 16542795Skato 16642795Skatostatic int 167245317Simppckbd_probe_unit(device_t dev, int port, int irq, int flags) 16842795Skato{ 16942795Skato keyboard_switch_t *sw; 17042795Skato int args[2]; 17144635Skato int error; 17242795Skato 17342795Skato sw = kbd_get_switch(DRIVER_NAME); 17442795Skato if (sw == NULL) 17542795Skato return ENXIO; 17642795Skato 17742795Skato args[0] = port; 17842795Skato args[1] = irq; 179245317Simp error = (*sw->probe)(device_get_unit(dev), args, flags); 18044635Skato if (error) 18144635Skato return error; 18244635Skato return 0; 18342795Skato} 18442795Skato 18542795Skatostatic int 186245317Simppckbd_attach_unit(device_t dev, keyboard_t **kbd, int port, int irq, int flags) 18742795Skato{ 18842795Skato keyboard_switch_t *sw; 18944635Skato int args[2]; 19042795Skato int error; 191245317Simp int unit; 19242795Skato 19342795Skato sw = kbd_get_switch(DRIVER_NAME); 19442795Skato if (sw == NULL) 19542795Skato return ENXIO; 19642795Skato 19742795Skato /* reset, initialize and enable the device */ 198245317Simp unit = device_get_unit(dev); 19944635Skato args[0] = port; 20044635Skato args[1] = irq; 20150236Skato *kbd = NULL; 20244635Skato error = (*sw->probe)(unit, args, flags); 20342795Skato if (error) 20444635Skato return error; 20550236Skato error = (*sw->init)(unit, kbd, args, flags); 20644635Skato if (error) 20744635Skato return error; 20850236Skato (*sw->enable)(*kbd); 20942795Skato 21042795Skato#ifdef KBD_INSTALL_CDEV 21142795Skato /* attach a virtual keyboard cdev */ 21250236Skato error = kbd_attach(*kbd); 21342795Skato if (error) 21442795Skato return error; 21542795Skato#endif /* KBD_INSTALL_CDEV */ 21642795Skato 21742795Skato /* 21842795Skato * This is a kludge to compensate for lost keyboard interrupts. 21942795Skato * A similar code used to be in syscons. See below. XXX 22042795Skato */ 22150236Skato pckbd_timeout(*kbd); 22242795Skato 22342795Skato if (bootverbose) 22450236Skato (*sw->diag)(*kbd, bootverbose); 22542795Skato 22642795Skato return 0; 22742795Skato} 22842795Skato 22942795Skatostatic void 23042795Skatopckbd_timeout(void *arg) 23142795Skato{ 23242795Skato keyboard_t *kbd; 23342795Skato int s; 23442795Skato 23542795Skato /* The following comments are extracted from syscons.c (1.287) */ 23642795Skato /* 23742795Skato * With release 2.1 of the Xaccel server, the keyboard is left 23842795Skato * hanging pretty often. Apparently an interrupt from the 23942795Skato * keyboard is lost, and I don't know why (yet). 24042795Skato * This ugly hack calls scintr if input is ready for the keyboard 24142795Skato * and conveniently hides the problem. XXX 24242795Skato */ 24342795Skato /* 24442795Skato * Try removing anything stuck in the keyboard controller; whether 24542795Skato * it's a keyboard scan code or mouse data. `scintr()' doesn't 24642795Skato * read the mouse data directly, but `kbdio' routines will, as a 24742795Skato * side effect. 24842795Skato */ 24942795Skato s = spltty(); 25042795Skato kbd = (keyboard_t *)arg; 251175001Snyan if (kbdd_lock(kbd, TRUE)) { 25242795Skato /* 25342795Skato * We have seen the lock flag is not set. Let's reset 25442795Skato * the flag early, otherwise the LED update routine fails 25542795Skato * which may want the lock during the interrupt routine. 25642795Skato */ 257175001Snyan kbdd_lock(kbd, FALSE); 258175001Snyan if (kbdd_check_char(kbd)) 259175001Snyan kbdd_intr(kbd, NULL); 26042795Skato } 26142795Skato splx(s); 26242795Skato timeout(pckbd_timeout, arg, hz/10); 26342795Skato} 26442795Skato 26542795Skato/* LOW-LEVEL */ 26642795Skato 267114216Skan#include <sys/limits.h> 26842795Skato 26942795Skato#define PC98KBD_DEFAULT 0 27042795Skato 27142795Skatotypedef caddr_t KBDC; 27242795Skato 27342795Skatotypedef struct pckbd_state { 27442795Skato KBDC kbdc; /* keyboard controller */ 27542795Skato int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 27642795Skato int ks_flags; /* flags */ 27742795Skato#define COMPOSE (1 << 0) 27842795Skato int ks_state; /* shift/lock key state */ 27942795Skato int ks_accents; /* accent key index (> 0) */ 28042795Skato u_int ks_composed_char; /* composed char code (> 0) */ 28142795Skato} pckbd_state_t; 28242795Skato 28342795Skato/* keyboard driver declaration */ 28442795Skatostatic int pckbd_configure(int flags); 28542795Skatostatic kbd_probe_t pckbd_probe; 28642795Skatostatic kbd_init_t pckbd_init; 28742795Skatostatic kbd_term_t pckbd_term; 28842795Skatostatic kbd_intr_t pckbd_intr; 28942795Skatostatic kbd_test_if_t pckbd_test_if; 29042795Skatostatic kbd_enable_t pckbd_enable; 29142795Skatostatic kbd_disable_t pckbd_disable; 29242795Skatostatic kbd_read_t pckbd_read; 29342795Skatostatic kbd_check_t pckbd_check; 29442795Skatostatic kbd_read_char_t pckbd_read_char; 29542795Skatostatic kbd_check_char_t pckbd_check_char; 29642795Skatostatic kbd_ioctl_t pckbd_ioctl; 29742795Skatostatic kbd_lock_t pckbd_lock; 29842795Skatostatic kbd_clear_state_t pckbd_clear_state; 29942795Skatostatic kbd_get_state_t pckbd_get_state; 30042795Skatostatic kbd_set_state_t pckbd_set_state; 30144635Skatostatic kbd_poll_mode_t pckbd_poll; 30242795Skato 30342795Skatokeyboard_switch_t pckbdsw = { 30442795Skato pckbd_probe, 30542795Skato pckbd_init, 30642795Skato pckbd_term, 30742795Skato pckbd_intr, 30842795Skato pckbd_test_if, 30942795Skato pckbd_enable, 31042795Skato pckbd_disable, 31142795Skato pckbd_read, 31242795Skato pckbd_check, 31342795Skato pckbd_read_char, 31442795Skato pckbd_check_char, 31542795Skato pckbd_ioctl, 31642795Skato pckbd_lock, 31742795Skato pckbd_clear_state, 31842795Skato pckbd_get_state, 31942795Skato pckbd_set_state, 32042795Skato genkbd_get_fkeystr, 32144635Skato pckbd_poll, 32242795Skato genkbd_diag, 32342795Skato}; 32442795Skato 32542795SkatoKEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure); 32642795Skato 32742795Skatostruct kbdc_softc { 32842795Skato int port; /* base port address */ 32942795Skato int lock; /* FIXME: XXX not quite a semaphore... */ 33042795Skato}; 33142795Skato 33242795Skato/* local functions */ 33342795Skatostatic int probe_keyboard(KBDC kbdc, int flags); 33442795Skatostatic int init_keyboard(KBDC kbdc, int *type, int flags); 33542795Skatostatic KBDC kbdc_open(int port); 33642795Skatostatic int kbdc_lock(KBDC kbdc, int lock); 33742795Skatostatic int kbdc_data_ready(KBDC kbdc); 33842795Skatostatic int read_kbd_data(KBDC kbdc); 33942795Skatostatic int read_kbd_data_no_wait(KBDC kbdc); 34042795Skatostatic int wait_for_kbd_data(struct kbdc_softc *kbdc); 34142795Skato 34242795Skato/* local variables */ 34342795Skato 34442795Skato/* the initial key map, accent map and fkey strings */ 345146138Snyan#include <pc98/cbus/pckbdtables.h> 34642795Skato 34742795Skato/* structures for the default keyboard */ 34842795Skatostatic keyboard_t default_kbd; 34942795Skatostatic pckbd_state_t default_kbd_state; 35042795Skatostatic keymap_t default_keymap; 35142795Skatostatic accentmap_t default_accentmap; 35242795Skatostatic fkeytab_t default_fkeytab[NUM_FKEYS]; 35342795Skato 35442795Skato/* 35542795Skato * The back door to the keyboard driver! 35642795Skato * This function is called by the console driver, via the kbdio module, 35742795Skato * to tickle keyboard drivers when the low-level console is being initialized. 35842795Skato * Almost nothing in the kernel has been initialied yet. Try to probe 35942795Skato * keyboards if possible. 36042795Skato * NOTE: because of the way the low-level conole is initialized, this routine 36142795Skato * may be called more than once!! 36242795Skato */ 36342795Skatostatic int 36442795Skatopckbd_configure(int flags) 36542795Skato{ 36642795Skato keyboard_t *kbd; 36742795Skato int arg[2]; 36844635Skato int i; 36942795Skato 37042795Skato /* XXX: a kludge to obtain the device configuration flags */ 37145783Skato if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) { 37245783Skato flags |= i; 37344635Skato /* if the driver is disabled, unregister the keyboard if any */ 374117167Sjhb if (resource_disabled(DRIVER_NAME, 0)) { 37544635Skato i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT); 37644635Skato if (i >= 0) { 37744635Skato kbd = kbd_get_keyboard(i); 37844635Skato kbd_unregister(kbd); 37944635Skato kbd->kb_flags &= ~KB_REGISTERED; 38044635Skato return 0; 38144635Skato } 38244635Skato } 38344635Skato } 38442795Skato 38542795Skato /* probe the default keyboard */ 38642795Skato arg[0] = -1; 38742795Skato arg[1] = -1; 38844635Skato kbd = NULL; 38944635Skato if (pckbd_probe(PC98KBD_DEFAULT, arg, flags)) 39042795Skato return 0; 39144635Skato if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags)) 39244635Skato return 0; 39342795Skato 39444635Skato /* return the number of found keyboards */ 39544635Skato return 1; 39642795Skato} 39742795Skato 39842795Skato/* low-level functions */ 39942795Skato 40044635Skato/* detect a keyboard */ 40142795Skatostatic int 40244635Skatopckbd_probe(int unit, void *arg, int flags) 40342795Skato{ 40442795Skato KBDC kbdc; 40542795Skato int *data = (int *)arg; 40642795Skato 40742795Skato if (unit != PC98KBD_DEFAULT) 40842795Skato return ENXIO; 40944635Skato if (KBD_IS_PROBED(&default_kbd)) 41042795Skato return 0; 41142795Skato 41244635Skato kbdc = kbdc_open(data[0]); 41342795Skato if (kbdc == NULL) 41442795Skato return ENXIO; 41542795Skato if (probe_keyboard(kbdc, flags)) { 41642795Skato if (flags & KB_CONF_FAIL_IF_NO_KBD) 41742795Skato return ENXIO; 41842795Skato } 41942795Skato return 0; 42042795Skato} 42142795Skato 42242795Skato/* reset and initialize the device */ 42342795Skatostatic int 42444635Skatopckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 42542795Skato{ 42644635Skato keyboard_t *kbd; 42744635Skato pckbd_state_t *state; 42844635Skato keymap_t *keymap; 42944635Skato accentmap_t *accmap; 43044635Skato fkeytab_t *fkeymap; 43144635Skato int fkeymap_size; 43244635Skato int *data = (int *)arg; 43342795Skato 43444635Skato if (unit != PC98KBD_DEFAULT) /* shouldn't happen */ 43544635Skato return ENXIO; 43642795Skato 43744635Skato *kbdp = kbd = &default_kbd; 43844635Skato state = &default_kbd_state; 43944635Skato if (!KBD_IS_PROBED(kbd)) { 44044635Skato keymap = &default_keymap; 44144635Skato accmap = &default_accentmap; 44244635Skato fkeymap = default_fkeytab; 44344635Skato fkeymap_size = 44444635Skato sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 44544635Skato 44644635Skato state->kbdc = kbdc_open(data[0]); 44744635Skato if (state->kbdc == NULL) 44844635Skato return ENXIO; 44944635Skato kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags, 45044635Skato data[0], IO_KBDSIZE); 45144635Skato bcopy(&key_map, keymap, sizeof(key_map)); 45244635Skato bcopy(&accent_map, accmap, sizeof(accent_map)); 45344635Skato bcopy(fkey_tab, fkeymap, 45444635Skato imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 45544635Skato kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 45644635Skato kbd->kb_data = (void *)state; 45744635Skato 45844635Skato if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */ 45944635Skato if (flags & KB_CONF_FAIL_IF_NO_KBD) 46044635Skato return ENXIO; 46144635Skato } else { 46244635Skato KBD_FOUND_DEVICE(kbd); 46344635Skato } 46444635Skato pckbd_clear_state(kbd); 46544635Skato state->ks_mode = K_XLATE; 46644635Skato KBD_PROBE_DONE(kbd); 46744635Skato } 46844635Skato if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 46942795Skato if (KBD_HAS_DEVICE(kbd) 47044635Skato && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 47142795Skato && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) 47242795Skato return ENXIO; 47344635Skato pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 47442795Skato KBD_INIT_DONE(kbd); 47542795Skato } 47642795Skato if (!KBD_IS_CONFIGURED(kbd)) { 47742795Skato if (kbd_register(kbd) < 0) 47842795Skato return ENXIO; 47942795Skato KBD_CONFIG_DONE(kbd); 48042795Skato } 48142795Skato 48242795Skato return 0; 48342795Skato} 48442795Skato 48542795Skato/* finish using this keyboard */ 48642795Skatostatic int 48742795Skatopckbd_term(keyboard_t *kbd) 48842795Skato{ 48942795Skato kbd_unregister(kbd); 49042795Skato return 0; 49142795Skato} 49242795Skato 49342795Skato/* keyboard interrupt routine */ 49442795Skatostatic int 49544635Skatopckbd_intr(keyboard_t *kbd, void *arg) 49642795Skato{ 49742795Skato int c; 49842795Skato 49942795Skato if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 50042795Skato /* let the callback function to process the input */ 50142795Skato (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 50242795Skato kbd->kb_callback.kc_arg); 50342795Skato } else { 50442795Skato /* read and discard the input; no one is waiting for input */ 50542795Skato do { 50642795Skato c = pckbd_read_char(kbd, FALSE); 50742795Skato } while (c != NOKEY); 50842795Skato } 50942795Skato return 0; 51042795Skato} 51142795Skato 51242795Skato/* test the interface to the device */ 51342795Skatostatic int 51442795Skatopckbd_test_if(keyboard_t *kbd) 51542795Skato{ 51642795Skato return 0; 51742795Skato} 51842795Skato 51942795Skato/* 52042795Skato * Enable the access to the device; until this function is called, 52142795Skato * the client cannot read from the keyboard. 52242795Skato */ 52342795Skatostatic int 52442795Skatopckbd_enable(keyboard_t *kbd) 52542795Skato{ 52642795Skato int s; 52742795Skato 52842795Skato s = spltty(); 52942795Skato KBD_ACTIVATE(kbd); 53042795Skato splx(s); 53142795Skato return 0; 53242795Skato} 53342795Skato 53442795Skato/* disallow the access to the device */ 53542795Skatostatic int 53642795Skatopckbd_disable(keyboard_t *kbd) 53742795Skato{ 53842795Skato int s; 53942795Skato 54042795Skato s = spltty(); 54142795Skato KBD_DEACTIVATE(kbd); 54242795Skato splx(s); 54342795Skato return 0; 54442795Skato} 54542795Skato 54642795Skato/* read one byte from the keyboard if it's allowed */ 54742795Skatostatic int 54842795Skatopckbd_read(keyboard_t *kbd, int wait) 54942795Skato{ 55042795Skato int c; 55142795Skato 55242795Skato if (wait) 55342795Skato c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc); 55442795Skato else 55542795Skato c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc); 55654551Skato if (c != -1) 55754551Skato ++kbd->kb_count; 55842795Skato return (KBD_IS_ACTIVE(kbd) ? c : -1); 55942795Skato} 56042795Skato 56142795Skato/* check if data is waiting */ 56242795Skatostatic int 56342795Skatopckbd_check(keyboard_t *kbd) 56442795Skato{ 56542795Skato if (!KBD_IS_ACTIVE(kbd)) 56642795Skato return FALSE; 56742795Skato return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc); 56842795Skato} 56942795Skato 57042795Skato/* read char from the keyboard */ 57142795Skatostatic u_int 57242795Skatopckbd_read_char(keyboard_t *kbd, int wait) 57342795Skato{ 57442795Skato pckbd_state_t *state; 57542795Skato u_int action; 57642795Skato int scancode; 57742795Skato int keycode; 57842795Skato 57942795Skato state = (pckbd_state_t *)kbd->kb_data; 58042795Skatonext_code: 58142795Skato /* do we have a composed char to return? */ 58242795Skato if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 58342795Skato action = state->ks_composed_char; 58442795Skato state->ks_composed_char = 0; 58542795Skato if (action > UCHAR_MAX) 58642795Skato return ERRKEY; 58742795Skato return action; 58842795Skato } 58942795Skato 59042795Skato /* see if there is something in the keyboard port */ 59142795Skato if (wait) { 59242795Skato do { 59342795Skato scancode = read_kbd_data(state->kbdc); 59442795Skato } while (scancode == -1); 59542795Skato } else { 59642795Skato scancode = read_kbd_data_no_wait(state->kbdc); 59742795Skato if (scancode == -1) 59842795Skato return NOKEY; 59942795Skato } 60054551Skato ++kbd->kb_count; 60142795Skato 60254551Skato#if 0 60354551Skato printf("pckbd_read_char(): scancode:0x%x\n", scancode); 60454551Skato#endif 60554551Skato 60642795Skato /* return the byte as is for the K_RAW mode */ 60742795Skato if (state->ks_mode == K_RAW) 60842795Skato return scancode; 60942795Skato 61042795Skato /* translate the scan code into a keycode */ 61142795Skato keycode = scancode & 0x7F; 61242795Skato switch(scancode) { 61342795Skato case 0xF3: /* GRPH (compose key) released */ 61442795Skato if (state->ks_flags & COMPOSE) { 61542795Skato state->ks_flags &= ~COMPOSE; 61642795Skato if (state->ks_composed_char > UCHAR_MAX) 61742795Skato state->ks_composed_char = 0; 61842795Skato } 61942795Skato break; 62042795Skato case 0x73: /* GRPH (compose key) pressed */ 62142795Skato if (!(state->ks_flags & COMPOSE)) { 62242795Skato state->ks_flags |= COMPOSE; 62342795Skato state->ks_composed_char = 0; 62442795Skato } 62542795Skato break; 62642795Skato } 62742795Skato 62842795Skato /* return the key code in the K_CODE mode */ 62942795Skato if (state->ks_mode == K_CODE) 63042795Skato return (keycode | (scancode & 0x80)); 63142795Skato 63242795Skato /* compose a character code */ 63342795Skato if (state->ks_flags & COMPOSE) { 63442795Skato switch (scancode) { 63542795Skato /* key pressed, process it */ 63642795Skato case 0x42: case 0x43: case 0x44: /* keypad 7,8,9 */ 63742795Skato state->ks_composed_char *= 10; 63842795Skato state->ks_composed_char += scancode - 0x3B; 63942795Skato if (state->ks_composed_char > UCHAR_MAX) 64042795Skato return ERRKEY; 64142795Skato goto next_code; 64242795Skato case 0x46: case 0x47: case 0x48: /* keypad 4,5,6 */ 64342795Skato state->ks_composed_char *= 10; 64442795Skato state->ks_composed_char += scancode - 0x42; 64542795Skato if (state->ks_composed_char > UCHAR_MAX) 64642795Skato return ERRKEY; 64742795Skato goto next_code; 64842795Skato case 0x4A: case 0x4B: case 0x4C: /* keypad 1,2,3 */ 64942795Skato state->ks_composed_char *= 10; 65042795Skato state->ks_composed_char += scancode - 0x49; 65142795Skato if (state->ks_composed_char > UCHAR_MAX) 65242795Skato return ERRKEY; 65342795Skato goto next_code; 65442795Skato case 0x4E: /* keypad 0 */ 65542795Skato state->ks_composed_char *= 10; 65642795Skato if (state->ks_composed_char > UCHAR_MAX) 65742795Skato return ERRKEY; 65842795Skato goto next_code; 65942795Skato 66042795Skato /* key released, no interest here */ 66142795Skato case 0xC2: case 0xC3: case 0xC4: /* keypad 7,8,9 */ 66242795Skato case 0xC6: case 0xC7: case 0xC8: /* keypad 4,5,6 */ 66342795Skato case 0xCA: case 0xCB: case 0xCC: /* keypad 1,2,3 */ 66442795Skato case 0xCE: /* keypad 0 */ 66542795Skato goto next_code; 66642795Skato 66742795Skato case 0x73: /* GRPH key */ 66842795Skato break; 66942795Skato 67042795Skato default: 67142795Skato if (state->ks_composed_char > 0) { 67242795Skato state->ks_flags &= ~COMPOSE; 67342795Skato state->ks_composed_char = 0; 67442795Skato return ERRKEY; 67542795Skato } 67642795Skato break; 67742795Skato } 67842795Skato } 67942795Skato 68042795Skato /* keycode to key action */ 68142795Skato action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 68242795Skato &state->ks_state, &state->ks_accents); 68342795Skato if (action == NOKEY) 68442795Skato goto next_code; 68542795Skato else 68642795Skato return action; 68742795Skato} 68842795Skato 68942795Skato/* check if char is waiting */ 69042795Skatostatic int 69142795Skatopckbd_check_char(keyboard_t *kbd) 69242795Skato{ 69342795Skato pckbd_state_t *state; 69442795Skato 69542795Skato if (!KBD_IS_ACTIVE(kbd)) 69642795Skato return FALSE; 69742795Skato state = (pckbd_state_t *)kbd->kb_data; 69842795Skato if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 69942795Skato return TRUE; 70042795Skato return kbdc_data_ready(state->kbdc); 70142795Skato} 70242795Skato 70342795Skato/* some useful control functions */ 70442795Skatostatic int 70542795Skatopckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 70642795Skato{ 70742795Skato pckbd_state_t *state = kbd->kb_data; 70842795Skato int s; 70942795Skato int i; 710162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 711162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 712162711Sru int ival; 713162711Sru#endif 71442795Skato 71542795Skato s = spltty(); 71642795Skato switch (cmd) { 71742795Skato 71842795Skato case KDGKBMODE: /* get keyboard mode */ 71942795Skato *(int *)arg = state->ks_mode; 72042795Skato break; 721162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 722162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 723162711Sru case _IO('K', 7): 724162711Sru ival = IOCPARM_IVAL(arg); 725162711Sru arg = (caddr_t)&ival; 726162711Sru /* FALLTHROUGH */ 727162711Sru#endif 72842795Skato case KDSKBMODE: /* set keyboard mode */ 72942795Skato switch (*(int *)arg) { 73042795Skato case K_XLATE: 73142795Skato if (state->ks_mode != K_XLATE) { 73242795Skato /* make lock key state and LED state match */ 73342795Skato state->ks_state &= ~LOCK_MASK; 73442795Skato state->ks_state |= KBD_LED_VAL(kbd); 73542795Skato } 736102412Scharnier /* FALLTHROUGH */ 73742795Skato case K_RAW: 73842795Skato case K_CODE: 73942795Skato if (state->ks_mode != *(int *)arg) { 74042795Skato pckbd_clear_state(kbd); 74142795Skato state->ks_mode = *(int *)arg; 74242795Skato } 74342795Skato break; 74442795Skato default: 74542795Skato splx(s); 74642795Skato return EINVAL; 74742795Skato } 74842795Skato break; 74942795Skato 75042795Skato case KDGETLED: /* get keyboard LED */ 75142795Skato *(int *)arg = KBD_LED_VAL(kbd); 75242795Skato break; 753162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 754162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 755162711Sru case _IO('K', 66): 756162711Sru ival = IOCPARM_IVAL(arg); 757162711Sru arg = (caddr_t)&ival; 758162711Sru /* FALLTHROUGH */ 759162711Sru#endif 76042795Skato case KDSETLED: /* set keyboard LED */ 76142795Skato /* NOTE: lock key state in ks_state won't be changed */ 76242795Skato if (*(int *)arg & ~LOCK_MASK) { 76342795Skato splx(s); 76442795Skato return EINVAL; 76542795Skato } 76642795Skato i = *(int *)arg; 76742795Skato /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 76842795Skato if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 76942795Skato if (i & ALKED) 77042795Skato i |= CLKED; 77142795Skato else 77242795Skato i &= ~CLKED; 77342795Skato } 77442795Skato KBD_LED_VAL(kbd) = *(int *)arg; 77542795Skato break; 77642795Skato 77742795Skato case KDGKBSTATE: /* get lock key state */ 77842795Skato *(int *)arg = state->ks_state & LOCK_MASK; 77942795Skato break; 780162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 781162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 782162711Sru case _IO('K', 20): 783162711Sru ival = IOCPARM_IVAL(arg); 784162711Sru arg = (caddr_t)&ival; 785162711Sru /* FALLTHROUGH */ 786162711Sru#endif 78742795Skato case KDSKBSTATE: /* set lock key state */ 78842795Skato if (*(int *)arg & ~LOCK_MASK) { 78942795Skato splx(s); 79042795Skato return EINVAL; 79142795Skato } 79242795Skato state->ks_state &= ~LOCK_MASK; 79342795Skato state->ks_state |= *(int *)arg; 79442795Skato splx(s); 79542795Skato /* set LEDs and quit */ 79642795Skato return pckbd_ioctl(kbd, KDSETLED, arg); 79742795Skato 79844635Skato case KDSETRAD: /* set keyboard repeat rate (old interface)*/ 79942795Skato break; 80044635Skato case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 80144635Skato break; 80242795Skato 80342795Skato case PIO_KEYMAP: /* set keyboard translation table */ 804224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 80542795Skato case PIO_KEYMAPENT: /* set keyboard translation table entry */ 80642795Skato case PIO_DEADKEYMAP: /* set accent key translation table */ 80742795Skato state->ks_accents = 0; 808102412Scharnier /* FALLTHROUGH */ 80942795Skato default: 81042795Skato splx(s); 81142795Skato return genkbd_commonioctl(kbd, cmd, arg); 81242795Skato } 81342795Skato 81442795Skato splx(s); 81542795Skato return 0; 81642795Skato} 81742795Skato 81842795Skato/* lock the access to the keyboard */ 81942795Skatostatic int 82042795Skatopckbd_lock(keyboard_t *kbd, int lock) 82142795Skato{ 82242795Skato return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock); 82342795Skato} 82442795Skato 82542795Skato/* clear the internal state of the keyboard */ 82642795Skatostatic void 82742795Skatopckbd_clear_state(keyboard_t *kbd) 82842795Skato{ 82942795Skato pckbd_state_t *state; 83042795Skato 83142795Skato state = (pckbd_state_t *)kbd->kb_data; 83242795Skato state->ks_flags = 0; 83342795Skato state->ks_state &= LOCK_MASK; /* preserve locking key state */ 83442795Skato state->ks_accents = 0; 83542795Skato state->ks_composed_char = 0; 83642795Skato} 83742795Skato 83842795Skato/* save the internal state */ 83942795Skatostatic int 84042795Skatopckbd_get_state(keyboard_t *kbd, void *buf, size_t len) 84142795Skato{ 84242795Skato if (len == 0) 84342795Skato return sizeof(pckbd_state_t); 84442795Skato if (len < sizeof(pckbd_state_t)) 84542795Skato return -1; 84642795Skato bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t)); 84742795Skato return 0; 84842795Skato} 84942795Skato 85042795Skato/* set the internal state */ 85142795Skatostatic int 85242795Skatopckbd_set_state(keyboard_t *kbd, void *buf, size_t len) 85342795Skato{ 85442795Skato if (len < sizeof(pckbd_state_t)) 85542795Skato return ENOMEM; 85642795Skato if (((pckbd_state_t *)kbd->kb_data)->kbdc 85742795Skato != ((pckbd_state_t *)buf)->kbdc) 85842795Skato return ENOMEM; 85942795Skato bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t)); 86042795Skato return 0; 86142795Skato} 86242795Skato 86344635Skato/* set polling mode */ 86444635Skatostatic int 86544635Skatopckbd_poll(keyboard_t *kbd, int on) 86644635Skato{ 86744635Skato return 0; 86844635Skato} 86944635Skato 87042795Skato/* local functions */ 87142795Skato 87242795Skatostatic int 87342795Skatoprobe_keyboard(KBDC kbdc, int flags) 87442795Skato{ 87542795Skato return 0; 87642795Skato} 87742795Skato 87842795Skatostatic int 87942795Skatoinit_keyboard(KBDC kbdc, int *type, int flags) 88042795Skato{ 88142795Skato *type = KB_OTHER; 88242795Skato return 0; 88342795Skato} 88442795Skato 88542795Skato/* keyboard I/O routines */ 88642795Skato 88742795Skato/* retry count */ 88842795Skato#ifndef KBD_MAXRETRY 88942795Skato#define KBD_MAXRETRY 3 89042795Skato#endif 89142795Skato 89242795Skato/* timing parameters */ 89342795Skato#ifndef KBD_RESETDELAY 89442795Skato#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ 89542795Skato#endif 89642795Skato#ifndef KBD_MAXWAIT 89742795Skato#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ 89842795Skato#endif 89942795Skato 90042795Skato/* I/O recovery time */ 90142795Skato#define KBDC_DELAYTIME 37 90242795Skato#define KBDD_DELAYTIME 37 90342795Skato 90442795Skato/* I/O ports */ 90542795Skato#define KBD_STATUS_PORT 2 /* status port, read */ 90642795Skato#define KBD_DATA_PORT 0 /* data port, read */ 90742795Skato 90842795Skato/* status bits (KBD_STATUS_PORT) */ 90942795Skato#define KBDS_BUFFER_FULL 0x0002 91042795Skato 91142795Skato/* macros */ 91242795Skato 91342795Skato#define kbdcp(p) ((struct kbdc_softc *)(p)) 91442795Skato 91542795Skato/* local variables */ 91642795Skato 917102151Speterstatic struct kbdc_softc kbdc_softc[1] = { { 0 }, }; 91842795Skato 91942795Skato/* associate a port number with a KBDC */ 92042795Skato 92142795Skatostatic KBDC 92242795Skatokbdc_open(int port) 92342795Skato{ 92442795Skato if (port <= 0) 92542795Skato port = IO_KBD; 92642795Skato 927102151Speter /* PC-98 has only one keyboard I/F */ 928102151Speter kbdc_softc[0].port = port; 929102151Speter kbdc_softc[0].lock = FALSE; 930102151Speter return (KBDC)&kbdc_softc[0]; 93142795Skato} 93242795Skato 93342795Skato/* set/reset polling lock */ 93442795Skatostatic int 93542795Skatokbdc_lock(KBDC p, int lock) 93642795Skato{ 93742795Skato int prevlock; 93842795Skato 93942795Skato prevlock = kbdcp(p)->lock; 94042795Skato kbdcp(p)->lock = lock; 94142795Skato 94242795Skato return (prevlock != lock); 94342795Skato} 94442795Skato 94542795Skato/* check if any data is waiting to be processed */ 94642795Skatostatic int 94742795Skatokbdc_data_ready(KBDC p) 94842795Skato{ 94942795Skato return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL); 95042795Skato} 95142795Skato 95242795Skato/* wait for data from the keyboard */ 95342795Skatostatic int 95442795Skatowait_for_kbd_data(struct kbdc_softc *kbdc) 95542795Skato{ 95642795Skato /* CPU will stay inside the loop for 200msec at most */ 95742795Skato int retry = 10000; 95842795Skato int port = kbdc->port; 95942795Skato 96042795Skato while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) { 96142795Skato DELAY(KBDD_DELAYTIME); 96242795Skato DELAY(KBDC_DELAYTIME); 96342795Skato if (--retry < 0) 96442795Skato return 0; 96542795Skato } 96642795Skato DELAY(KBDD_DELAYTIME); 96742795Skato return 1; 96842795Skato} 96942795Skato 97042795Skato/* read one byte from the keyboard */ 97142795Skatostatic int 97242795Skatoread_kbd_data(KBDC p) 97342795Skato{ 97442795Skato if (!wait_for_kbd_data(kbdcp(p))) 97542795Skato return -1; /* timeout */ 97642795Skato DELAY(KBDC_DELAYTIME); 97742795Skato return inb(kbdcp(p)->port + KBD_DATA_PORT); 97842795Skato} 97942795Skato 98042795Skato/* read one byte from the keyboard, but return immediately if 98142795Skato * no data is waiting 98242795Skato */ 98342795Skatostatic int 98442795Skatoread_kbd_data_no_wait(KBDC p) 98542795Skato{ 98642795Skato if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) { 98742795Skato DELAY(KBDD_DELAYTIME); 98842795Skato return inb(kbdcp(p)->port + KBD_DATA_PORT); 98942795Skato } 99042795Skato return -1; /* no data */ 99142795Skato} 992