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;
|