pckbd.c revision 117167
142805Skato/* 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: head/sys/pc98/cbus/pckbd.c 117167 2003-07-02 16:09:02Z jhb $ 2942795Skato */ 3042795Skato 3142795Skato#include "opt_kbd.h" 3242795Skato 3342795Skato#include <sys/param.h> 3442795Skato#include <sys/systm.h> 3542795Skato#include <sys/kernel.h> 3645783Skato#include <sys/module.h> 3742795Skato#include <sys/bus.h> 3845783Skato#include <machine/bus.h> 3945783Skato#include <sys/rman.h> 4067370Skato#include <sys/kbio.h> 4142795Skato 4242795Skato#include <machine/resource.h> 4342795Skato 4442795Skato#include <dev/kbd/kbdreg.h> 4542795Skato 4642795Skato#include <pc98/pc98/pc98.h> 4742795Skato 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; 13778385Snyan res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); 13878385Snyan if (res == NULL) 13978385Snyan return ENXIO; 14046759Skato BUS_SETUP_INTR(device_get_parent(dev), dev, res, INTR_TYPE_TTY, 14178385Snyan pckbd_isa_intr, kbd, &ih); 14245783Skato 14379702Snyan return 0; 14479702Snyan} 14579702Snyan 14679702Snyanstatic int 14779702Snyanpckbdresume(device_t dev) 14879702Snyan{ 14979702Snyan keyboard_t *kbd; 15079702Snyan 15179702Snyan kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, 15279702Snyan device_get_unit(dev))); 15379702Snyan if (kbd) 15479702Snyan (*kbdsw[kbd->kb_index]->clear_state)(kbd); 15579702Snyan 15645783Skato return (0); 15742795Skato} 15842795Skato 15942795Skatostatic void 16045783Skatopckbd_isa_intr(void *arg) 16142795Skato{ 16250236Skato keyboard_t *kbd = arg; 16342795Skato 16444635Skato (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 16542795Skato} 16642795Skato 16742795Skatostatic int 16844635Skatopckbd_probe_unit(int unit, int port, int irq, int flags) 16942795Skato{ 17042795Skato keyboard_switch_t *sw; 17142795Skato int args[2]; 17244635Skato int error; 17342795Skato 17442795Skato sw = kbd_get_switch(DRIVER_NAME); 17542795Skato if (sw == NULL) 17642795Skato return ENXIO; 17742795Skato 17842795Skato args[0] = port; 17942795Skato args[1] = irq; 18044635Skato error = (*sw->probe)(unit, args, flags); 18144635Skato if (error) 18244635Skato return error; 18344635Skato return 0; 18442795Skato} 18542795Skato 18642795Skatostatic int 18750236Skatopckbd_attach_unit(int unit, keyboard_t **kbd, int port, int irq, int flags) 18842795Skato{ 18942795Skato keyboard_switch_t *sw; 19044635Skato int args[2]; 19142795Skato int error; 19242795Skato 19342795Skato sw = kbd_get_switch(DRIVER_NAME); 19442795Skato if (sw == NULL) 19542795Skato return ENXIO; 19642795Skato 19742795Skato /* reset, initialize and enable the device */ 19844635Skato args[0] = port; 19944635Skato args[1] = irq; 20050236Skato *kbd = NULL; 20144635Skato error = (*sw->probe)(unit, args, flags); 20242795Skato if (error) 20344635Skato return error; 20450236Skato error = (*sw->init)(unit, kbd, args, flags); 20544635Skato if (error) 20644635Skato return error; 20750236Skato (*sw->enable)(*kbd); 20842795Skato 20942795Skato#ifdef KBD_INSTALL_CDEV 21042795Skato /* attach a virtual keyboard cdev */ 21150236Skato error = kbd_attach(*kbd); 21242795Skato if (error) 21342795Skato return error; 21442795Skato#endif /* KBD_INSTALL_CDEV */ 21542795Skato 21642795Skato /* 21742795Skato * This is a kludge to compensate for lost keyboard interrupts. 21842795Skato * A similar code used to be in syscons. See below. XXX 21942795Skato */ 22050236Skato pckbd_timeout(*kbd); 22142795Skato 22242795Skato if (bootverbose) 22350236Skato (*sw->diag)(*kbd, bootverbose); 22442795Skato 22542795Skato return 0; 22642795Skato} 22742795Skato 22842795Skatostatic void 22942795Skatopckbd_timeout(void *arg) 23042795Skato{ 23142795Skato keyboard_t *kbd; 23242795Skato int s; 23342795Skato 23442795Skato /* The following comments are extracted from syscons.c (1.287) */ 23542795Skato /* 23642795Skato * With release 2.1 of the Xaccel server, the keyboard is left 23742795Skato * hanging pretty often. Apparently an interrupt from the 23842795Skato * keyboard is lost, and I don't know why (yet). 23942795Skato * This ugly hack calls scintr if input is ready for the keyboard 24042795Skato * and conveniently hides the problem. XXX 24142795Skato */ 24242795Skato /* 24342795Skato * Try removing anything stuck in the keyboard controller; whether 24442795Skato * it's a keyboard scan code or mouse data. `scintr()' doesn't 24542795Skato * read the mouse data directly, but `kbdio' routines will, as a 24642795Skato * side effect. 24742795Skato */ 24842795Skato s = spltty(); 24942795Skato kbd = (keyboard_t *)arg; 25042795Skato if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) { 25142795Skato /* 25242795Skato * We have seen the lock flag is not set. Let's reset 25342795Skato * the flag early, otherwise the LED update routine fails 25442795Skato * which may want the lock during the interrupt routine. 25542795Skato */ 25642795Skato (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); 25742795Skato if ((*kbdsw[kbd->kb_index]->check_char)(kbd)) 25844635Skato (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); 25942795Skato } 26042795Skato splx(s); 26142795Skato timeout(pckbd_timeout, arg, hz/10); 26242795Skato} 26342795Skato 26442795Skato/* LOW-LEVEL */ 26542795Skato 266114216Skan#include <sys/limits.h> 26742795Skato 26842795Skato#define PC98KBD_DEFAULT 0 26942795Skato 27042795Skatotypedef caddr_t KBDC; 27142795Skato 27242795Skatotypedef struct pckbd_state { 27342795Skato KBDC kbdc; /* keyboard controller */ 27442795Skato int ks_mode; /* input mode (K_XLATE,K_RAW,K_CODE) */ 27542795Skato int ks_flags; /* flags */ 27642795Skato#define COMPOSE (1 << 0) 27742795Skato int ks_state; /* shift/lock key state */ 27842795Skato int ks_accents; /* accent key index (> 0) */ 27942795Skato u_int ks_composed_char; /* composed char code (> 0) */ 28042795Skato} pckbd_state_t; 28142795Skato 28242795Skato/* keyboard driver declaration */ 28342795Skatostatic int pckbd_configure(int flags); 28442795Skatostatic kbd_probe_t pckbd_probe; 28542795Skatostatic kbd_init_t pckbd_init; 28642795Skatostatic kbd_term_t pckbd_term; 28742795Skatostatic kbd_intr_t pckbd_intr; 28842795Skatostatic kbd_test_if_t pckbd_test_if; 28942795Skatostatic kbd_enable_t pckbd_enable; 29042795Skatostatic kbd_disable_t pckbd_disable; 29142795Skatostatic kbd_read_t pckbd_read; 29242795Skatostatic kbd_check_t pckbd_check; 29342795Skatostatic kbd_read_char_t pckbd_read_char; 29442795Skatostatic kbd_check_char_t pckbd_check_char; 29542795Skatostatic kbd_ioctl_t pckbd_ioctl; 29642795Skatostatic kbd_lock_t pckbd_lock; 29742795Skatostatic kbd_clear_state_t pckbd_clear_state; 29842795Skatostatic kbd_get_state_t pckbd_get_state; 29942795Skatostatic kbd_set_state_t pckbd_set_state; 30044635Skatostatic kbd_poll_mode_t pckbd_poll; 30142795Skato 30242795Skatokeyboard_switch_t pckbdsw = { 30342795Skato pckbd_probe, 30442795Skato pckbd_init, 30542795Skato pckbd_term, 30642795Skato pckbd_intr, 30742795Skato pckbd_test_if, 30842795Skato pckbd_enable, 30942795Skato pckbd_disable, 31042795Skato pckbd_read, 31142795Skato pckbd_check, 31242795Skato pckbd_read_char, 31342795Skato pckbd_check_char, 31442795Skato pckbd_ioctl, 31542795Skato pckbd_lock, 31642795Skato pckbd_clear_state, 31742795Skato pckbd_get_state, 31842795Skato pckbd_set_state, 31942795Skato genkbd_get_fkeystr, 32044635Skato pckbd_poll, 32142795Skato genkbd_diag, 32242795Skato}; 32342795Skato 32442795SkatoKEYBOARD_DRIVER(pckbd, pckbdsw, pckbd_configure); 32542795Skato 32642795Skatostruct kbdc_softc { 32742795Skato int port; /* base port address */ 32842795Skato int lock; /* FIXME: XXX not quite a semaphore... */ 32942795Skato}; 33042795Skato 33142795Skato/* local functions */ 33242795Skatostatic int probe_keyboard(KBDC kbdc, int flags); 33342795Skatostatic int init_keyboard(KBDC kbdc, int *type, int flags); 33442795Skatostatic KBDC kbdc_open(int port); 33542795Skatostatic int kbdc_lock(KBDC kbdc, int lock); 33642795Skatostatic int kbdc_data_ready(KBDC kbdc); 33742795Skatostatic int read_kbd_data(KBDC kbdc); 33842795Skatostatic int read_kbd_data_no_wait(KBDC kbdc); 33942795Skatostatic int wait_for_kbd_data(struct kbdc_softc *kbdc); 34042795Skato 34142795Skato/* local variables */ 34242795Skato 34342795Skato/* the initial key map, accent map and fkey strings */ 34442833Skato#include <dev/kbd/kbdtables.h> 34542795Skato 34642795Skato/* structures for the default keyboard */ 34742795Skatostatic keyboard_t default_kbd; 34842795Skatostatic pckbd_state_t default_kbd_state; 34942795Skatostatic keymap_t default_keymap; 35042795Skatostatic accentmap_t default_accentmap; 35142795Skatostatic fkeytab_t default_fkeytab[NUM_FKEYS]; 35242795Skato 35342795Skato/* 35442795Skato * The back door to the keyboard driver! 35542795Skato * This function is called by the console driver, via the kbdio module, 35642795Skato * to tickle keyboard drivers when the low-level console is being initialized. 35742795Skato * Almost nothing in the kernel has been initialied yet. Try to probe 35842795Skato * keyboards if possible. 35942795Skato * NOTE: because of the way the low-level conole is initialized, this routine 36042795Skato * may be called more than once!! 36142795Skato */ 36242795Skatostatic int 36342795Skatopckbd_configure(int flags) 36442795Skato{ 36542795Skato keyboard_t *kbd; 36642795Skato int arg[2]; 36744635Skato int i; 36842795Skato 36942795Skato /* XXX: a kludge to obtain the device configuration flags */ 37045783Skato if (resource_int_value(DRIVER_NAME, 0, "flags", &i) == 0) { 37145783Skato flags |= i; 37244635Skato /* if the driver is disabled, unregister the keyboard if any */ 373117167Sjhb if (resource_disabled(DRIVER_NAME, 0)) { 37444635Skato i = kbd_find_keyboard(DRIVER_NAME, PC98KBD_DEFAULT); 37544635Skato if (i >= 0) { 37644635Skato kbd = kbd_get_keyboard(i); 37744635Skato kbd_unregister(kbd); 37844635Skato kbd->kb_flags &= ~KB_REGISTERED; 37944635Skato return 0; 38044635Skato } 38144635Skato } 38244635Skato } 38342795Skato 38442795Skato /* probe the default keyboard */ 38542795Skato arg[0] = -1; 38642795Skato arg[1] = -1; 38744635Skato kbd = NULL; 38844635Skato if (pckbd_probe(PC98KBD_DEFAULT, arg, flags)) 38942795Skato return 0; 39044635Skato if (pckbd_init(PC98KBD_DEFAULT, &kbd, arg, flags)) 39144635Skato return 0; 39242795Skato 39344635Skato /* return the number of found keyboards */ 39444635Skato return 1; 39542795Skato} 39642795Skato 39742795Skato/* low-level functions */ 39842795Skato 39944635Skato/* detect a keyboard */ 40042795Skatostatic int 40144635Skatopckbd_probe(int unit, void *arg, int flags) 40242795Skato{ 40342795Skato KBDC kbdc; 40442795Skato int *data = (int *)arg; 40542795Skato 40642795Skato if (unit != PC98KBD_DEFAULT) 40742795Skato return ENXIO; 40844635Skato if (KBD_IS_PROBED(&default_kbd)) 40942795Skato return 0; 41042795Skato 41144635Skato kbdc = kbdc_open(data[0]); 41242795Skato if (kbdc == NULL) 41342795Skato return ENXIO; 41442795Skato if (probe_keyboard(kbdc, flags)) { 41542795Skato if (flags & KB_CONF_FAIL_IF_NO_KBD) 41642795Skato return ENXIO; 41742795Skato } 41842795Skato return 0; 41942795Skato} 42042795Skato 42142795Skato/* reset and initialize the device */ 42242795Skatostatic int 42344635Skatopckbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 42442795Skato{ 42544635Skato keyboard_t *kbd; 42644635Skato pckbd_state_t *state; 42744635Skato keymap_t *keymap; 42844635Skato accentmap_t *accmap; 42944635Skato fkeytab_t *fkeymap; 43044635Skato int fkeymap_size; 43144635Skato int *data = (int *)arg; 43242795Skato 43344635Skato if (unit != PC98KBD_DEFAULT) /* shouldn't happen */ 43444635Skato return ENXIO; 43542795Skato 43644635Skato *kbdp = kbd = &default_kbd; 43744635Skato state = &default_kbd_state; 43844635Skato if (!KBD_IS_PROBED(kbd)) { 43944635Skato keymap = &default_keymap; 44044635Skato accmap = &default_accentmap; 44144635Skato fkeymap = default_fkeytab; 44244635Skato fkeymap_size = 44344635Skato sizeof(default_fkeytab)/sizeof(default_fkeytab[0]); 44444635Skato 44544635Skato state->kbdc = kbdc_open(data[0]); 44644635Skato if (state->kbdc == NULL) 44744635Skato return ENXIO; 44844635Skato kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags, 44944635Skato data[0], IO_KBDSIZE); 45044635Skato bcopy(&key_map, keymap, sizeof(key_map)); 45144635Skato bcopy(&accent_map, accmap, sizeof(accent_map)); 45244635Skato bcopy(fkey_tab, fkeymap, 45344635Skato imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 45444635Skato kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 45544635Skato kbd->kb_data = (void *)state; 45644635Skato 45744635Skato if (probe_keyboard(state->kbdc, flags)) {/* shouldn't happen */ 45844635Skato if (flags & KB_CONF_FAIL_IF_NO_KBD) 45944635Skato return ENXIO; 46044635Skato } else { 46144635Skato KBD_FOUND_DEVICE(kbd); 46244635Skato } 46344635Skato pckbd_clear_state(kbd); 46444635Skato state->ks_mode = K_XLATE; 46544635Skato KBD_PROBE_DONE(kbd); 46644635Skato } 46744635Skato if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 46842795Skato if (KBD_HAS_DEVICE(kbd) 46944635Skato && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) 47042795Skato && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) 47142795Skato return ENXIO; 47244635Skato pckbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 47342795Skato KBD_INIT_DONE(kbd); 47442795Skato } 47542795Skato if (!KBD_IS_CONFIGURED(kbd)) { 47642795Skato if (kbd_register(kbd) < 0) 47742795Skato return ENXIO; 47842795Skato KBD_CONFIG_DONE(kbd); 47942795Skato } 48042795Skato 48142795Skato return 0; 48242795Skato} 48342795Skato 48442795Skato/* finish using this keyboard */ 48542795Skatostatic int 48642795Skatopckbd_term(keyboard_t *kbd) 48742795Skato{ 48842795Skato kbd_unregister(kbd); 48942795Skato return 0; 49042795Skato} 49142795Skato 49242795Skato/* keyboard interrupt routine */ 49342795Skatostatic int 49444635Skatopckbd_intr(keyboard_t *kbd, void *arg) 49542795Skato{ 49642795Skato int c; 49742795Skato 49842795Skato if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 49942795Skato /* let the callback function to process the input */ 50042795Skato (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 50142795Skato kbd->kb_callback.kc_arg); 50242795Skato } else { 50342795Skato /* read and discard the input; no one is waiting for input */ 50442795Skato do { 50542795Skato c = pckbd_read_char(kbd, FALSE); 50642795Skato } while (c != NOKEY); 50742795Skato } 50842795Skato return 0; 50942795Skato} 51042795Skato 51142795Skato/* test the interface to the device */ 51242795Skatostatic int 51342795Skatopckbd_test_if(keyboard_t *kbd) 51442795Skato{ 51542795Skato return 0; 51642795Skato} 51742795Skato 51842795Skato/* 51942795Skato * Enable the access to the device; until this function is called, 52042795Skato * the client cannot read from the keyboard. 52142795Skato */ 52242795Skatostatic int 52342795Skatopckbd_enable(keyboard_t *kbd) 52442795Skato{ 52542795Skato int s; 52642795Skato 52742795Skato s = spltty(); 52842795Skato KBD_ACTIVATE(kbd); 52942795Skato splx(s); 53042795Skato return 0; 53142795Skato} 53242795Skato 53342795Skato/* disallow the access to the device */ 53442795Skatostatic int 53542795Skatopckbd_disable(keyboard_t *kbd) 53642795Skato{ 53742795Skato int s; 53842795Skato 53942795Skato s = spltty(); 54042795Skato KBD_DEACTIVATE(kbd); 54142795Skato splx(s); 54242795Skato return 0; 54342795Skato} 54442795Skato 54542795Skato/* read one byte from the keyboard if it's allowed */ 54642795Skatostatic int 54742795Skatopckbd_read(keyboard_t *kbd, int wait) 54842795Skato{ 54942795Skato int c; 55042795Skato 55142795Skato if (wait) 55242795Skato c = read_kbd_data(((pckbd_state_t *)kbd->kb_data)->kbdc); 55342795Skato else 55442795Skato c = read_kbd_data_no_wait(((pckbd_state_t *)kbd->kb_data)->kbdc); 55554551Skato if (c != -1) 55654551Skato ++kbd->kb_count; 55742795Skato return (KBD_IS_ACTIVE(kbd) ? c : -1); 55842795Skato} 55942795Skato 56042795Skato/* check if data is waiting */ 56142795Skatostatic int 56242795Skatopckbd_check(keyboard_t *kbd) 56342795Skato{ 56442795Skato if (!KBD_IS_ACTIVE(kbd)) 56542795Skato return FALSE; 56642795Skato return kbdc_data_ready(((pckbd_state_t *)kbd->kb_data)->kbdc); 56742795Skato} 56842795Skato 56942795Skato/* read char from the keyboard */ 57042795Skatostatic u_int 57142795Skatopckbd_read_char(keyboard_t *kbd, int wait) 57242795Skato{ 57342795Skato pckbd_state_t *state; 57442795Skato u_int action; 57542795Skato int scancode; 57642795Skato int keycode; 57742795Skato 57842795Skato state = (pckbd_state_t *)kbd->kb_data; 57942795Skatonext_code: 58042795Skato /* do we have a composed char to return? */ 58142795Skato if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 58242795Skato action = state->ks_composed_char; 58342795Skato state->ks_composed_char = 0; 58442795Skato if (action > UCHAR_MAX) 58542795Skato return ERRKEY; 58642795Skato return action; 58742795Skato } 58842795Skato 58942795Skato /* see if there is something in the keyboard port */ 59042795Skato if (wait) { 59142795Skato do { 59242795Skato scancode = read_kbd_data(state->kbdc); 59342795Skato } while (scancode == -1); 59442795Skato } else { 59542795Skato scancode = read_kbd_data_no_wait(state->kbdc); 59642795Skato if (scancode == -1) 59742795Skato return NOKEY; 59842795Skato } 59954551Skato ++kbd->kb_count; 60042795Skato 60154551Skato#if 0 60254551Skato printf("pckbd_read_char(): scancode:0x%x\n", scancode); 60354551Skato#endif 60454551Skato 60542795Skato /* return the byte as is for the K_RAW mode */ 60642795Skato if (state->ks_mode == K_RAW) 60742795Skato return scancode; 60842795Skato 60942795Skato /* translate the scan code into a keycode */ 61042795Skato keycode = scancode & 0x7F; 61142795Skato switch(scancode) { 61242795Skato case 0xF3: /* GRPH (compose key) released */ 61342795Skato if (state->ks_flags & COMPOSE) { 61442795Skato state->ks_flags &= ~COMPOSE; 61542795Skato if (state->ks_composed_char > UCHAR_MAX) 61642795Skato state->ks_composed_char = 0; 61742795Skato } 61842795Skato break; 61942795Skato case 0x73: /* GRPH (compose key) pressed */ 62042795Skato if (!(state->ks_flags & COMPOSE)) { 62142795Skato state->ks_flags |= COMPOSE; 62242795Skato state->ks_composed_char = 0; 62342795Skato } 62442795Skato break; 62542795Skato } 62642795Skato 62742795Skato /* return the key code in the K_CODE mode */ 62842795Skato if (state->ks_mode == K_CODE) 62942795Skato return (keycode | (scancode & 0x80)); 63042795Skato 63142795Skato /* compose a character code */ 63242795Skato if (state->ks_flags & COMPOSE) { 63342795Skato switch (scancode) { 63442795Skato /* key pressed, process it */ 63542795Skato case 0x42: case 0x43: case 0x44: /* keypad 7,8,9 */ 63642795Skato state->ks_composed_char *= 10; 63742795Skato state->ks_composed_char += scancode - 0x3B; 63842795Skato if (state->ks_composed_char > UCHAR_MAX) 63942795Skato return ERRKEY; 64042795Skato goto next_code; 64142795Skato case 0x46: case 0x47: case 0x48: /* keypad 4,5,6 */ 64242795Skato state->ks_composed_char *= 10; 64342795Skato state->ks_composed_char += scancode - 0x42; 64442795Skato if (state->ks_composed_char > UCHAR_MAX) 64542795Skato return ERRKEY; 64642795Skato goto next_code; 64742795Skato case 0x4A: case 0x4B: case 0x4C: /* keypad 1,2,3 */ 64842795Skato state->ks_composed_char *= 10; 64942795Skato state->ks_composed_char += scancode - 0x49; 65042795Skato if (state->ks_composed_char > UCHAR_MAX) 65142795Skato return ERRKEY; 65242795Skato goto next_code; 65342795Skato case 0x4E: /* keypad 0 */ 65442795Skato state->ks_composed_char *= 10; 65542795Skato if (state->ks_composed_char > UCHAR_MAX) 65642795Skato return ERRKEY; 65742795Skato goto next_code; 65842795Skato 65942795Skato /* key released, no interest here */ 66042795Skato case 0xC2: case 0xC3: case 0xC4: /* keypad 7,8,9 */ 66142795Skato case 0xC6: case 0xC7: case 0xC8: /* keypad 4,5,6 */ 66242795Skato case 0xCA: case 0xCB: case 0xCC: /* keypad 1,2,3 */ 66342795Skato case 0xCE: /* keypad 0 */ 66442795Skato goto next_code; 66542795Skato 66642795Skato case 0x73: /* GRPH key */ 66742795Skato break; 66842795Skato 66942795Skato default: 67042795Skato if (state->ks_composed_char > 0) { 67142795Skato state->ks_flags &= ~COMPOSE; 67242795Skato state->ks_composed_char = 0; 67342795Skato return ERRKEY; 67442795Skato } 67542795Skato break; 67642795Skato } 67742795Skato } 67842795Skato 67942795Skato /* keycode to key action */ 68042795Skato action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 68142795Skato &state->ks_state, &state->ks_accents); 68242795Skato if (action == NOKEY) 68342795Skato goto next_code; 68442795Skato else 68542795Skato return action; 68642795Skato} 68742795Skato 68842795Skato/* check if char is waiting */ 68942795Skatostatic int 69042795Skatopckbd_check_char(keyboard_t *kbd) 69142795Skato{ 69242795Skato pckbd_state_t *state; 69342795Skato 69442795Skato if (!KBD_IS_ACTIVE(kbd)) 69542795Skato return FALSE; 69642795Skato state = (pckbd_state_t *)kbd->kb_data; 69742795Skato if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 69842795Skato return TRUE; 69942795Skato return kbdc_data_ready(state->kbdc); 70042795Skato} 70142795Skato 70242795Skato/* some useful control functions */ 70342795Skatostatic int 70442795Skatopckbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 70542795Skato{ 70642795Skato pckbd_state_t *state = kbd->kb_data; 70742795Skato int s; 70842795Skato int i; 70942795Skato 71042795Skato s = spltty(); 71142795Skato switch (cmd) { 71242795Skato 71342795Skato case KDGKBMODE: /* get keyboard mode */ 71442795Skato *(int *)arg = state->ks_mode; 71542795Skato break; 71642795Skato case KDSKBMODE: /* set keyboard mode */ 71742795Skato switch (*(int *)arg) { 71842795Skato case K_XLATE: 71942795Skato if (state->ks_mode != K_XLATE) { 72042795Skato /* make lock key state and LED state match */ 72142795Skato state->ks_state &= ~LOCK_MASK; 72242795Skato state->ks_state |= KBD_LED_VAL(kbd); 72342795Skato } 724102412Scharnier /* FALLTHROUGH */ 72542795Skato case K_RAW: 72642795Skato case K_CODE: 72742795Skato if (state->ks_mode != *(int *)arg) { 72842795Skato pckbd_clear_state(kbd); 72942795Skato state->ks_mode = *(int *)arg; 73042795Skato } 73142795Skato break; 73242795Skato default: 73342795Skato splx(s); 73442795Skato return EINVAL; 73542795Skato } 73642795Skato break; 73742795Skato 73842795Skato case KDGETLED: /* get keyboard LED */ 73942795Skato *(int *)arg = KBD_LED_VAL(kbd); 74042795Skato break; 74142795Skato case KDSETLED: /* set keyboard LED */ 74242795Skato /* NOTE: lock key state in ks_state won't be changed */ 74342795Skato if (*(int *)arg & ~LOCK_MASK) { 74442795Skato splx(s); 74542795Skato return EINVAL; 74642795Skato } 74742795Skato i = *(int *)arg; 74842795Skato /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 74942795Skato if (kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 75042795Skato if (i & ALKED) 75142795Skato i |= CLKED; 75242795Skato else 75342795Skato i &= ~CLKED; 75442795Skato } 75542795Skato KBD_LED_VAL(kbd) = *(int *)arg; 75642795Skato break; 75742795Skato 75842795Skato case KDGKBSTATE: /* get lock key state */ 75942795Skato *(int *)arg = state->ks_state & LOCK_MASK; 76042795Skato break; 76142795Skato case KDSKBSTATE: /* set lock key state */ 76242795Skato if (*(int *)arg & ~LOCK_MASK) { 76342795Skato splx(s); 76442795Skato return EINVAL; 76542795Skato } 76642795Skato state->ks_state &= ~LOCK_MASK; 76742795Skato state->ks_state |= *(int *)arg; 76842795Skato splx(s); 76942795Skato /* set LEDs and quit */ 77042795Skato return pckbd_ioctl(kbd, KDSETLED, arg); 77142795Skato 77244635Skato case KDSETRAD: /* set keyboard repeat rate (old interface)*/ 77342795Skato break; 77444635Skato case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 77544635Skato break; 77642795Skato 77742795Skato case PIO_KEYMAP: /* set keyboard translation table */ 77842795Skato case PIO_KEYMAPENT: /* set keyboard translation table entry */ 77942795Skato case PIO_DEADKEYMAP: /* set accent key translation table */ 78042795Skato state->ks_accents = 0; 781102412Scharnier /* FALLTHROUGH */ 78242795Skato default: 78342795Skato splx(s); 78442795Skato return genkbd_commonioctl(kbd, cmd, arg); 78542795Skato } 78642795Skato 78742795Skato splx(s); 78842795Skato return 0; 78942795Skato} 79042795Skato 79142795Skato/* lock the access to the keyboard */ 79242795Skatostatic int 79342795Skatopckbd_lock(keyboard_t *kbd, int lock) 79442795Skato{ 79542795Skato return kbdc_lock(((pckbd_state_t *)kbd->kb_data)->kbdc, lock); 79642795Skato} 79742795Skato 79842795Skato/* clear the internal state of the keyboard */ 79942795Skatostatic void 80042795Skatopckbd_clear_state(keyboard_t *kbd) 80142795Skato{ 80242795Skato pckbd_state_t *state; 80342795Skato 80442795Skato state = (pckbd_state_t *)kbd->kb_data; 80542795Skato state->ks_flags = 0; 80642795Skato state->ks_state &= LOCK_MASK; /* preserve locking key state */ 80742795Skato state->ks_accents = 0; 80842795Skato state->ks_composed_char = 0; 80942795Skato} 81042795Skato 81142795Skato/* save the internal state */ 81242795Skatostatic int 81342795Skatopckbd_get_state(keyboard_t *kbd, void *buf, size_t len) 81442795Skato{ 81542795Skato if (len == 0) 81642795Skato return sizeof(pckbd_state_t); 81742795Skato if (len < sizeof(pckbd_state_t)) 81842795Skato return -1; 81942795Skato bcopy(kbd->kb_data, buf, sizeof(pckbd_state_t)); 82042795Skato return 0; 82142795Skato} 82242795Skato 82342795Skato/* set the internal state */ 82442795Skatostatic int 82542795Skatopckbd_set_state(keyboard_t *kbd, void *buf, size_t len) 82642795Skato{ 82742795Skato if (len < sizeof(pckbd_state_t)) 82842795Skato return ENOMEM; 82942795Skato if (((pckbd_state_t *)kbd->kb_data)->kbdc 83042795Skato != ((pckbd_state_t *)buf)->kbdc) 83142795Skato return ENOMEM; 83242795Skato bcopy(buf, kbd->kb_data, sizeof(pckbd_state_t)); 83342795Skato return 0; 83442795Skato} 83542795Skato 83644635Skato/* set polling mode */ 83744635Skatostatic int 83844635Skatopckbd_poll(keyboard_t *kbd, int on) 83944635Skato{ 84044635Skato return 0; 84144635Skato} 84244635Skato 84342795Skato/* local functions */ 84442795Skato 84542795Skatostatic int 84642795Skatoprobe_keyboard(KBDC kbdc, int flags) 84742795Skato{ 84842795Skato return 0; 84942795Skato} 85042795Skato 85142795Skatostatic int 85242795Skatoinit_keyboard(KBDC kbdc, int *type, int flags) 85342795Skato{ 85442795Skato *type = KB_OTHER; 85542795Skato return 0; 85642795Skato} 85742795Skato 85842795Skato/* keyboard I/O routines */ 85942795Skato 86042795Skato/* retry count */ 86142795Skato#ifndef KBD_MAXRETRY 86242795Skato#define KBD_MAXRETRY 3 86342795Skato#endif 86442795Skato 86542795Skato/* timing parameters */ 86642795Skato#ifndef KBD_RESETDELAY 86742795Skato#define KBD_RESETDELAY 200 /* wait 200msec after kbd/mouse reset */ 86842795Skato#endif 86942795Skato#ifndef KBD_MAXWAIT 87042795Skato#define KBD_MAXWAIT 5 /* wait 5 times at most after reset */ 87142795Skato#endif 87242795Skato 87342795Skato/* I/O recovery time */ 87442795Skato#define KBDC_DELAYTIME 37 87542795Skato#define KBDD_DELAYTIME 37 87642795Skato 87742795Skato/* I/O ports */ 87842795Skato#define KBD_STATUS_PORT 2 /* status port, read */ 87942795Skato#define KBD_DATA_PORT 0 /* data port, read */ 88042795Skato 88142795Skato/* status bits (KBD_STATUS_PORT) */ 88242795Skato#define KBDS_BUFFER_FULL 0x0002 88342795Skato 88442795Skato/* macros */ 88542795Skato 88642795Skato#define kbdcp(p) ((struct kbdc_softc *)(p)) 88742795Skato 88842795Skato/* local variables */ 88942795Skato 890102151Speterstatic struct kbdc_softc kbdc_softc[1] = { { 0 }, }; 89142795Skato 89242795Skato/* associate a port number with a KBDC */ 89342795Skato 89442795Skatostatic KBDC 89542795Skatokbdc_open(int port) 89642795Skato{ 89742795Skato if (port <= 0) 89842795Skato port = IO_KBD; 89942795Skato 900102151Speter /* PC-98 has only one keyboard I/F */ 901102151Speter kbdc_softc[0].port = port; 902102151Speter kbdc_softc[0].lock = FALSE; 903102151Speter return (KBDC)&kbdc_softc[0]; 90442795Skato} 90542795Skato 90642795Skato/* set/reset polling lock */ 90742795Skatostatic int 90842795Skatokbdc_lock(KBDC p, int lock) 90942795Skato{ 91042795Skato int prevlock; 91142795Skato 91242795Skato prevlock = kbdcp(p)->lock; 91342795Skato kbdcp(p)->lock = lock; 91442795Skato 91542795Skato return (prevlock != lock); 91642795Skato} 91742795Skato 91842795Skato/* check if any data is waiting to be processed */ 91942795Skatostatic int 92042795Skatokbdc_data_ready(KBDC p) 92142795Skato{ 92242795Skato return (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL); 92342795Skato} 92442795Skato 92542795Skato/* wait for data from the keyboard */ 92642795Skatostatic int 92742795Skatowait_for_kbd_data(struct kbdc_softc *kbdc) 92842795Skato{ 92942795Skato /* CPU will stay inside the loop for 200msec at most */ 93042795Skato int retry = 10000; 93142795Skato int port = kbdc->port; 93242795Skato 93342795Skato while (!(inb(port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL)) { 93442795Skato DELAY(KBDD_DELAYTIME); 93542795Skato DELAY(KBDC_DELAYTIME); 93642795Skato if (--retry < 0) 93742795Skato return 0; 93842795Skato } 93942795Skato DELAY(KBDD_DELAYTIME); 94042795Skato return 1; 94142795Skato} 94242795Skato 94342795Skato/* read one byte from the keyboard */ 94442795Skatostatic int 94542795Skatoread_kbd_data(KBDC p) 94642795Skato{ 94742795Skato if (!wait_for_kbd_data(kbdcp(p))) 94842795Skato return -1; /* timeout */ 94942795Skato DELAY(KBDC_DELAYTIME); 95042795Skato return inb(kbdcp(p)->port + KBD_DATA_PORT); 95142795Skato} 95242795Skato 95342795Skato/* read one byte from the keyboard, but return immediately if 95442795Skato * no data is waiting 95542795Skato */ 95642795Skatostatic int 95742795Skatoread_kbd_data_no_wait(KBDC p) 95842795Skato{ 95942795Skato if (inb(kbdcp(p)->port + KBD_STATUS_PORT) & KBDS_BUFFER_FULL) { 96042795Skato DELAY(KBDD_DELAYTIME); 96142795Skato return inb(kbdcp(p)->port + KBD_DATA_PORT); 96242795Skato } 96342795Skato return -1; /* no data */ 96442795Skato} 965