Project

General

Profile

Submit #3206 ยป psm_2_FBSD12_delay_hopefully_fixed.patch

htse, 10/05/2019 03:48 PM

View differences:

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;
... This diff was truncated because it exceeds the maximum size that can be displayed.
    (1-1/1)