Submit #3206 ยป psm_2_FBSD12_delay_hopefully_fixed.patch
| sys/dev/misc/kbd/atkbd.c | ||
|---|---|---|
|
* NOTE: All locks are handled by the kbd wrappers.
|
||
|
*/
|
||
|
#include "opt_kbd.h"
|
||
|
#include "opt_atkbd.h"
|
||
|
#include "opt_evdev.h"
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/malloc.h>
|
||
|
#include <sys/systm.h>
|
||
|
#include <sys/kernel.h>
|
||
|
#include <sys/bus.h>
|
||
|
#include <sys/proc.h>
|
||
|
#include <sys/malloc.h>
|
||
| ... | ... | |
|
#include <bus/isa/isareg.h>
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
#include <dev/misc/evdev/evdev.h>
|
||
|
#include <dev/misc/evdev/input.h>
|
||
|
#endif
|
||
|
static timeout_t atkbd_timeout;
|
||
|
#if 0
|
||
| ... | ... | |
|
keyboard_t *kbd;
|
||
|
/*
|
||
|
* The original text of the following comments are extracted
|
||
|
* The original text of the following comments are extracted
|
||
|
* from syscons.c (1.287)
|
||
|
*
|
||
|
*
|
||
|
* With release 2.1 of the Xaccel server, the keyboard is left
|
||
|
* hanging pretty often. Apparently an interrupt from the
|
||
|
* keyboard is lost, and I don't know why (yet).
|
||
| ... | ... | |
|
*
|
||
|
* Try removing anything stuck in the keyboard controller; whether
|
||
|
* it's a keyboard scan code or mouse data. The low-level
|
||
|
* interrupt routine doesn't read the mouse data directly,
|
||
|
* interrupt routine doesn't read the mouse data directly,
|
||
|
* but the keyboard controller driver will, as a side effect.
|
||
|
*/
|
||
|
/*
|
||
| ... | ... | |
|
int ks_accents; /* accent key index (> 0) */
|
||
|
u_int ks_composed_char; /* composed char code (> 0) */
|
||
|
u_char ks_prefix; /* AT scan code prefix */
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
struct evdev_dev *ks_evdev;
|
||
|
int ks_evdev_state;
|
||
|
#endif
|
||
|
} atkbd_state_t;
|
||
|
#define HAS_QUIRK(p, q) (((atkbdc_softc_t *)(p))->quirks & q)
|
||
|
#define ALLOW_DISABLE_KBD(kbdc) !HAS_QUIRK(kbdc, KBDC_QUIRK_KEEP_ACTIVATED)
|
||
|
#define DEFAULT_DELAY 0x1 /* 500ms */
|
||
|
#define DEFAULT_RATE 0x10 /* 14Hz */
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
#define PS2_KEYBOARD_VENDOR 1
|
||
|
#define PS2_KEYBOARD_PRODUCT 1
|
||
|
#endif
|
||
|
/* keyboard driver declaration */
|
||
|
static int atkbd_configure(int flags);
|
||
| ... | ... | |
|
static int typematic_delay(int delay);
|
||
|
static int typematic_rate(int rate);
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
static evdev_event_t atkbd_ev_event;
|
||
|
static const struct evdev_methods atkbd_evdev_methods = {
|
||
|
.ev_event = atkbd_ev_event,
|
||
|
};
|
||
|
#endif
|
||
|
/* local variables */
|
||
|
/* the initial key map, accent map and fkey strings */
|
||
| ... | ... | |
|
static accentmap_t default_accentmap;
|
||
|
static fkeytab_t default_fkeytab[NUM_FKEYS];
|
||
|
/*
|
||
|
/*
|
||
|
* The back door to the keyboard driver!
|
||
|
* This function is called by the console driver, via the kbdio module,
|
||
|
* to tickle keyboard drivers when the low-level console is being initialized.
|
||
| ... | ... | |
|
* is disabled, unregister the keyboard if any.
|
||
|
*/
|
||
|
if (atkbdc_configure() != 0 ||
|
||
|
resource_disabled("atkbd", ATKBD_DEFAULT)) {
|
||
|
resource_disabled("atkbd", ATKBD_DEFAULT)) {
|
||
|
i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT);
|
||
|
if (i >= 0) {
|
||
|
kbd = kbd_get_keyboard(i);
|
||
|
KBD_ALWAYS_LOCK(kbd);
|
||
|
kbd_unregister(kbd);
|
||
|
kbd = NULL; /* huh? */
|
||
|
}
|
||
|
kbd->kb_flags &= ~KB_REGISTERED;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* XXX: a kludge to obtain the device configuration flags */
|
||
|
if (resource_int_value("atkbd", ATKBD_DEFAULT, "flags", &i) == 0)
|
||
|
flags |= i;
|
||
| ... | ... | |
|
fkeytab_t *fkeymap;
|
||
|
int fkeymap_size;
|
||
|
int delay[2];
|
||
|
int *data = (int *)arg; /* data[0]: controller, data[1]: irq */
|
||
|
int *data = (int *)arg; /* data[0]: controller, data[1]: irq */
|
||
|
int needfree = 0;
|
||
|
int error = 0;
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
struct evdev_dev *evdev;
|
||
|
char phys_loc[8];
|
||
|
#endif
|
||
|
/* XXX */
|
||
|
if (unit == ATKBD_DEFAULT) {
|
||
| ... | ... | |
|
accmap = &default_accentmap;
|
||
|
fkeymap = default_fkeytab;
|
||
|
fkeymap_size = NELEM(default_fkeytab);
|
||
|
needfree = 0;
|
||
|
} else if (*kbdp == NULL) {
|
||
|
*kbdp = kbd = kmalloc(sizeof(*kbd), M_DEVBUF, M_WAITOK|M_ZERO);
|
||
|
state = kmalloc(sizeof(*state), M_DEVBUF, M_WAITOK|M_ZERO);
|
||
| ... | ... | |
|
accmap = kmalloc(sizeof(accent_map), M_DEVBUF, M_WAITOK);
|
||
|
fkeymap = kmalloc(sizeof(fkey_tab), M_DEVBUF, M_WAITOK);
|
||
|
fkeymap_size = NELEM(fkey_tab);
|
||
|
needfree = 1;
|
||
|
if((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
|
||
|
(accmap == NULL) || (fkeymap == NULL)){
|
||
|
error = ENOMEM;
|
||
|
goto bad;
|
||
|
}
|
||
|
} else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
|
||
|
return 0;
|
||
|
} else {
|
||
| ... | ... | |
|
accmap = kbd->kb_accentmap;
|
||
|
fkeymap = kbd->kb_fkeytab;
|
||
|
fkeymap_size = kbd->kb_fkeytab_size;
|
||
|
needfree = 0;
|
||
|
}
|
||
|
if (!KBD_IS_PROBED(kbd)) {
|
||
|
state->kbdc = atkbdc_open(data[0]);
|
||
|
if (state->kbdc == NULL) {
|
||
|
return ENXIO;
|
||
|
error = ENXIO;
|
||
|
goto bad;
|
||
|
}
|
||
|
kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags,
|
||
|
KB_PRI_ATKBD, 0, 0);
|
||
| ... | ... | |
|
imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
|
||
|
kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
|
||
|
kbd->kb_data = (void *)state;
|
||
|
|
||
|
if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */
|
||
|
if (flags & KB_CONF_FAIL_IF_NO_KBD) {
|
||
|
return ENXIO;
|
||
| ... | ... | |
|
}
|
||
|
atkbd_clear_state(kbd);
|
||
|
state->ks_mode = K_XLATE;
|
||
|
/*
|
||
|
/*
|
||
|
* FIXME: set the initial value for lock keys in ks_state
|
||
|
* according to the BIOS data?
|
||
|
*/
|
||
| ... | ... | |
|
if (!KBD_HAS_DEVICE(kbd)
|
||
|
&& init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config)
|
||
|
&& (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) {
|
||
|
return ENXIO;
|
||
|
kbd_unregister(kbd);
|
||
|
error = ENXIO;
|
||
|
goto bad;
|
||
|
}
|
||
|
atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
|
||
|
get_typematic(kbd);
|
||
|
delay[0] = kbd->kb_delay1;
|
||
|
delay[1] = kbd->kb_delay2;
|
||
|
atkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
/* register as evdev provider on first init */
|
||
|
if (state->ks_evdev == NULL) {
|
||
|
ksnprintf(phys_loc, sizeof(phys_loc), "atkbd%d", unit);
|
||
|
evdev = evdev_alloc();
|
||
|
evdev_set_name(evdev, "AT keyboard");
|
||
|
evdev_set_phys(evdev, phys_loc);
|
||
|
evdev_set_id(evdev, BUS_I8042, PS2_KEYBOARD_VENDOR,
|
||
|
PS2_KEYBOARD_PRODUCT, 0);
|
||
|
evdev_set_methods(evdev, kbd, &atkbd_evdev_methods);
|
||
|
evdev_support_event(evdev, EV_SYN);
|
||
|
evdev_support_event(evdev, EV_KEY);
|
||
|
evdev_support_event(evdev, EV_LED);
|
||
|
evdev_support_event(evdev, EV_REP);
|
||
|
evdev_support_all_known_keys(evdev);
|
||
|
evdev_support_led(evdev, LED_NUML);
|
||
|
evdev_support_led(evdev, LED_CAPSL);
|
||
|
evdev_support_led(evdev, LED_SCROLLL);
|
||
|
/* NOTE: in freebsd, this depends on their Giant mutex lock,
|
||
|
* discuss with the others which locking would be best here */
|
||
|
if (evdev_register(evdev))
|
||
|
evdev_free(evdev);
|
||
|
else
|
||
|
state->ks_evdev = evdev;
|
||
|
state->ks_evdev_state = 0;
|
||
|
}
|
||
|
#endif
|
||
|
KBD_FOUND_DEVICE(kbd);
|
||
|
KBD_INIT_DONE(kbd);
|
||
|
}
|
||
|
if (!KBD_IS_CONFIGURED(kbd)) {
|
||
|
if (kbd_register(kbd) < 0) {
|
||
|
return ENXIO;
|
||
|
error = ENXIO;
|
||
|
goto bad;
|
||
|
}
|
||
|
KBD_CONFIG_DONE(kbd);
|
||
|
}
|
||
|
return 0;
|
||
|
bad:
|
||
|
if(needfree) {
|
||
|
if (state != NULL)
|
||
|
kfree(state, M_DEVBUF);
|
||
|
if (keymap != NULL)
|
||
|
kfree(keymap, M_DEVBUF);
|
||
|
if (accmap != NULL)
|
||
|
kfree(accmap, M_DEVBUF);
|
||
|
if (fkeymap != NULL)
|
||
|
kfree(fkeymap, M_DEVBUF);
|
||
|
if (kbd != NULL) {
|
||
|
kfree(kbd, M_DEVBUF);
|
||
|
*kbdp = NULL; /* insure ref doesn't leak to caller */
|
||
|
}
|
||
|
}
|
||
|
return error;
|
||
|
}
|
||
|
/* finish using this keyboard */
|
||
|
static int
|
||
|
atkbd_term(keyboard_t *kbd)
|
||
|
{
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
atkbd_state_t *state = (atkbd_state_t *)kbd->kb_data;
|
||
|
if(state->ks_evdev) {
|
||
|
evdev_free(state->ks_evdev);
|
||
|
state->ks_evdev = NULL;
|
||
|
state->ks_evdev_state = 0;
|
||
|
}
|
||
|
#endif
|
||
|
kbd_unregister(kbd);
|
||
|
return 0;
|
||
|
}
|
||
| ... | ... | |
|
return error;
|
||
|
}
|
||
|
/*
|
||
|
/*
|
||
|
* Enable the access to the device; until this function is called,
|
||
|
* the client cannot read from the keyboard.
|
||
|
*/
|
||
| ... | ... | |
|
#if KBDIO_DEBUG >= 10
|
||
|
kprintf("atkbd_read_char(): scancode:0x%x\n", scancode);
|
||
|
#endif
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
/* push evdev event */
|
||
|
if (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD && state->ks_evdev != NULL) {
|
||
|
keycode = evdev_scancode2key(&state->ks_evdev_state,
|
||
|
scancode);
|
||
|
if (keycode != KEY_RESERVED) {
|
||
|
evdev_push_event(state->ks_evdev, EV_KEY,
|
||
|
(uint16_t)keycode, scancode & 0x80 ? 0 : 1);
|
||
|
evdev_sync(state->ks_evdev);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
/* return the byte as is for the K_RAW mode */
|
||
| ... | ... | |
|
goto next_code;
|
||
|
}
|
||
|
break;
|
||
|
case 0xE0: /* 0xE0 prefix */
|
||
|
case 0xE0: /* 0xE0 prefix */
|
||
|
state->ks_prefix = 0;
|
||
|
switch (keycode) {
|
||
|
case 0x1C: /* right enter key */
|
||
| ... | ... | |
|
}
|
||
|
break;
|
||
|
case 0xE1: /* 0xE1 prefix */
|
||
|
/*
|
||
|
/*
|
||
|
* The pause/break key on the 101 keyboard produces:
|
||
|
* E1-1D-45 E1-9D-C5
|
||
|
* Ctrl-pause/break produces:
|
||
| ... | ... | |
|
atkbd_check_char(keyboard_t *kbd)
|
||
|
{
|
||
|
atkbd_state_t *state;
|
||
|
int ret;
|
||
|
if (!KBD_IS_ACTIVE(kbd)) {
|
||
|
return FALSE;
|
||
| ... | ... | |
|
if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
ret = kbdc_data_ready(state->kbdc);
|
||
|
return ret;
|
||
|
return kbdc_data_ready(state->kbdc);
|
||
|
}
|
||
|
/* some useful control functions */
|
||
| ... | ... | |
|
return error;
|
||
|
}
|
||
|
}
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
/* push LED states to evdev */
|
||
|
if (state->ks_evdev != NULL &&
|
||
|
evdev_rcpt_mask & EVDEV_RCPT_HW_KBD)
|
||
|
evdev_push_leds(state->ks_evdev, *(int *)arg);
|
||
|
#endif
|
||
|
KBD_LED_VAL(kbd) = *(int *)arg;
|
||
|
break;
|
||
| ... | ... | |
|
if (error == 0) {
|
||
|
kbd->kb_delay1 = typematic_delay(i);
|
||
|
kbd->kb_delay2 = typematic_rate(i);
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
if (state->ks_evdev != NULL &&
|
||
|
evdev_rcpt_mask & EVDEV_RCPT_HW_KBD)
|
||
|
evdev_push_repeats(state->ks_evdev, kbd);
|
||
|
#endif
|
||
|
}
|
||
|
return error;
|
||
| ... | ... | |
|
return 0;
|
||
|
}
|
||
|
#ifdef EVDEV_SUPPORT
|
||
|
static void
|
||
|
atkbd_ev_event(struct evdev_dev *evdev, void *softc, uint16_t type, uint16_t code,
|
||
|
int32_t value)
|
||
|
{
|
||
|
keyboard_t *kbd = (keyboard_t *)softc;
|
||
|
if (evdev_rcpt_mask & EVDEV_RCPT_HW_KBD &&
|
||
|
(type == EV_LED || type == EV_REP)) {
|
||
|
/*
|
||
|
* NOTE: the current data writing part of kbd_ev_event() are its calls to kbd_ioctl()
|
||
|
* kbd_ioctl() performs a lockmgr lock per the KBD_LOCK macro,
|
||
|
* so unlike FreeBSD we don't lock here.
|
||
|
*
|
||
|
* Should the data writes in kbd_ev_event(), which is a completely FreeBSD ported
|
||
|
* function, ever change to encompass things outside of kbd_ioctl,
|
||
|
* then this needs to be redesigned or rethought, possibly by:
|
||
|
*
|
||
|
* setting a lockmgr(&kbd->kb_lock, LK_EXCLUSIVE)
|
||
|
* saving the KB_POLLING flag of kbd->kb_flags
|
||
|
* setting it
|
||
|
* doing our stuff in kbd_ev_event()
|
||
|
* and restoring the original KB_POLLING FLAG afterwards
|
||
|
* releasing the lockmgr() held lock
|
||
|
*
|
||
|
* KBD_LOCK defined at sys/dev/misc/kbd/kbdreg.h:137
|
||
|
* and works by checking if KB_POLLING is not set.
|
||
|
* This would obviously be quite a hack, if it were needed.
|
||
|
* Note by htse (harald.brinkhof@gmail.com).
|
||
|
*/
|
||
|
#if 0
|
||
|
if(!lockmgr(&kbd->kb_lock, LK_EXCLUSIVE)) {
|
||
|
/* save original flag */
|
||
|
int orig_is_polled = KBD_IS_POLLED(kbd);
|
||
|
/* set state to polling */
|
||
|
KBD_POLL(kbd);
|
||
|
#endif
|
||
|
kbd_ev_event(kbd, type, code, value);
|
||
|
#if 0
|
||
|
/* restore original state if not polling */
|
||
|
if(orig_is_polled == 0)
|
||
|
KBD_UNPOLL(kbd);
|
||
|
lockmgr(&kbd->kb_lock, LK_RELEASE);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
/* local functions */
|
||
|
static int
|
||
| ... | ... | |
|
/* enable the keyboard port and intr. */
|
||
|
if (setup_kbd_port(kbdc, TRUE, TRUE)) {
|
||
|
/*
|
||
|
* CONTROLLER ERROR
|
||
|
* This is serious; the keyboard intr is left disabled!
|
||
|
* CONTROLLER ERROR
|
||
|
* This is serious; the keyboard intr is left disabled!
|
||
|
*/
|
||
|
return ENXIO;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
| ... | ... | |
|
probe_keyboard(KBDC kbdc, int flags)
|
||
|
{
|
||
|
/*
|
||
|
* Don't try to print anything in this function. The low-level
|
||
|
* Don't try to print anything in this function. The low-level
|
||
|
* console may not have been initialized yet...
|
||
|
*/
|
||
|
int err;
|
||
|
int c;
|
||
|
int m;
|
||
|
if (!kbdc_lock(kbdc, TRUE)) {
|
||
|
/* driver error? */
|
||
| ... | ... | |
|
empty_both_buffers(kbdc, 100);
|
||
|
/* save the current keyboard controller command byte */
|
||
|
m = kbdc_get_device_mask(kbdc) & ~KBD_KBD_CONTROL_BITS;
|
||
|
c = get_controller_command_byte(kbdc);
|
||
|
if (c == -1) {
|
||
|
/* CONTROLLER ERROR */
|
||
|
kbdc_set_device_mask(kbdc, m);
|
||
|
kbdc_lock(kbdc, FALSE);
|
||
|
return ENXIO;
|
||
|
}
|
||
|
/*
|
||
|
/*
|
||
|
* The keyboard may have been screwed up by the boot block.
|
||
|
* We may just be able to recover from error by testing the controller
|
||
|
* and the keyboard port. The controller command byte needs to be
|
||
|
* saved before this recovery operation, as some controllers seem
|
||
|
* saved before this recovery operation, as some controllers seem
|
||
|
* to set the command byte to particular values.
|
||
|
*/
|
||
|
test_controller(kbdc);
|
||
|
test_kbd_port(kbdc);
|
||
|
if (!(flags & KB_CONF_NO_PROBE_TEST))
|
||
|
test_kbd_port(kbdc);
|
||
|
err = get_kbd_echo(kbdc);
|
||
| ... | ... | |
|
* to the system later. It is NOT recommended to hot-plug
|
||
|
* the AT keyboard, but many people do so...
|
||
|
*/
|
||
|
kbdc_set_device_mask(kbdc, m | KBD_KBD_CONTROL_BITS);
|
||
|
setup_kbd_port(kbdc, TRUE, TRUE);
|
||
|
#if 0
|
||
|
if (err) {
|
||
| ... | ... | |
|
#endif
|
||
|
kbdc_lock(kbdc, FALSE);
|
||
|
return err;
|
||
|
return (HAS_QUIRK(kbdc, KBDC_QUIRK_IGNORE_PROBE_RESULT)) ? 0 : err;
|
||
|
}
|
||
|
static int
|
||
| ... | ... | |
|
return EIO;
|
||
|
}
|
||
|
/*
|
||
|
* Check if we have an XT keyboard before we attempt to reset it.
|
||
|
* The procedure assumes that the keyboard and the controller have
|
||
|
* been set up properly by BIOS and have not been messed up
|
||
|
/*
|
||
|
* Check if we have an XT keyboard before we attempt to reset it.
|
||
|
* The procedure assumes that the keyboard and the controller have
|
||
|
* been set up properly by BIOS and have not been messed up
|
||
|
* during the boot process.
|
||
|
*/
|
||
|
codeset = -1;
|
||
| ... | ... | |
|
else if ((c & KBD_TRANSLATION) == 0) {
|
||
|
/* SET_SCANCODE_SET is not always supported; ignore error */
|
||
|
if (send_kbd_command_and_data(kbdc, KBDC_SET_SCANCODE_SET, 0)
|
||
|
== KBD_ACK)
|
||
|
== KBD_ACK)
|
||
|
codeset = read_kbd_data(kbdc);
|
||
|
}
|
||
|
#endif /* KBD_DETECT_XT_KEYBOARD */
|
||
|
if (bootverbose)
|
||
|
kprintf("atkbd: scancode set %d\n", codeset);
|
||
|
|
||
|
/*
|
||
|
* Get the keyboard id.
|
||
|
*/
|
||
| ... | ... | |
|
c &= ~KBD_TRANSLATION;
|
||
|
} else {
|
||
|
/*
|
||
|
* KEYBOARD ERROR
|
||
|
* KEYBOARD ERROR
|
||
|
* The XT kbd isn't usable unless the proper scan
|
||
|
* code set is selected.
|
||
|
* code set is selected.
|
||
|
*/
|
||
|
set_controller_command_byte(kbdc,
|
||
|
KBD_KBD_CONTROL_BITS, c);
|
||
| ... | ... | |
|
}
|
||
|
/* enable the keyboard port and intr. */
|
||
|
if (!set_controller_command_byte(kbdc,
|
||
|
if (!set_controller_command_byte(kbdc,
|
||
|
KBD_KBD_CONTROL_BITS | KBD_TRANSLATION |
|
||
|
KBD_OVERRIDE_KBD_LOCK | mux_mask,
|
||
|
(c & (KBD_TRANSLATION | KBD_OVERRIDE_KBD_LOCK))
|
||
|
| KBD_ENABLE_KBD_PORT | KBD_ENABLE_KBD_INT | mux_val)) {
|
||
|
/*
|
||
|
* CONTROLLER ERROR
|
||
|
* CONTROLLER ERROR
|
||
|
* This is serious; we are left with the disabled
|
||
|
* keyboard intr.
|
||
|
* keyboard intr.
|
||
|
*/
|
||
|
set_controller_command_byte(kbdc,
|
||
|
KBD_KBD_CONTROL_BITS | KBD_TRANSLATION |
|
||
| ... | ... | |
|
static int
|
||
|
write_kbd(KBDC kbdc, int command, int data)
|
||
|
{
|
||
|
/* prevent the timeout routine from polling the keyboard */
|
||
|
if (!kbdc_lock(kbdc, TRUE))
|
||
|
return EBUSY;
|
||
|
/* prevent the timeout routine from polling the keyboard */
|
||
|
if (!kbdc_lock(kbdc, TRUE))
|
||
|
return EBUSY;
|
||
|
/* disable the keyboard and mouse interrupt */
|
||
|
crit_enter();
|
||
|
/* disable the keyboard and mouse interrupt */
|
||
|
crit_enter();
|
||
|
#if 0
|
||
|
/*
|
||
|
* XXX NOTE: We can't just disable the KBD port any more, even
|
||
|
* temporarily, without blowing up some BIOS emulations
|
||
|
* if not followed by a full reset.
|
||
|
*/
|
||
|
c = get_controller_command_byte(kbdc);
|
||
|
if ((c == -1) ||
|
||
|
!set_controller_command_byte(kbdc,
|
||
|
/*
|
||
|
* XXX NOTE: We can't just disable the KBD port any more, even
|
||
|
* temporarily, without blowing up some BIOS emulations
|
||
|
* if not followed by a full reset.
|
||
|
*/
|
||
|
c = get_controller_command_byte(kbdc);
|
||
|
if ((c == -1) ||
|
||
|
!set_controller_command_byte(kbdc,
|
||
|
KBD_KBD_CONTROL_BITS,
|
||
|
KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT)) {
|
||
|
/* CONTROLLER ERROR */
|
||
|
kbdc_lock(kbdc, FALSE);
|
||
|
/* CONTROLLER ERROR */
|
||
|
kbdc_lock(kbdc, FALSE);
|
||
|
crit_exit();
|
||
|
return EIO;
|
||
|
}
|
||
|
/*
|
||
|
* Now that the keyboard controller is told not to generate
|
||
|
* the keyboard and mouse interrupts, call `splx()' to allow
|
||
|
* the other tty interrupts. The clock interrupt may also occur,
|
||
|
* but the timeout routine (`scrn_timer()') will be blocked
|
||
|
* by the lock flag set via `kbdc_lock()'
|
||
|
*/
|
||
|
crit_exit();
|
||
|
return EIO;
|
||
|
}
|
||
|
/*
|
||
|
* Now that the keyboard controller is told not to generate
|
||
|
* the keyboard and mouse interrupts, call `splx()' to allow
|
||
|
* the other tty interrupts. The clock interrupt may also occur,
|
||
|
* but the timeout routine (`scrn_timer()') will be blocked
|
||
|
* by the lock flag set via `kbdc_lock()'
|
||
|
*/
|
||
|
crit_exit();
|
||
|
#endif
|
||
|
if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK)
|
||
|
send_kbd_command(kbdc, KBDC_ENABLE_KBD);
|
||
|
if (send_kbd_command_and_data(kbdc, command, data) != KBD_ACK)
|
||
|
send_kbd_command(kbdc, KBDC_ENABLE_KBD);
|
||
|
#if 0
|
||
|
/* restore the interrupts */
|
||
|
if (!set_controller_command_byte(kbdc, KBD_KBD_CONTROL_BITS, c)) {
|
||
|
/* CONTROLLER ERROR */
|
||
|
}
|
||
|
/* restore the interrupts */
|
||
|
if (!set_controller_command_byte(kbdc, KBD_KBD_CONTROL_BITS, c)) {
|
||
|
/* CONTROLLER ERROR */
|
||
|
}
|
||
|
#else
|
||
|
crit_exit();
|
||
|
crit_exit();
|
||
|
#endif
|
||
|
kbdc_lock(kbdc, FALSE);
|
||
|
kbdc_lock(kbdc, FALSE);
|
||
|
return 0;
|
||
|
return 0;
|
||
|
}
|
||
|
static int
|
||
| sys/dev/misc/kbd/atkbdc.c | ||
|---|---|---|
|
static int wait_for_aux_data(atkbdc_softc_t *kbdc);
|
||
|
static int wait_for_aux_ack(atkbdc_softc_t *kbdc);
|
||
|
struct atkbdc_quirks {
|
||
|
const char* bios_vendor;
|
||
|
const char* maker;
|
||
|
const char* product;
|
||
|
int quirk;
|
||
|
};
|
||
|
static struct atkbdc_quirks quirks[] = {
|
||
|
{"coreboot", NULL, NULL,
|
||
|
KBDC_QUIRK_KEEP_ACTIVATED | KBDC_QUIRK_IGNORE_PROBE_RESULT |
|
||
|
KBDC_QUIRK_RESET_AFTER_PROBE | KBDC_QUIRK_SETLEDS_ON_INIT},
|
||
|
{NULL, NULL, NULL, 0}
|
||
|
};
|
||
|
#define QUIRK_STR_MATCH(s1, s2) (s1 == NULL || \
|
||
|
(s2 != NULL && !strcmp(s1, s2)))
|
||
|
static int
|
||
|
atkbdc_getquirks(void)
|
||
|
{
|
||
|
int i;
|
||
|
char* bios_vendor = kgetenv("smbios.bios.vendor");
|
||
|
char* maker = kgetenv("smbios.system.maker");
|
||
|
char* product = kgetenv("smbios.system.product");
|
||
|
for (i=0; quirks[i].quirk != 0; ++i)
|
||
|
if (QUIRK_STR_MATCH(quirks[i].bios_vendor, bios_vendor) &&
|
||
|
QUIRK_STR_MATCH(quirks[i].maker, maker) &&
|
||
|
QUIRK_STR_MATCH(quirks[i].product, product))
|
||
|
return (quirks[i].quirk);
|
||
|
return (0);
|
||
|
}
|
||
|
atkbdc_softc_t *
|
||
|
atkbdc_get_softc(int unit)
|
||
|
{
|
||
| ... | ... | |
|
atkbdc_setup(atkbdc_softc_t *sc, bus_space_tag_t tag, bus_space_handle_t h0,
|
||
|
bus_space_handle_t h1)
|
||
|
{
|
||
|
u_int64_t tscval[3], read_delay;
|
||
|
register_t flags;
|
||
|
if (sc->ioh0 == 0) { /* XXX */
|
||
|
sc->command_byte = -1;
|
||
|
sc->lock = FALSE;
|
||
|
sc->kbd.head = sc->kbd.tail = 0;
|
||
|
sc->aux.head = sc->aux.tail = 0;
|
||
|
sc->command_byte = -1;
|
||
|
sc->command_mask = 0;
|
||
|
sc->lock = FALSE;
|
||
|
sc->kbd.head = sc->kbd.tail = 0;
|
||
|
sc->aux.head = sc->aux.tail = 0;
|
||
|
sc->aux_mux_enabled = FALSE;
|
||
|
#if KBDIO_DEBUG >= 2
|
||
|
sc->kbd.call_count = 0;
|
||
|
sc->kbd.qcount = sc->kbd.max_qcount = 0;
|
||
|
sc->aux.call_count = 0;
|
||
|
sc->aux.qcount = sc->aux.max_qcount = 0;
|
||
|
sc->kbd.call_count = 0;
|
||
|
sc->kbd.qcount = sc->kbd.max_qcount = 0;
|
||
|
sc->aux.call_count = 0;
|
||
|
sc->aux.qcount = sc->aux.max_qcount = 0;
|
||
|
#endif
|
||
|
}
|
||
|
sc->iot = tag;
|
||
|
sc->ioh0 = h0;
|
||
|
sc->ioh1 = h1;
|
||
|
/*
|
||
|
* On certain chipsets AT keyboard controller isn't present and is
|
||
|
* emulated by BIOS using SMI interrupt. On those chipsets reading
|
||
|
* from the status port may be thousand times slower than usually.
|
||
|
* Sometimes this emilation is not working properly resulting in
|
||
|
* commands timing our and since we assume that inb() operation
|
||
|
* takes very little time to complete we need to adjust number of
|
||
|
* retries to keep waiting time within a designed limits (100ms).
|
||
|
* Measure time it takes to make read_status() call and adjust
|
||
|
* number of retries accordingly.
|
||
|
*/
|
||
|
flags = intr_disable();
|
||
|
tscval[0] = rdtsc();
|
||
|
read_status(sc);
|
||
|
tscval[1] = rdtsc();
|
||
|
DELAY(1000);
|
||
|
tscval[2] = rdtsc();
|
||
|
intr_restore(flags);
|
||
|
read_delay = tscval[1] - tscval[0];
|
||
|
read_delay /= (tscval[2] - tscval[1]) / 1000;
|
||
|
sc->retry = 100000 / ((KBDD_DELAYTIME * 2) + read_delay);
|
||
|
sc->quirks = atkbdc_getquirks();
|
||
|
return 0;
|
||
|
}
|
||
|
/* open a keyboard controller */
|
||
|
KBDC
|
||
|
KBDC
|
||
|
atkbdc_open(int unit)
|
||
|
{
|
||
|
if (unit <= 0)
|
||
|
unit = 0;
|
||
|
if (unit >= MAXKBDC)
|
||
|
if (unit <= 0)
|
||
|
unit = 0;
|
||
|
if (unit >= MAXKBDC)
|
||
|
return NULL;
|
||
|
if ((atkbdc_softc[unit]->port0 != NULL)
|
||
|
|| (atkbdc_softc[unit]->ioh0 != 0)) /* XXX */
|
||
|
return (KBDC)atkbdc_softc[unit];
|
||
|
return NULL;
|
||
|
if ((atkbdc_softc[unit]->port0 != NULL)
|
||
|
|| (atkbdc_softc[unit]->ioh0 != 0)) /* XXX */
|
||
|
return (KBDC)atkbdc_softc[unit];
|
||
|
return NULL;
|
||
|
}
|
||
|
/*
|
||
| ... | ... | |
|
*/
|
||
|
/* set/reset polling lock */
|
||
|
int
|
||
|
int
|
||
|
kbdc_lock(KBDC p, int lock)
|
||
|
{
|
||
|
int prevlock;
|
||
|
int prevlock;
|
||
|
prevlock = kbdcp(p)->lock;
|
||
|
kbdcp(p)->lock = lock;
|
||
|
prevlock = kbdcp(p)->lock;
|
||
|
kbdcp(p)->lock = lock;
|
||
|
return (prevlock != lock);
|
||
|
return (prevlock != lock);
|
||
|
}
|
||
|
/* check if any data is waiting to be processed */
|
||
|
int
|
||
|
kbdc_data_ready(KBDC p)
|
||
|
{
|
||
|
return (availq(&kbdcp(p)->kbd) || availq(&kbdcp(p)->aux)
|
||
|
return (availq(&kbdcp(p)->kbd) || availq(&kbdcp(p)->aux)
|
||
|
|| (read_status(kbdcp(p)) & KBDS_ANY_BUFFER_FULL));
|
||
|
}
|
||
| ... | ... | |
|
static int
|
||
|
addq(kbdkqueue *q, int c)
|
||
|
{
|
||
|
if (nextq(q->tail) != q->head) {
|
||
|
q->q[q->tail] = c;
|
||
|
q->tail = nextq(q->tail);
|
||
|
if (nextq(q->tail) != q->head) {
|
||
|
q->q[q->tail] = c;
|
||
|
q->tail = nextq(q->tail);
|
||
|
#if KBDIO_DEBUG >= 2
|
||
|
++q->call_count;
|
||
|
++q->qcount;
|
||
|
if (q->qcount > q->max_qcount)
|
||
|
q->max_qcount = q->qcount;
|
||
|
++q->call_count;
|
||
|
++q->qcount;
|
||
|
if (q->qcount > q->max_qcount)
|
||
|
q->max_qcount = q->qcount;
|
||
|
#endif
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
static int
|
||
|
removeq(kbdkqueue *q)
|
||
|
{
|
||
|
int c;
|
||
|
int c;
|
||
|
if (q->tail != q->head) {
|
||
|
c = q->q[q->head];
|
||
|
q->head = nextq(q->head);
|
||
|
if (q->tail != q->head) {
|
||
|
c = q->q[q->head];
|
||
|
q->head = nextq(q->head);
|
||
|
#if KBDIO_DEBUG >= 2
|
||
|
--q->qcount;
|
||
|
--q->qcount;
|
||
|
#endif
|
||
|
return c;
|
||
|
}
|
||
|
return -1;
|
||
|
return c;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
/*
|
||
|
/*
|
||
|
* device I/O routines
|
||
|
*/
|
||
|
static int
|
||
|
wait_while_controller_busy(struct atkbdc_softc *kbdc)
|
||
|
{
|
||
|
/* CPU will stay inside the loop for 100msec at most */
|
||
|
TOTALDELAY retry = { .us = 70000, .last_clock =0 }; /* 70ms */
|
||
|
int f;
|
||
|
unsigned char c;
|
||
|
while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) {
|
||
|
if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
c = read_data(kbdc);
|
||
|
addq(&kbdc->kbd, c);
|
||
|
} else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
c = read_data(kbdc);
|
||
|
addq(&kbdc->aux, c);
|
||
|
/* CPU will stay inside the loop for 100msec at most */
|
||
|
TOTALDELAY retry = { .us = 70000, .last_clock =0 }; /* 70ms */
|
||
|
int f;
|
||
|
unsigned char c;
|
||
|
while ((f = read_status(kbdc)) & KBDS_INPUT_BUFFER_FULL) {
|
||
|
if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
c = read_data(kbdc);
|
||
|
addq(&kbdc->kbd, c);
|
||
|
} else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
c = read_data(kbdc);
|
||
|
addq(&kbdc->aux, c);
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return FALSE;
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
return TRUE;
|
||
|
}
|
||
|
/*
|
||
| ... | ... | |
|
static int
|
||
|
wait_for_data(struct atkbdc_softc *kbdc)
|
||
|
{
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
while ((f = read_status(kbdc) & KBDS_ANY_BUFFER_FULL) == 0) {
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return 0;
|
||
|
}
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
return f;
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
while ((f = read_status(kbdc) & KBDS_ANY_BUFFER_FULL) == 0) {
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return 0;
|
||
|
}
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
return f;
|
||
|
}
|
||
|
/* wait for data from the keyboard */
|
||
|
static int
|
||
|
wait_for_kbd_data(struct atkbdc_softc *kbdc)
|
||
|
{
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
unsigned char c;
|
||
|
while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
|
||
|
!= KBDS_KBD_BUFFER_FULL) {
|
||
|
if (f == KBDS_AUX_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
c = read_data(kbdc);
|
||
|
addq(&kbdc->aux, c);
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
unsigned char c;
|
||
|
while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
|
||
|
!= KBDS_KBD_BUFFER_FULL) {
|
||
|
if (f == KBDS_AUX_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
c = read_data(kbdc);
|
||
|
addq(&kbdc->aux, c);
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return 0;
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return 0;
|
||
|
}
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
return f;
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
return f;
|
||
|
}
|
||
|
/*
|
||
| ... | ... | |
|
static int
|
||
|
wait_for_kbd_ack(struct atkbdc_softc *kbdc)
|
||
|
{
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
int b;
|
||
|
while (CHECKTIMEOUT(&retry) == 0) {
|
||
|
if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdc);
|
||
|
if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
|
||
|
if ((b == KBD_ACK) || (b == KBD_RESEND)
|
||
|
|| (b == KBD_RESET_FAIL))
|
||
|
return b;
|
||
|
addq(&kbdc->kbd, b);
|
||
|
} else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
|
||
|
addq(&kbdc->aux, b);
|
||
|
}
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
int b;
|
||
|
while (CHECKTIMEOUT(&retry) == 0) {
|
||
|
if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdc);
|
||
|
if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
|
||
|
if ((b == KBD_ACK) || (b == KBD_RESEND)
|
||
|
|| (b == KBD_RESET_FAIL))
|
||
|
return b;
|
||
|
addq(&kbdc->kbd, b);
|
||
|
} else if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
|
||
|
addq(&kbdc->aux, b);
|
||
|
}
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
}
|
||
|
return -1;
|
||
|
return -1;
|
||
|
}
|
||
|
/* wait for data from the aux device */
|
||
|
static int
|
||
|
wait_for_aux_data(struct atkbdc_softc *kbdc)
|
||
|
{
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
unsigned char b;
|
||
|
while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
|
||
|
!= KBDS_AUX_BUFFER_FULL) {
|
||
|
if (f == KBDS_KBD_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdc);
|
||
|
addq(&kbdc->kbd, b);
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
unsigned char b;
|
||
|
while ((f = read_status(kbdc) & KBDS_BUFFER_FULL)
|
||
|
!= KBDS_AUX_BUFFER_FULL) {
|
||
|
if (f == KBDS_KBD_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdc);
|
||
|
addq(&kbdc->kbd, b);
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return 0;
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
if (CHECKTIMEOUT(&retry))
|
||
|
return 0;
|
||
|
}
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
return f;
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
return f;
|
||
|
}
|
||
|
/*
|
||
| ... | ... | |
|
static int
|
||
|
wait_for_aux_ack(struct atkbdc_softc *kbdc)
|
||
|
{
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
int b;
|
||
|
while (CHECKTIMEOUT(&retry) == 0) {
|
||
|
if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdc);
|
||
|
if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
|
||
|
if ((b == PSM_ACK) || (b == PSM_RESEND)
|
||
|
|| (b == PSM_RESET_FAIL))
|
||
|
return b;
|
||
|
addq(&kbdc->aux, b);
|
||
|
} else if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
|
||
|
addq(&kbdc->kbd, b);
|
||
|
}
|
||
|
/* CPU will stay inside the loop for 200msec at most */
|
||
|
TOTALDELAY retry = { 200000, 0 }; /* 200ms */
|
||
|
int f;
|
||
|
int b;
|
||
|
while (CHECKTIMEOUT(&retry) == 0) {
|
||
|
if ((f = read_status(kbdc)) & KBDS_ANY_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdc);
|
||
|
if ((f & KBDS_BUFFER_FULL) == KBDS_AUX_BUFFER_FULL) {
|
||
|
if ((b == PSM_ACK) || (b == PSM_RESEND)
|
||
|
|| (b == PSM_RESET_FAIL))
|
||
|
return b;
|
||
|
addq(&kbdc->aux, b);
|
||
|
} else if ((f & KBDS_BUFFER_FULL) == KBDS_KBD_BUFFER_FULL) {
|
||
|
addq(&kbdc->kbd, b);
|
||
|
}
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
}
|
||
|
DELAY(KBDC_DELAYTIME);
|
||
|
}
|
||
|
return -1;
|
||
|
return -1;
|
||
|
}
|
||
|
/*
|
||
| ... | ... | |
|
int
|
||
|
write_controller_w1r1(KBDC p, int c, int d)
|
||
|
{
|
||
|
if (!write_controller_command(p, c))
|
||
|
return(-1);
|
||
|
if (!write_controller_data(p, d))
|
||
|
return(-1);
|
||
|
return (read_controller_data(p));
|
||
|
if (!write_controller_command(p, c))
|
||
|
return(-1);
|
||
|
if (!write_controller_data(p, d))
|
||
|
return(-1);
|
||
|
return (read_controller_data(p));
|
||
|
}
|
||
|
/* write a one byte command to the controller */
|
||
|
int
|
||
|
write_controller_command(KBDC p, int c)
|
||
|
{
|
||
|
if (!wait_while_controller_busy(kbdcp(p)))
|
||
|
return FALSE;
|
||
|
write_command(kbdcp(p), c);
|
||
|
return TRUE;
|
||
|
if (!wait_while_controller_busy(kbdcp(p)))
|
||
|
return FALSE;
|
||
|
write_command(kbdcp(p), c);
|
||
|
return TRUE;
|
||
|
}
|
||
|
/* write a one byte data to the controller */
|
||
|
int
|
||
|
write_controller_data(KBDC p, int c)
|
||
|
{
|
||
|
if (!wait_while_controller_busy(kbdcp(p)))
|
||
|
return FALSE;
|
||
|
write_data(kbdcp(p), c);
|
||
|
return TRUE;
|
||
|
if (!wait_while_controller_busy(kbdcp(p)))
|
||
|
return FALSE;
|
||
|
write_data(kbdcp(p), c);
|
||
|
return TRUE;
|
||
|
}
|
||
|
/* write a one byte keyboard command */
|
||
|
int
|
||
|
write_kbd_command(KBDC p, int c)
|
||
|
{
|
||
|
if (!wait_while_controller_busy(kbdcp(p)))
|
||
|
return FALSE;
|
||
|
write_data(kbdcp(p), c);
|
||
|
return TRUE;
|
||
|
if (!wait_while_controller_busy(kbdcp(p)))
|
||
|
return FALSE;
|
||
|
write_data(kbdcp(p), c);
|
||
|
return TRUE;
|
||
|
}
|
||
|
/* write a one byte auxiliary device command */
|
||
|
int
|
||
|
write_aux_command(KBDC p, int c)
|
||
|
{
|
||
|
if (!write_controller_command(p, KBDC_WRITE_TO_AUX))
|
||
|
return FALSE;
|
||
|
return write_controller_data(p, c);
|
||
|
int f;
|
||
|
f = aux_mux_is_enabled(p) ?
|
||
|
KBDC_WRITE_TO_AUX_MUX + kbdcp(p)->aux_mux_port :
|
||
|
KBDC_WRITE_TO_AUX;
|
||
|
if (!write_controller_command(p, f))
|
||
|
return FALSE;
|
||
|
return write_controller_data(p, c);
|
||
|
}
|
||
|
/* send a command to the keyboard and wait for ACK */
|
||
|
int
|
||
|
send_kbd_command(KBDC p, int c)
|
||
|
{
|
||
|
int retry = KBD_MAXRETRY;
|
||
|
int res = -1;
|
||
|
while (retry-- > 0) {
|
||
|
if (!write_kbd_command(p, c))
|
||
|
continue;
|
||
|
res = wait_for_kbd_ack(kbdcp(p));
|
||
|
if (res == KBD_ACK)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
int retry = KBD_MAXRETRY;
|
||
|
int res = -1;
|
||
|
while (retry-- > 0) {
|
||
|
if (!write_kbd_command(p, c))
|
||
|
continue;
|
||
|
res = wait_for_kbd_ack(kbdcp(p));
|
||
|
if (res == KBD_ACK)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
/* send a command to the auxiliary device and wait for ACK */
|
||
|
int
|
||
|
send_aux_command(KBDC p, int c)
|
||
|
{
|
||
|
int retry = KBD_MAXRETRY;
|
||
|
int res = -1;
|
||
|
int retry = KBD_MAXRETRY;
|
||
|
int res = -1;
|
||
|
while (retry-- > 0) {
|
||
|
if (!write_aux_command(p, c))
|
||
|
continue;
|
||
|
/*
|
||
|
* FIXME: XXX
|
||
|
* The aux device may have already sent one or two bytes of
|
||
|
* status data, when a command is received. It will immediately
|
||
|
* stop data transmission, thus, leaving an incomplete data
|
||
|
* packet in our buffer. We have to discard any unprocessed
|
||
|
* data in order to remove such packets. Well, we may remove
|
||
|
* unprocessed, but necessary data byte as well...
|
||
|
*/
|
||
|
emptyq(&kbdcp(p)->aux);
|
||
|
res = wait_for_aux_ack(kbdcp(p));
|
||
|
if (res == PSM_ACK)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
while (retry-- > 0) {
|
||
|
if (!write_aux_command(p, c))
|
||
|
continue;
|
||
|
/*
|
||
|
* FIXME: XXX
|
||
|
* The aux device may have already sent one or two bytes of
|
||
|
* status data, when a command is received. It will immediately
|
||
|
* stop data transmission, thus, leaving an incomplete data
|
||
|
* packet in our buffer. We have to discard any unprocessed
|
||
|
* data in order to remove such packets. Well, we may remove
|
||
|
* unprocessed, but necessary data byte as well...
|
||
|
*/
|
||
|
emptyq(&kbdcp(p)->aux);
|
||
|
res = wait_for_aux_ack(kbdcp(p));
|
||
|
if (res == PSM_ACK)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
/* send a command and a data to the keyboard, wait for ACKs */
|
||
|
int
|
||
|
send_kbd_command_and_data(KBDC p, int c, int d)
|
||
|
{
|
||
|
int retry;
|
||
|
int res = -1;
|
||
|
for (retry = KBD_MAXRETRY; retry > 0; --retry) {
|
||
|
if (!write_kbd_command(p, c))
|
||
|
continue;
|
||
|
res = wait_for_kbd_ack(kbdcp(p));
|
||
|
if (res == KBD_ACK)
|
||
|
break;
|
||
|
else if (res != KBD_RESEND)
|
||
|
return res;
|
||
|
}
|
||
|
if (retry <= 0)
|
||
|
int retry;
|
||
|
int res = -1;
|
||
|
for (retry = KBD_MAXRETRY; retry > 0; --retry) {
|
||
|
if (!write_kbd_command(p, c))
|
||
|
continue;
|
||
|
res = wait_for_kbd_ack(kbdcp(p));
|
||
|
if (res == KBD_ACK)
|
||
|
break;
|
||
|
else if (res != KBD_RESEND)
|
||
|
return res;
|
||
|
}
|
||
|
if (retry <= 0)
|
||
|
return res;
|
||
|
for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
|
||
|
if (!write_kbd_command(p, d))
|
||
|
continue;
|
||
|
res = wait_for_kbd_ack(kbdcp(p));
|
||
|
if (res != KBD_RESEND)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
|
||
|
if (!write_kbd_command(p, d))
|
||
|
continue;
|
||
|
res = wait_for_kbd_ack(kbdcp(p));
|
||
|
if (res != KBD_RESEND)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
/* send a command and a data to the auxiliary device, wait for ACKs */
|
||
|
int
|
||
|
send_aux_command_and_data(KBDC p, int c, int d)
|
||
|
{
|
||
|
int retry;
|
||
|
int res = -1;
|
||
|
for (retry = KBD_MAXRETRY; retry > 0; --retry) {
|
||
|
if (!write_aux_command(p, c))
|
||
|
continue;
|
||
|
emptyq(&kbdcp(p)->aux);
|
||
|
res = wait_for_aux_ack(kbdcp(p));
|
||
|
if (res == PSM_ACK)
|
||
|
break;
|
||
|
else if (res != PSM_RESEND)
|
||
|
return res;
|
||
|
}
|
||
|
if (retry <= 0)
|
||
|
int retry;
|
||
|
int res = -1;
|
||
|
for (retry = KBD_MAXRETRY; retry > 0; --retry) {
|
||
|
if (!write_aux_command(p, c))
|
||
|
continue;
|
||
|
emptyq(&kbdcp(p)->aux);
|
||
|
res = wait_for_aux_ack(kbdcp(p));
|
||
|
if (res == PSM_ACK)
|
||
|
break;
|
||
|
else if (res != PSM_RESEND)
|
||
|
return res;
|
||
|
}
|
||
|
if (retry <= 0)
|
||
|
return res;
|
||
|
for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
|
||
|
if (!write_aux_command(p, d))
|
||
|
continue;
|
||
|
res = wait_for_aux_ack(kbdcp(p));
|
||
|
if (res != PSM_RESEND)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
for (retry = KBD_MAXRETRY, res = -1; retry > 0; --retry) {
|
||
|
if (!write_aux_command(p, d))
|
||
|
continue;
|
||
|
res = wait_for_aux_ack(kbdcp(p));
|
||
|
if (res != PSM_RESEND)
|
||
|
break;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
/*
|
||
| ... | ... | |
|
int
|
||
|
read_controller_data(KBDC p)
|
||
|
{
|
||
|
if (availq(&kbdcp(p)->kbd))
|
||
|
return removeq(&kbdcp(p)->kbd);
|
||
|
if (availq(&kbdcp(p)->aux))
|
||
|
return removeq(&kbdcp(p)->aux);
|
||
|
if (!wait_for_data(kbdcp(p)))
|
||
|
return -1; /* timeout */
|
||
|
return read_data(kbdcp(p));
|
||
|
if (availq(&kbdcp(p)->kbd))
|
||
|
return removeq(&kbdcp(p)->kbd);
|
||
|
if (availq(&kbdcp(p)->aux))
|
||
|
return removeq(&kbdcp(p)->aux);
|
||
|
if (!wait_for_data(kbdcp(p)))
|
||
|
return -1; /* timeout */
|
||
|
return read_data(kbdcp(p));
|
||
|
}
|
||
|
#if KBDIO_DEBUG >= 2
|
||
| ... | ... | |
|
int
|
||
|
read_kbd_data(KBDC p)
|
||
|
{
|
||
|
unsigned char b;
|
||
|
unsigned char b;
|
||
|
#if KBDIO_DEBUG >= 2
|
||
|
if (++call > 2000) {
|
||
|
call = 0;
|
||
|
log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
|
||
|
"aux q: %d calls, max %d chars\n",
|
||
|
kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
|
||
|
kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
|
||
|
}
|
||
|
if (++call > 2000) {
|
||
|
call = 0;
|
||
|
log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
|
||
|
"aux q: %d calls, max %d chars\n",
|
||
|
kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
|
||
|
kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
|
||
|
}
|
||
|
#endif
|
||
|
if (availq(&kbdcp(p)->kbd))
|
||
|
return removeq(&kbdcp(p)->kbd);
|
||
|
if (!wait_for_kbd_data(kbdcp(p)))
|
||
|
return -1; /* timeout */
|
||
|
b = read_data(kbdcp(p));
|
||
|
return b;
|
||
|
if (availq(&kbdcp(p)->kbd))
|
||
|
return removeq(&kbdcp(p)->kbd);
|
||
|
if (!wait_for_kbd_data(kbdcp(p)))
|
||
|
return -1; /* timeout */
|
||
|
b = read_data(kbdcp(p));
|
||
|
return b;
|
||
|
}
|
||
|
/* read one byte from the keyboard, but return immediately if
|
||
| ... | ... | |
|
int
|
||
|
read_kbd_data_no_wait(KBDC p)
|
||
|
{
|
||
|
int f;
|
||
|
unsigned char b;
|
||
|
int f;
|
||
|
unsigned char b;
|
||
|
#if KBDIO_DEBUG >= 2
|
||
|
if (++call > 2000) {
|
||
|
call = 0;
|
||
|
log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
|
||
|
"aux q: %d calls, max %d chars\n",
|
||
|
kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
|
||
|
kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
|
||
|
}
|
||
|
if (++call > 2000) {
|
||
|
call = 0;
|
||
|
log(LOG_DEBUG, "kbdc: kbd q: %d calls, max %d chars, "
|
||
|
"aux q: %d calls, max %d chars\n",
|
||
|
kbdcp(p)->kbd.call_count, kbdcp(p)->kbd.max_qcount,
|
||
|
kbdcp(p)->aux.call_count, kbdcp(p)->aux.max_qcount);
|
||
|
}
|
||
|
#endif
|
||
|
if (availq(&kbdcp(p)->kbd))
|
||
|
return removeq(&kbdcp(p)->kbd);
|
||
|
f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
|
||
|
while (f == KBDS_AUX_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdcp(p));
|
||
|
addq(&kbdcp(p)->aux, b);
|
||
|
f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
|
||
|
}
|
||
|
if (f == KBDS_KBD_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
if (availq(&kbdcp(p)->kbd))
|
||
|
return removeq(&kbdcp(p)->kbd);
|
||
|
f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
|
||
|
while (f == KBDS_AUX_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdcp(p));
|
||
|
addq(&kbdcp(p)->aux, b);
|
||
|
f = read_status(kbdcp(p)) & KBDS_BUFFER_FULL;
|
||
|
}
|
||
|
if (f == KBDS_KBD_BUFFER_FULL) {
|
||
|
DELAY(KBDD_DELAYTIME);
|
||
|
b = read_data(kbdcp(p));
|
||
|
return (int)b;
|
||
|
}
|
||
|
return -1; /* no data */
|
||
|
return (int)b;
|
||