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:
parent
6a036b85d9
commit
2b7d2123cd
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user