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 8044635Skatostatic int pckbd_probe_unit(int unit, int port, int irq, 8144635Skato int flags); 8250236Skatostatic int pckbd_attach_unit(int unit, 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 10678385Snyan error = pckbd_probe_unit(device_get_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 13178385Snyan error = pckbd_attach_unit(device_get_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 16744635Skatopckbd_probe_unit(int unit, 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; 17944635Skato error = (*sw->probe)(unit, args, flags); 18044635Skato if (error) 18144635Skato return error; 18244635Skato return 0; 18342795Skato} 18442795Skato 18542795Skatostatic int 18650236Skatopckbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags) 18742795Skato{ 18842795Skato keyboard_switch_t *sw; 18944635Skato int args[2]; 19042795Skato int error; 19142795Skato 19242795Skato sw = kbd_get_switch(DRIVER_NAME); 19342795Skato if (sw == NULL) 19442795Skato return ENXIO; 19542795Skato 19642795Skato /* reset, initialize and enable the device */ 19744635Skato args[0] = port; 19844635Skato args[1] = irq; 19950236Skato *kbd = NULL; 20044635Skato error = (*sw->probe)(unit, args, flags); 20142795Skato if (error) 20244635Skato return error; 20350236Skato error = (*sw->init)(unit, kbd, args, flags); 20444635Skato if (error) 20544635Skato return error; 20650236Skato (*sw->enable)(*kbd); 20742795Skato 20842795Skato#ifdef KBD_INSTALL_CDEV 20942795Skato /* attach a virtual keyboard cdev */ 21050236Skato error = kbd_attach(*kbd); 21142795Skato if (error) 21242795Skato return error; 21342795Skato#endif /* KBD_INSTALL_CDEV */ 21442795Skato 21542795Skato /* 21642795Skato * This is a kludge to compensate for lost keyboard interrupts. 21742795Skato * A similar code used to be in syscons. See below. XXX 21842795Skato */ 21950236Skato pckbd_timeout(*kbd); 22042795Skato 22142795Skato if (bootverbose) 22250236Skato (*sw->diag)(*kbd, bootverbose); 22342795Skato 22442795Skato return 0; 22542795Skato} 22642795Skato 22742795Skatostatic void 22842795Skatopckbd_timeout(void *arg) 22942795Skato{ 23042795Skato keyboard_t *kbd; 23142795Skato int s; 23242795Skato 23342795Skato /* The following comments are extracted from syscons.c (1.287) */ 23442795Skato /* 23542795Skato * With release 2.1 of the Xaccel server, the keyboard is left 23642795Skato * hanging pretty often. Apparently an interrupt from the 23742795Skato * keyboard is lost, and I don't know why (yet). 23842795Skato * This ugly hack calls scintr if input is ready for the keyboard 23942795Skato * and conveniently hides the problem. XXX 24042795Skato */ 24142795Skato /* 24242795Skato * Try removing anything stuck in the keyboard controller; whether 24342795Skato * it's a keyboard scan code or mouse data. `scintr()' doesn't 24442795Skato * read the mouse data directly, but `kbdio' routines will, as a 24542795Skato * side effect. 24642795Skato */ 24742795Skato s = spltty(); 24842795Skato kbd = (keyboard_t *)arg; 249175001Snyan if (kbdd_lock(kbd, TRUE)) { 25042795Skato /* 25142795Skato * We have seen the lock flag is not set. Let's reset 25242795Skato * the flag early, otherwise the LED update routine fails 25342795Skato * which may want the lock during the interrupt routine. 25442795Skato */ 255175001Snyan kbdd_lock(kbd, FALSE); 256175001Snyan if (kbdd_check_char(kbd)) 257175001Snyan kbdd_intr(kbd, NULL); 25842795Skato } 25942795Skato splx(s); 26042795Skato timeout(pckbd_timeout, arg, hz/10); 26142795Skato} 26242795Skato 26342795Skato/* LOW-LEVEL */ 26442795Skato 265114216Skan#include <sys/limits.h> 26642795Skato 26742795Skato#define PC98KBD_DEFAULT 0 26842795Skato 26942795Skatotypedef caddr_t KBDC; 27042795Skato 27142795Skatotypedef struct pckbd_state { 27242795Skato KBDC kbdc; /* keyboard controller */ 27342795Skato int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 27442795Skato int ks_flags; /* flags */ 27542795Skato#define COMPOSE (1 << 0) 27642795Skato int ks_state; /* shift/lock key state */ 27742795Skato int ks_accents; /* accent key index (> 0) */ 27842795Skato u_int ks_composed_char; /* composed char code (> 0) */ 27942795Skato} pckbd_state_t; 28042795Skato 28142795Skato/* keyboard driver declaration */ 28242795Skatostatic int pckbd_configure(int flags); 28342795Skatostatic kbd_probe_t pckbd_probe; 28442795Skatostatic kbd_init_t pckbd_init; 28542795Skatostatic kbd_term_t pckbd_term; 28642795Skatostatic kbd_intr_t pckbd_intr; 28742795Skatostatic kbd_test_if_t pckbd_test_if; 28842795Skatostatic kbd_enable_t pckbd_enable; 28942795Skatostatic kbd_disable_t pckbd_disable; 29042795Skatostatic kbd_read_t pckbd_read; 29142795Skatostatic kbd_check_t pckbd_check; 29242795Skatostatic kbd_read_char_t pckbd_read_char; 29342795Skatostatic kbd_check_char_t pckbd_check_char; 29442795Skatostatic kbd_ioctl_t pckbd_ioctl; 29542795Skatostatic kbd_lock_t pckbd_lock; 29642795Skatostatic kbd_clear_state_t pckbd_clear_state; 29742795Skatostatic kbd_get_state_t pckbd_get_state; 29842795Skatostatic kbd_set_state_t pckbd_set_state; 29944635Skatostatic kbd_poll_mode_t pckbd_poll; 30042795Skato 30142795Skatokeyboard_switch_t pckbdsw = { 30242795Skato pckbd_probe, 30342795Skato pckbd_init, 30442795Skato pckbd_term, 30542795Skato pckbd_intr, 30642795Skato pckbd_test_if, 30742795Skato pckbd_enable, 30842795Skato pckbd_disable, 30942795Skato pckbd_read, 31042795Skato pckbd_check, 31142795Skato pckbd_read_char, 31242795Skato pckbd_check_char, 31342795Skato pckbd_ioctl, 31442795Skato pckbd_lock, 31542795Skato pckbd_clear_state, 31642795Skato pckbd_get_state, 31742795Skato pckbd_set_state, 31842795Skato genkbd_get_fkeystr, 31944635Skato pckbd_poll, 32042795Skato genkbd_diag, 32142795Skato}; 32242795Skato 32342795SkatoKEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure); 32442795Skato 32542795Skatostruct kbdc_softc { 32642795Skato int port; /* base port address */ 32742795Skato int lock; /* FIXME: XXX not quite a semaphore... */ 32842795Skato}; 32942795Skato 33042795Skato/* local functions */ 33142795Skatostatic int probe_keyboard(KBDC kbdc, int flags); 33242795Skatostatic int init_keyboard(KBDC kbdc, int *type, int flags); 33342795Skatostatic KBDC kbdc_open(int port); 33442795Skatostatic int kbdc_lock(KBDC kbdc, int lock); 33542795Skatostatic int kbdc_data_ready(KBDC kbdc); 33642795Skatostatic int read_kbd_data(KBDC kbdc); 33742795Skatostatic int read_kbd_data_no_wait(KBDC kbdc); 33842795Skatostatic int wait_for_kbd_data(struct kbdc_softc *kbdc); 33942795Skato 34042795Skato/* local variables */ 34142795Skato 34242795Skato/* the initial key map, accent map and fkey strings */ 343146138Snyan#include <pc98/cbus/pckbdtables.h> 34442795Skato 34542795Skato/* structures for the default keyboard */ 34642795Skatostatic keyboard_t default_kbd; 34742795Skatostatic pckbd_state_t default_kbd_state; 34842795Skatostatic keymap_t default_keymap; 34942795Skatostatic accentmap_t default_accentmap; 35042795Skatostatic fkeytab_t default_fkeytab[NUM_FKEYS]; 35142795Skato 35242795Skato/* 35342795Skato * The back door to the keyboard driver! 35442795Skato * This function is called by the console driver, via the kbdio module, 35542795Skato * to tickle keyboard drivers when the low-level console is being initialized. 35642795Skato * Almost nothing in the kernel has been initialied yet. Try to probe 35742795Skato * keyboards if possible. 35842795Skato * NOTE: because of the way the low-level conole is initialized, this routine 35942795Skato * may be called more than once!! 36042795Skato */ 36142795Skatostatic int 36242795Skatopckbd_configure(int flags) 36342795Skato{ 36442795Skato keyboard_t *kbd; 36542795Skato int arg[2]; 36644635Skato int i; 36742795Skato 36842795Skato /* XXX: a kludge to obtain the device configuration flags */ 36945783Skato if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) { 37045783Skato flags |= i; 37144635Skato /* if the driver is disabled, unregister the keyboard if any */ 372117167Sjhb if (resource_disabled(DRIVER_NAME, 0)) { 37344635Skato i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT); 37444635Skato if (i >= 0) { 37544635Skato kbd = kbd_get_keyboard(i); 37644635Skato kbd_unregister(kbd); 37744635Skato kbd->kb_flags &= ~KB_REGISTERED; 37844635Skato return 0; 37944635Skato } 38044635Skato } 38144635Skato } 38242795Skato 38342795Skato /* probe the default keyboard */ 38442795Skato arg[0] = -1; 38542795Skato arg[1] = -1; 38644635Skato kbd = NULL; 38744635Skato if (pckbd_probe(PC98KBD_DEFAULT, arg, flags)) 38842795Skato return 0; 38944635Skato if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags)) 39044635Skato return 0; 39142795Skato 39244635Skato /* return the number of found keyboards */ 39344635Skato return 1; 39442795Skato} 39542795Skato 39642795Skato/* low-level functions */ 39742795Skato 39844635Skato/* detect a keyboard */ 39942795Skatostatic int 40044635Skatopckbd_probe(int unit, void *arg, int flags) 40142795Skato{ 40242795Skato KBDC kbdc; 40342795Skato int *data = (int *)arg; 40442795Skato 40542795Skato if (unit != PC98KBD_DEFAULT) 40642795Skato return ENXIO; 40744635Skato if (KBD_IS_PROBED(&default_kbd)) 40842795Skato return 0; 40942795Skato 41044635Skato kbdc = kbdc_open(data[0]); 41142795Skato if (kbdc == NULL) 41242795Skato return ENXIO; 41342795Skato if (probe_keyboard(kbdc, flags)) { 41442795Skato if (flags & KB_CONF_FAIL_IF_NO_KBD) 41542795Skato return ENXIO; 41642795Skato } 41742795Skato return 0; 41842795Skato} 41942795Skato 42042795Skato/* reset and initialize the device */ 42142795Skatostatic int 42244635Skatopckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 42342795Skato{ 42444635Skato keyboard_t *kbd; 42544635Skato pckbd_state_t *state; 42644635Skato keymap_t *keymap; 42744635Skato accentmap_t *accmap; 42844635Skato fkeytab_t *fkeymap; 42944635Skato int fkeymap_size; 43044635Skato int *data = (int *)arg; 43142795Skato 43244635Skato if (unit != PC98KBD_DEFAULT) /* shouldn't happen */ 43344635Skato return ENXIO; 43442795Skato 43544635Skato *kbdp = kbd = &default_kbd; 43644635Skato state = &default_kbd_state; 43744635Skato if (!KBD_IS_PROBED(kbd)) { 43844635Skato keymap = &default_keymap; 43944635Skato accmap = &default_accentmap; 44044635Skato fkeymap = default_fkeytab; 44144635Skato fkeymap_size = 44244635Skato sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 44344635Skato 44444635Skato state->kbdc = kbdc_open(data[0]); 44544635Skato if (state->kbdc == NULL) 44644635Skato return ENXIO; 44744635Skato kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags, 44844635Skato data[0], IO_KBDSIZE); 44944635Skato bcopy(&key_map, keymap, sizeof(key_map)); 45044635Skato bcopy(&accent_map, accmap, sizeof(accent_map)); 45144635Skato bcopy(fkey_tab, fkeymap, 45244635Skato imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 45344635Skato kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 45444635Skato kbd->kb_data = (void *)state; 45544635Skato 45644635Skato if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */ 45744635Skato if (flags & KB_CONF_FAIL_IF_NO_KBD) 45844635Skato return ENXIO; 45944635Skato } else { 46044635Skato KBD_FOUND_DEVICE(kbd); 46144635Skato } 46244635Skato pckbd_clear_state(kbd); 46344635Skato state->ks_mode = K_XLATE; 46444635Skato KBD_PROBE_DONE(kbd); 46544635Skato } 46644635Skato if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 46742795Skato if (KBD_HAS_DEVICE(kbd) 46844635Skato && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 46942795Skato && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) 47042795Skato return ENXIO; 47144635Skato pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 47242795Skato KBD_INIT_DONE(kbd); 47342795Skato } 47442795Skato if (!KBD_IS_CONFIGURED(kbd)) { 47542795Skato if (kbd_register(kbd) < 0) 47642795Skato return ENXIO; 47742795Skato KBD_CONFIG_DONE(kbd); 47842795Skato } 47942795Skato 48042795Skato return 0; 48142795Skato} 48242795Skato 48342795Skato/* finish using this keyboard */ 48442795Skatostatic int 48542795Skatopckbd_term(keyboard_t *kbd) 48642795Skato{ 48742795Skato kbd_unregister(kbd); 48842795Skato return 0; 48942795Skato} 49042795Skato 49142795Skato/* keyboard interrupt routine */ 49242795Skatostatic int 49344635Skatopckbd_intr(keyboard_t *kbd, void *arg) 49442795Skato{ 49542795Skato int c; 49642795Skato 49742795Skato if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 49842795Skato /* let the callback function to process the input */ 49942795Skato (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 50042795Skato kbd->kb_callback.kc_arg); 50142795Skato } else { 50242795Skato /* read and discard the input; no one is waiting for input */ 50342795Skato do { 50442795Skato c = pckbd_read_char(kbd, FALSE); 50542795Skato } while (c != NOKEY); 50642795Skato } 50742795Skato return 0; 50842795Skato} 50942795Skato 51042795Skato/* test the interface to the device */ 51142795Skatostatic int 51242795Skatopckbd_test_if(keyboard_t *kbd) 51342795Skato{ 51442795Skato return 0; 51542795Skato} 51642795Skato 51742795Skato/* 51842795Skato * Enable the access to the device; until this function is called, 51942795Skato * the client cannot read from the keyboard. 52042795Skato */ 52142795Skatostatic int 52242795Skatopckbd_enable(keyboard_t *kbd) 52342795Skato{ 52442795Skato int s; 52542795Skato 52642795Skato s = spltty(); 52742795Skato KBD_ACTIVATE(kbd); 52842795Skato splx(s); 52942795Skato return 0; 53042795Skato} 53142795Skato 53242795Skato/* disallow the access to the device */ 53342795Skatostatic int 53442795Skatopckbd_disable(keyboard_t *kbd) 53542795Skato{ 53642795Skato int s; 53742795Skato 53842795Skato s = spltty(); 53942795Skato KBD_DEACTIVATE(kbd); 54042795Skato splx(s); 54142795Skato return 0; 54242795Skato} 54342795Skato 54442795Skato/* read one byte from the keyboard if it's allowed */ 54542795Skatostatic int 54642795Skatopckbd_read(keyboard_t *kbd, int wait) 54742795Skato{ 54842795Skato int c; 54942795Skato 55042795Skato if (wait) 55142795Skato c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc); 55242795Skato else 55342795Skato c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc); 55454551Skato if (c != -1) 55554551Skato ++kbd->kb_count; 55642795Skato return (KBD_IS_ACTIVE(kbd) ? c : -1); 55742795Skato} 55842795Skato 55942795Skato/* check if data is waiting */ 56042795Skatostatic int 56142795Skatopckbd_check(keyboard_t *kbd) 56242795Skato{ 56342795Skato if (!KBD_IS_ACTIVE(kbd)) 56442795Skato return FALSE; 56542795Skato return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc); 56642795Skato} 56742795Skato 56842795Skato/* read char from the keyboard */ 56942795Skatostatic u_int 57042795Skatopckbd_read_char(keyboard_t *kbd, int wait) 57142795Skato{ 57242795Skato pckbd_state_t *state; 57342795Skato u_int action; 57442795Skato int scancode; 57542795Skato int keycode; 57642795Skato 57742795Skato state = (pckbd_state_t *)kbd->kb_data; 57842795Skatonext_code: 57942795Skato /* do we have a composed char to return? */ 58042795Skato if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 58142795Skato action = state->ks_composed_char; 58242795Skato state->ks_composed_char = 0; 58342795Skato if (action > UCHAR_MAX) 58442795Skato return ERRKEY; 58542795Skato return action; 58642795Skato } 58742795Skato 58842795Skato /* see if there is something in the keyboard port */ 58942795Skato if (wait) { 59042795Skato do { 59142795Skato scancode = read_kbd_data(state->kbdc); 59242795Skato } while (scancode == -1); 59342795Skato } else { 59442795Skato scancode = read_kbd_data_no_wait(state->kbdc); 59542795Skato if (scancode == -1) 59642795Skato return NOKEY; 59742795Skato } 59854551Skato ++kbd->kb_count; 59942795Skato 60054551Skato#if 0 60154551Skato printf("pckbd_read_char(): scancode:0x%x\n", scancode); 60254551Skato#endif 60354551Skato 60442795Skato /* return the byte as is for the K_RAW mode */ 60542795Skato if (state->ks_mode == K_RAW) 60642795Skato return scancode; 60742795Skato 60842795Skato /* translate the scan code into a keycode */ 60942795Skato keycode = scancode & 0x7F; 61042795Skato switch(scancode) { 61142795Skato case 0xF3: /* GRPH (compose key) released */ 61242795Skato if (state->ks_flags & COMPOSE) { 61342795Skato state->ks_flags &= ~COMPOSE; 61442795Skato if (state->ks_composed_char > UCHAR_MAX) 61542795Skato state->ks_composed_char = 0; 61642795Skato } 61742795Skato break; 61842795Skato case 0x73: /* GRPH (compose key) pressed */ 61942795Skato if (!(state->ks_flags & COMPOSE)) { 62042795Skato state->ks_flags |= COMPOSE; 62142795Skato state->ks_composed_char = 0; 62242795Skato } 62342795Skato break; 62442795Skato } 62542795Skato 62642795Skato /* return the key code in the K_CODE mode */ 62742795Skato if (state->ks_mode == K_CODE) 62842795Skato return (keycode | (scancode & 0x80)); 62942795Skato 63042795Skato /* compose a character code */ 63142795Skato if (state->ks_flags & COMPOSE) { 63242795Skato switch (scancode) { 63342795Skato /* key pressed, process it */ 63442795Skato case 0x42: case 0x43: case 0x44: /* keypad 7,8,9 */ 63542795Skato state->ks_composed_char *= 10; 63642795Skato state->ks_composed_char += scancode - 0x3B; 63742795Skato if (state->ks_composed_char > UCHAR_MAX) 63842795Skato return ERRKEY; 63942795Skato goto next_code; 64042795Skato case 0x46: case 0x47: case 0x48: /* keypad 4,5,6 */ 64142795Skato state->ks_composed_char *= 10; 64242795Skato state->ks_composed_char += scancode - 0x42; 64342795Skato if (state->ks_composed_char > UCHAR_MAX) 64442795Skato return ERRKEY; 64542795Skato goto next_code; 64642795Skato case 0x4A: case 0x4B: case 0x4C: /* keypad 1,2,3 */ 64742795Skato state->ks_composed_char *= 10; 64842795Skato state->ks_composed_char += scancode - 0x49; 64942795Skato if (state->ks_composed_char > UCHAR_MAX) 65042795Skato return ERRKEY; 65142795Skato goto next_code; 65242795Skato case 0x4E: /* keypad 0 */ 65342795Skato state->ks_composed_char *= 10; 65442795Skato if (state->ks_composed_char > UCHAR_MAX) 65542795Skato return ERRKEY; 65642795Skato goto next_code; 65742795Skato 65842795Skato /* key released, no interest here */ 65942795Skato case 0xC2: case 0xC3: case 0xC4: /* keypad 7,8,9 */ 66042795Skato case 0xC6: case 0xC7: case 0xC8: /* keypad 4,5,6 */ 66142795Skato case 0xCA: case 0xCB: case 0xCC: /* keypad 1,2,3 */ 66242795Skato case 0xCE: /* keypad 0 */ 66342795Skato goto next_code; 66442795Skato 66542795Skato case 0x73: /* GRPH key */ 66642795Skato break; 66742795Skato 66842795Skato default: 66942795Skato if (state->ks_composed_char > 0) { 67042795Skato state->ks_flags &= ~COMPOSE; 67142795Skato state->ks_composed_char = 0; 67242795Skato return ERRKEY; 67342795Skato } 67442795Skato break; 67542795Skato } 67642795Skato } 67742795Skato 67842795Skato /* keycode to key action */ 67942795Skato action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 68042795Skato &state->ks_state, &state->ks_accents); 68142795Skato if (action == NOKEY) 68242795Skato goto next_code; 68342795Skato else 68442795Skato return action; 68542795Skato} 68642795Skato 68742795Skato/* check if char is waiting */ 68842795Skatostatic int 68942795Skatopckbd_check_char(keyboard_t *kbd) 69042795Skato{ 69142795Skato pckbd_state_t *state; 69242795Skato 69342795Skato if (!KBD_IS_ACTIVE(kbd)) 69442795Skato return FALSE; 69542795Skato state = (pckbd_state_t *)kbd->kb_data; 69642795Skato if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 69742795Skato return TRUE; 69842795Skato return kbdc_data_ready(state->kbdc); 69942795Skato} 70042795Skato 70142795Skato/* some useful control functions */ 70242795Skatostatic int 70342795Skatopckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 70442795Skato{ 70542795Skato pckbd_state_t *state = kbd->kb_data; 70642795Skato int s; 70742795Skato int i; 708162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 709162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 710162711Sru int ival; 711162711Sru#endif 71242795Skato 71342795Skato s = spltty(); 71442795Skato switch (cmd) { 71542795Skato 71642795Skato case KDGKBMODE: /* get keyboard mode */ 71742795Skato *(int *)arg = state->ks_mode; 71842795Skato break; 719162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 720162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 721162711Sru case _IO('K', 7): 722162711Sru ival = IOCPARM_IVAL(arg); 723162711Sru arg = (caddr_t)&ival; 724162711Sru /* FALLTHROUGH */ 725162711Sru#endif 72642795Skato case KDSKBMODE: /* set keyboard mode */ 72742795Skato switch (*(int *)arg) { 72842795Skato case K_XLATE: 72942795Skato if (state->ks_mode != K_XLATE) { 73042795Skato /* make lock key state and LED state match */ 73142795Skato state->ks_state &= ~LOCK_MASK; 73242795Skato state->ks_state |= KBD_LED_VAL(kbd); 73342795Skato } 734102412Scharnier /* FALLTHROUGH */ 73542795Skato case K_RAW: 73642795Skato case K_CODE: 73742795Skato if (state->ks_mode != *(int *)arg) { 73842795Skato pckbd_clear_state(kbd); 73942795Skato state->ks_mode = *(int *)arg; 74042795Skato } 74142795Skato break; 74242795Skato default: 74342795Skato splx(s); 74442795Skato return EINVAL; 74542795Skato } 74642795Skato break; 74742795Skato 74842795Skato case KDGETLED: /* get keyboard LED */ 74942795Skato *(int *)arg = KBD_LED_VAL(kbd); 75042795Skato break; 751162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 752162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 753162711Sru case _IO('K', 66): 754162711Sru ival = IOCPARM_IVAL(arg); 755162711Sru arg = (caddr_t)&ival; 756162711Sru /* FALLTHROUGH */ 757162711Sru#endif 75842795Skato case KDSETLED: /* set keyboard LED */ 75942795Skato /* NOTE: lock key state in ks_state won't be changed */ 76042795Skato if (*(int *)arg & ~LOCK_MASK) { 76142795Skato splx(s); 76242795Skato return EINVAL; 76342795Skato } 76442795Skato i = *(int *)arg; 76542795Skato /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 76642795Skato if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 76742795Skato if (i & ALKED) 76842795Skato i |= CLKED; 76942795Skato else 77042795Skato i &= ~CLKED; 77142795Skato } 77242795Skato KBD_LED_VAL(kbd) = *(int *)arg; 77342795Skato break; 77442795Skato 77542795Skato case KDGKBSTATE: /* get lock key state */ 77642795Skato *(int *)arg = state->ks_state & LOCK_MASK; 77742795Skato break; 778162711Sru#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ 779162711Sru defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 780162711Sru case _IO('K', 20): 781162711Sru ival = IOCPARM_IVAL(arg); 782162711Sru arg = (caddr_t)&ival; 783162711Sru /* FALLTHROUGH */ 784162711Sru#endif 78542795Skato case KDSKBSTATE: /* set lock key state */ 78642795Skato if (*(int *)arg & ~LOCK_MASK) { 78742795Skato splx(s); 78842795Skato return EINVAL; 78942795Skato } 79042795Skato state->ks_state &= ~LOCK_MASK; 79142795Skato state->ks_state |= *(int *)arg; 79242795Skato splx(s); 79342795Skato /* set LEDs and quit */ 79442795Skato return pckbd_ioctl(kbd, KDSETLED, arg); 79542795Skato 79644635Skato case KDSETRAD: /* set keyboard repeat rate (old interface)*/ 79742795Skato break; 79844635Skato case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 79944635Skato break; 80042795Skato 80142795Skato case PIO_KEYMAP: /* set keyboard translation table */ 802224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 80342795Skato case PIO_KEYMAPENT: /* set keyboard translation table entry */ 80442795Skato case PIO_DEADKEYMAP: /* set accent key translation table */ 80542795Skato state->ks_accents = 0; 806102412Scharnier /* FALLTHROUGH */ 80742795Skato default: 80842795Skato splx(s); 80942795Skato return genkbd_commonioctl(kbd, cmd, arg); 81042795Skato } 81142795Skato 81242795Skato splx(s); 81342795Skato return 0; 81442795Skato} 81542795Skato 81642795Skato/* lock the access to the keyboard */ 81742795Skatostatic int 81842795Skatopckbd_lock(keyboard_t *kbd, int lock) 81942795Skato{ 82042795Skato return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock); 82142795Skato} 82242795Skato 82342795Skato/* clear the internal state of the keyboard */ 82442795Skatostatic void 82542795Skatopckbd_clear_state(keyboard_t *kbd) 82642795Skato{ 82742795Skato pckbd_state_t *state; 82842795Skato 82942795Skato state = (pckbd_state_t *)kbd->kb_data; 83042795Skato state->ks_flags = 0; 83142795Skato state->ks_state &= LOCK_MASK; /* preserve locking key state */ 83242795Skato state->ks_accents = 0; 83342795Skato state->ks_composed_char = 0; 83442795Skato} 83542795Skato 83642795Skato/* save the internal state */ 83742795Skatostatic int 83842795Skatopckbd_get_state(keyboard_t *kbd, void *buf, size_t len) 83942795Skato{ 84042795Skato if (len == 0) 84142795Skato return sizeof(pckbd_state_t); 84242795Skato if (len < sizeof(pckbd_state_t)) 84342795Skato return -1; 84442795Skato bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t)); 84542795Skato return 0; 84642795Skato} 84742795Skato 84842795Skato/* set the internal state */ 84942795Skatostatic int 85042795Skatopckbd_set_state(keyboard_t *kbd, void *buf, size_t len) 85142795Skato{ 85242795Skato if (len < sizeof(pckbd_state_t)) 85342795Skato return ENOMEM; 85442795Skato if (((pckbd_state_t *)kbd->kb_data)->kbdc 85542795Skato != ((pckbd_state_t *)buf)->kbdc) 85642795Skato return ENOMEM; 85742795Skato bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t)); 85842795Skato return 0; 85942795Skato} 86042795Skato 86144635Skato/* set polling mode */ 86244635Skatostatic int 86344635Skatopckbd_poll(keyboard_t *kbd, int on) 86444635Skato{ 86544635Skato return 0; 86644635Skato} 86744635Skato 86842795Skato/* local functions */ 86942795Skato 87042795Skatostatic int 87142795Skatoprobe_keyboard(KBDC kbdc, int flags) 87242795Skato{ 87342795Skato return 0; 87442795Skato} 87542795Skato 87642795Skatostatic int 87742795Skatoinit_keyboard(KBDC kbdc, int *type, int flags) 87842795Skato{ 87942795Skato *type = KB_OTHER; 88042795Skato return 0; 88142795Skato} 88242795Skato 88342795Skato/* keyboard I/O routines */ 88442795Skato 88542795Skato/* retry count */ 88642795Skato#ifndef KBD_MAXRETRY 88742795Skato#define KBD_MAXRETRY 3 88842795Skato#endif 88942795Skato 89042795Skato/* timing parameters */ 89142795Skato#ifndef KBD_RESETDELAY 89242795Skato#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ 89342795Skato#endif 89442795Skato#ifndef KBD_MAXWAIT 89542795Skato#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ 89642795Skato#endif 89742795Skato 89842795Skato/* I/O recovery time */ 89942795Skato#define KBDC_DELAYTIME 37 90042795Skato#define KBDD_DELAYTIME 37 90142795Skato 90242795Skato/* I/O ports */ 90342795Skato#define KBD_STATUS_PORT 2 /* status port, read */ 90442795Skato#define KBD_DATA_PORT 0 /* data port, read */ 90542795Skato 90642795Skato/* status bits (KBD_STATUS_PORT) */ 90742795Skato#define KBDS_BUFFER_FULL 0x0002 90842795Skato 90942795Skato/* macros */ 91042795Skato 91142795Skato#define kbdcp(p) ((struct kbdc_softc *)(p)) 91242795Skato 91342795Skato/* local variables */ 91442795Skato 915102151Speterstatic struct kbdc_softc kbdc_softc[1] = { { 0 }, }; 91642795Skato 91742795Skato/* associate a port number with a KBDC */ 91842795Skato 91942795Skatostatic KBDC 92042795Skatokbdc_open(int port) 92142795Skato{ 92242795Skato if (port <= 0) 92342795Skato port = IO_KBD; 92442795Skato 925102151Speter /* PC-98 has only one keyboard I/F */ 926102151Speter kbdc_softc[0].port = port; 927102151Speter kbdc_softc[0].lock = FALSE; 928102151Speter return (KBDC)&kbdc_softc[0]; 92942795Skato} 93042795Skato 93142795Skato/* set/reset polling lock */ 93242795Skatostatic int 93342795Skatokbdc_lock(KBDC p, int lock) 93442795Skato{ 93542795Skato int prevlock; 93642795Skato 93742795Skato prevlock = kbdcp(p)->lock; 93842795Skato kbdcp(p)->lock = lock; 93942795Skato 94042795Skato return (prevlock != lock); 94142795Skato} 94242795Skato 94342795Skato/* check if any data is waiting to be processed */ 94442795Skatostatic int 94542795Skatokbdc_data_ready(KBDC p) 94642795Skato{ 94742795Skato return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL); 94842795Skato} 94942795Skato 95042795Skato/* wait for data from the keyboard */ 95142795Skatostatic int 95242795Skatowait_for_kbd_data(struct kbdc_softc *kbdc) 95342795Skato{ 95442795Skato /* CPU will stay inside the loop for 200msec at most */ 95542795Skato int retry = 10000; 95642795Skato int port = kbdc->port; 95742795Skato 95842795Skato while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) { 95942795Skato DELAY(KBDD_DELAYTIME); 96042795Skato DELAY(KBDC_DELAYTIME); 96142795Skato if (--retry < 0) 96242795Skato return 0; 96342795Skato } 96442795Skato DELAY(KBDD_DELAYTIME); 96542795Skato return 1; 96642795Skato} 96742795Skato 96842795Skato/* read one byte from the keyboard */ 96942795Skatostatic int 97042795Skatoread_kbd_data(KBDC p) 97142795Skato{ 97242795Skato if (!wait_for_kbd_data(kbdcp(p))) 97342795Skato return -1; /* timeout */ 97442795Skato DELAY(KBDC_DELAYTIME); 97542795Skato return inb(kbdcp(p)->port + KBD_DATA_PORT); 97642795Skato} 97742795Skato 97842795Skato/* read one byte from the keyboard, but return immediately if 97942795Skato * no data is waiting 98042795Skato */ 98142795Skatostatic int 98242795Skatoread_kbd_data_no_wait(KBDC p) 98342795Skato{ 98442795Skato if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) { 98542795Skato DELAY(KBDD_DELAYTIME); 98642795Skato return inb(kbdcp(p)->port + KBD_DATA_PORT); 98742795Skato } 98842795Skato return -1; /* no data */ 98942795Skato} 990