Make console polling (cnpollc/cngetc) work on IBM PS/2 keyboard controller

using level triggered interrupts, which livelocks calling intr routine
if the data register is not read in the interrupt routine, as it's case
when polling after interrupts are enabled during boot.

Block all interrupts when polling for keypress, and modify intr routine
to read and store value from data register. The latter one is to avoid
losing a keypress when one would manage to press a key when kernel is
not in spl-guarded code section.

Tested with classic pccons, 'pcconskbd at pckbc' and 'pckbd at pckbc'
configurations, on i386.
This commit is contained in:
jdolecek 2001-07-31 13:15:28 +00:00
parent 6a036b85d9
commit 2b7d2123cd
2 changed files with 62 additions and 11 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: pccons.c,v 1.148 2001/07/24 22:29:08 wiz Exp $ */
/* $NetBSD: pccons.c,v 1.149 2001/07/31 13:15:29 jdolecek Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -157,6 +157,7 @@ static u_short *Crtat; /* pointer to backing store */
static u_short *crtat; /* pointer to current char */
#if (NPCCONSKBD == 0)
static volatile u_char ack, nak; /* Don't ask. */
static int poll_data = -1;
#endif
static u_char async, kernel, polling; /* Really, you don't want to know. */
static u_char lock_state = 0x00; /* all off */
@ -942,10 +943,13 @@ pcintr(arg)
if ((inb(IO_KBD + KBSTATP) & KBS_DIB) == 0)
return (0);
if (polling)
return (1);
do {
cp = sget();
if (polling) {
poll_data = *cp;
return (1);
}
if (!tp || (tp->t_state & TS_ISOPEN) == 0)
return (1);
if (cp)
@ -1119,6 +1123,11 @@ pccnputc(dev, c)
kernel = oldkernel;
}
/*
* Note: the spl games here are to deal with some strange PC kbd controllers
* in some system configurations.
* This is not canonical way to handle polling input.
*/
/* ARGSUSED */
int
pccngetc(dev)
@ -1134,9 +1143,20 @@ pccngetc(dev)
do {
/* wait for byte */
#if (NPCCONSKBD == 0)
int s = splhigh();
if (poll_data != -1) {
int data = poll_data;
poll_data = -1;
splx(s);
return (data);
}
while ((inb(IO_KBD + KBSTATP) & KBS_DIB) == 0);
/* see if it's worthwhile */
cp = sget();
splx(s);
#else
int data;
do {
@ -1160,7 +1180,9 @@ pccnpollc(dev, on)
#if (NPCCONSKBD > 0)
pckbc_set_poll(kbctag, kbcslot, on);
#else
if (!on) {
if (on)
poll_data = -1;
else {
int unit;
struct pc_softc *sc;
int s;

View File

@ -1,4 +1,4 @@
/* $NetBSD: pckbc.c,v 1.14 2001/07/23 21:03:21 jdolecek Exp $ */
/* $NetBSD: pckbc.c,v 1.15 2001/07/31 13:15:28 jdolecek Exp $ */
/*
* Copyright (c) 1998
@ -76,7 +76,9 @@ struct pckbc_devcmd {
/* data per slave device */
struct pckbc_slotdata {
int polling; /* don't read data port in interrupt handler */
int polling; /* don't process data in interrupt handler */
int poll_data; /* data read from inr handler if polling */
int poll_stat; /* status read from inr handler if polling */
TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
#define NCMD 5
@ -147,6 +149,11 @@ pckbc_send_cmd(iot, ioh_c, val)
return (1);
}
/*
* Note: the spl games here are to deal with some strange PC kbd controllers
* in some system configurations.
* This is not canonical way to handle polling input.
*/
int
pckbc_poll_data1(pt, slot, checkaux)
pckbc_tag_t pt;
@ -154,9 +161,20 @@ pckbc_poll_data1(pt, slot, checkaux)
int checkaux;
{
struct pckbc_internal *t = pt;
int i;
struct pckbc_slotdata *q = t->t_slotdata[slot];
int i, s;
u_char stat, c;
s = splhigh();
if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
stat = q->poll_stat;
c = q->poll_data;
q->poll_data = -1;
q->poll_stat = -1;
goto process;
}
/* if 1 port read takes 1us (?), this polls for 100ms */
for (i = 100000; i; i--) {
stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
@ -164,6 +182,7 @@ pckbc_poll_data1(pt, slot, checkaux)
KBD_DELAY;
c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
process:
if (checkaux && (stat & 0x20)) { /* aux data */
if (slot != PCKBC_AUX_SLOT) {
#ifdef PCKBCDEBUG
@ -179,9 +198,12 @@ pckbc_poll_data1(pt, slot, checkaux)
continue;
}
}
splx(s);
return (c);
}
}
splx(s);
return (-1);
}
@ -522,7 +544,10 @@ pckbc_set_poll(self, slot, on)
t->t_slotdata[slot]->polling = on;
if (!on) {
if (on) {
t->t_slotdata[slot]->poll_data = -1;
t->t_slotdata[slot]->poll_stat = -1;
} else {
int s;
/*
@ -917,15 +942,19 @@ pckbcintr(vsc)
continue;
}
if (q->polling)
break; /* pckbc_poll_data() will get it */
KBD_DELAY;
data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
#if NRND > 0
rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
#endif
if (q->polling) {
q->poll_data = data;
q->poll_stat = stat;
break; /* pckbc_poll_data() will get it */
}
if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
continue;