Handle mouse and other packages received from the keyboard correctly.
The initialisation now resets the keyboard and disables all packages that make no sense because their drivers are not activated.
This commit is contained in:
parent
91bada6a66
commit
73c861e2e3
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: kbd.c,v 1.2 1995/04/10 08:54:41 mycroft Exp $ */
|
||||
/* $NetBSD: kbd.c,v 1.3 1995/06/09 20:00:14 leo Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995 Leo Weppelman
|
||||
@ -59,8 +59,8 @@
|
||||
* The ringbuffer is the interface between the hard and soft interrupt handler.
|
||||
* The hard interrupt runs straight from the MFP interrupt.
|
||||
*/
|
||||
#define KBD_RING_SIZE 16 /* Size of the ring buffer, must be power of 2 */
|
||||
#define KBD_RING_MASK 15 /* Modulo mask for above */
|
||||
#define KBD_RING_SIZE 256 /* Sz of input ring buffer, must be power of 2 */
|
||||
#define KBD_RING_MASK 255 /* Modulo mask for above */
|
||||
|
||||
static u_char kbd_ring[KBD_RING_SIZE];
|
||||
static volatile u_int kbd_rbput = 0; /* 'put' index */
|
||||
@ -71,6 +71,12 @@ struct kbd_softc {
|
||||
int k_event_mode; /* if 1, collect events, */
|
||||
/* else pass to ite */
|
||||
struct evvar k_events; /* event queue state */
|
||||
u_char k_soft_cs; /* control-reg. copy */
|
||||
u_char k_package[20]; /* XXX package being build */
|
||||
u_char k_pkg_size; /* Size of the package */
|
||||
u_char k_pkg_idx;
|
||||
u_char *k_sendp; /* Output pointer */
|
||||
int k_send_cnt; /* Chars left for output */
|
||||
};
|
||||
|
||||
static struct kbd_softc kbd_softc;
|
||||
@ -78,6 +84,9 @@ static struct kbd_softc kbd_softc;
|
||||
static void kbdsoft __P((void));
|
||||
static void kbdattach __P((struct device *, struct device *, void *));
|
||||
static int kbdmatch __P((struct device *, struct cfdata *, void *));
|
||||
static int kbd_wite_poll __P((u_char *, int));
|
||||
static void kbd_write __P((u_char *, int));
|
||||
static void kbd_pkg_start __P((struct kbd_softc *, u_char));
|
||||
|
||||
struct cfdriver kbdcd = {
|
||||
NULL, "kbd", (cfmatch_t)kbdmatch, kbdattach,
|
||||
@ -91,9 +100,9 @@ struct device *pdp;
|
||||
struct cfdata *cfp;
|
||||
void *auxp;
|
||||
{
|
||||
if(!strcmp((char *)auxp, "kbd"))
|
||||
return(1);
|
||||
return(0);
|
||||
if (!strcmp((char *)auxp, "kbd"))
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
@ -102,48 +111,85 @@ kbdattach(pdp, dp, auxp)
|
||||
struct device *pdp, *dp;
|
||||
void *auxp;
|
||||
{
|
||||
int timeout;
|
||||
u_char rst[] = { 0x80, 0x01 };
|
||||
|
||||
/*
|
||||
* Disable keyboard interrupts from MFP
|
||||
*/
|
||||
MFP->mf_ierb &= ~IB_AINT;
|
||||
|
||||
/*
|
||||
* Reset ACIA and intialize to:
|
||||
* divide by 16, 8 data, 1 stop, no parity, enable RX interrupts
|
||||
*/
|
||||
KBD->ac_cs = A_RESET;
|
||||
delay(100); /* XXX: enough? */
|
||||
KBD->ac_cs = kbd_softc.k_soft_cs = KBD_INIT | A_RXINT;
|
||||
|
||||
/*
|
||||
* Clear error conditions
|
||||
*/
|
||||
while (KBD->ac_cs & (A_IRQ|A_RXRDY))
|
||||
timeout = KBD->ac_da;
|
||||
|
||||
/*
|
||||
* Now send the reset string, and read+ignore it's response
|
||||
*/
|
||||
if (!kbd_wite_poll(rst, 2))
|
||||
printf("kbd: error cannot reset keyboard\n");
|
||||
for (timeout = 1000; timeout > 0; timeout--) {
|
||||
if (KBD->ac_cs & (A_IRQ|A_RXRDY)) {
|
||||
timeout = KBD->ac_da;
|
||||
timeout = 100;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* definitions for atari keyboard encoding. */
|
||||
#define KEY_CODE(c) ((c) & 0x7f)
|
||||
#define KEY_UP(c) ((c) & 0x80)
|
||||
#define KEY_CODE(c) ((u_char)(c) & 0x7f)
|
||||
#define KEY_UP(c) ((u_char)(c) & 0x80)
|
||||
#define IS_KEY(c) ((u_char)(c) < 0xf6)
|
||||
|
||||
void
|
||||
kbdenable()
|
||||
{
|
||||
int s, code;
|
||||
int s, code;
|
||||
u_char kbd_icmd[] = { 0x12, 0x15 };
|
||||
|
||||
s = spltty();
|
||||
|
||||
/*
|
||||
* Initialize ACIA port
|
||||
* Clear error conditions...
|
||||
*/
|
||||
code = KBD->ac_da; /* Clear error conditions */
|
||||
|
||||
/* divide by 16, 8 data, 1 stop, no parity, enable interrupts */
|
||||
KBD->ac_cs = KBD_INIT | A_RXINT;
|
||||
#if 0 /* XXX Turn off mouse??? */
|
||||
KBD->ac_da = 0x12;
|
||||
#endif
|
||||
|
||||
while (KBD->ac_cs & (A_IRQ|A_RXRDY))
|
||||
code = KBD->ac_da;
|
||||
/*
|
||||
* Enable interrupts from MFP
|
||||
*/
|
||||
MFP->mf_iprb &= ~IB_AINT;
|
||||
MFP->mf_ierb |= IB_AINT;
|
||||
MFP->mf_imrb |= IB_AINT;
|
||||
code = KBD->ac_da; /* Clear error conditions */
|
||||
|
||||
kbd_softc.k_event_mode = 0;
|
||||
kbd_softc.k_events.ev_io = 0;
|
||||
kbd_softc.k_pkg_size = 0;
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Send init command: disable mice & joysticks
|
||||
*/
|
||||
kbd_write(kbd_icmd, sizeof(kbd_icmd));
|
||||
}
|
||||
|
||||
int kbdopen(dev_t dev, int flags, int mode, struct proc *p)
|
||||
{
|
||||
int s, error;
|
||||
|
||||
if(kbd_softc.k_events.ev_io)
|
||||
if (kbd_softc.k_events.ev_io)
|
||||
return EBUSY;
|
||||
|
||||
kbd_softc.k_events.ev_io = p;
|
||||
@ -174,7 +220,7 @@ kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p)
|
||||
|
||||
switch (cmd) {
|
||||
case KIOCTRANS:
|
||||
if(*(int *)data == TR_UNTRANS_EVENT)
|
||||
if (*(int *)data == TR_UNTRANS_EVENT)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
@ -197,7 +243,7 @@ kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p)
|
||||
return 0;
|
||||
|
||||
case TIOCSPGRP:
|
||||
if(*(int *)data != k->k_events.ev_io->p_pgid)
|
||||
if (*(int *)data != k->k_events.ev_io->p_pgid)
|
||||
return EPERM;
|
||||
return 0;
|
||||
|
||||
@ -218,31 +264,56 @@ kbdselect (dev_t dev, int rw, struct proc *p)
|
||||
}
|
||||
|
||||
/*
|
||||
* Keyboard interrupt handler called straight from MFP.
|
||||
* Keyboard interrupt handler called straight from MFP at spl6.
|
||||
*/
|
||||
int
|
||||
kbdintr(sr)
|
||||
int sr; /* sr at time of interrupt */
|
||||
{
|
||||
int code;
|
||||
int got_char = 0;
|
||||
|
||||
/*
|
||||
* There may be multiple keys available. Read them all.
|
||||
*/
|
||||
while(KBD->ac_cs & (A_IRQ|A_RXRDY)) {
|
||||
if(KBD->ac_cs & (A_OE|A_PE)) {
|
||||
code = KBD->ac_da; /* Silently ignore overruns */
|
||||
while (KBD->ac_cs & (A_RXRDY|A_OE|A_PE)) {
|
||||
got_char = 1;
|
||||
if (KBD->ac_cs & (A_OE|A_PE)) {
|
||||
code = KBD->ac_da; /* Silently ignore errors */
|
||||
continue;
|
||||
}
|
||||
kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da;
|
||||
}
|
||||
if(!BASEPRI(sr)) {
|
||||
if(!kbd_soft++)
|
||||
add_sicallback(kbdsoft, 0, 0);
|
||||
|
||||
/*
|
||||
* If characters are waiting for transmit, send them.
|
||||
*/
|
||||
if ((kbd_softc.k_soft_cs & A_TXINT) && (KBD->ac_cs & A_TXRDY)) {
|
||||
if (kbd_softc.k_sendp != NULL)
|
||||
KBD->ac_da = *kbd_softc.k_sendp++;
|
||||
if (--kbd_softc.k_send_cnt <= 0) {
|
||||
/*
|
||||
* The total package has been transmitted,
|
||||
* wakeup anyone waiting for it.
|
||||
*/
|
||||
KBD->ac_cs = (kbd_softc.k_soft_cs &= ~A_TXINT);
|
||||
kbd_softc.k_sendp = NULL;
|
||||
kbd_softc.k_send_cnt = 0;
|
||||
wakeup((caddr_t)&kbd_softc.k_send_cnt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
spl1();
|
||||
kbdsoft();
|
||||
|
||||
/*
|
||||
* Activate software-level to handle possible input.
|
||||
*/
|
||||
if (got_char) {
|
||||
if (!BASEPRI(sr)) {
|
||||
if (!kbd_soft++)
|
||||
add_sicallback(kbdsoft, 0, 0);
|
||||
} else {
|
||||
spl1();
|
||||
kbdsoft();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,23 +333,47 @@ kbdsoft()
|
||||
kbd_soft = 0;
|
||||
get = kbd_rbget;
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
n = kbd_rbput;
|
||||
if(get == n) /* We're done */
|
||||
if (get == n) /* We're done */
|
||||
break;
|
||||
n -= get;
|
||||
if(n > KBD_RING_SIZE) { /* Ring buffer overflow */
|
||||
if (n > KBD_RING_SIZE) { /* Ring buffer overflow */
|
||||
get += n - KBD_RING_SIZE;
|
||||
n = KBD_RING_SIZE;
|
||||
}
|
||||
while(--n >= 0) {
|
||||
while (--n >= 0) {
|
||||
code = kbd_ring[get++ & KBD_RING_MASK];
|
||||
|
||||
/*
|
||||
* If collecting a package, stuff it in and
|
||||
* continue.
|
||||
*/
|
||||
if (k->k_pkg_size && (k->k_pkg_idx < k->k_pkg_size)) {
|
||||
k->k_package[k->k_pkg_idx++] = code;
|
||||
if (k->k_pkg_idx == k->k_pkg_size) {
|
||||
k->k_pkg_size = 0;
|
||||
/*
|
||||
* Package is complete, we can now
|
||||
* send it to (the not yet present)
|
||||
* mouse driver...
|
||||
*/
|
||||
/* mouse_soft(k->k_package,k->k_pkg_size);*/
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If this is a package header, init pkg. handling.
|
||||
*/
|
||||
if (!IS_KEY(code)) {
|
||||
kbd_pkg_start(k, code);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* if not in event mode, deliver straight to ite to
|
||||
* process key stroke
|
||||
*/
|
||||
if(!k->k_event_mode) {
|
||||
if (!k->k_event_mode) {
|
||||
/* Gets to spltty() by itself */
|
||||
ite_filter(code, ITEFILT_TTY);
|
||||
continue;
|
||||
@ -293,7 +388,7 @@ kbdsoft()
|
||||
put = k->k_events.ev_put;
|
||||
fe = &k->k_events.ev_q[put];
|
||||
put = (put + 1) % EV_QSIZE;
|
||||
if(put == k->k_events.ev_get) {
|
||||
if (put == k->k_events.ev_get) {
|
||||
log(LOG_WARNING,
|
||||
"keyboard event queue overflow\n");
|
||||
splx(s);
|
||||
@ -318,14 +413,14 @@ static char sound[] = {
|
||||
int
|
||||
kbdbell()
|
||||
{
|
||||
register int i, sps;
|
||||
register int i, sps;
|
||||
|
||||
sps = spltty();
|
||||
for(i = 0; i < sizeof(sound); i++) {
|
||||
SOUND->sd_selr = i;
|
||||
SOUND->sd_wdat = sound[i];
|
||||
}
|
||||
splx(sps);
|
||||
sps = spltty();
|
||||
for (i = 0; i < sizeof(sound); i++) {
|
||||
SOUND->sd_selr = i;
|
||||
SOUND->sd_wdat = sound[i];
|
||||
}
|
||||
splx(sps);
|
||||
}
|
||||
|
||||
int
|
||||
@ -335,8 +430,15 @@ kbdgetcn()
|
||||
int s = spltty();
|
||||
|
||||
MFP->mf_imrb &= ~IB_AINT;
|
||||
while(!(KBD->ac_cs & A_IRQ))
|
||||
; /* Wait for key */
|
||||
for (;;) {
|
||||
while (!(KBD->ac_cs & (A_IRQ|A_RXRDY)))
|
||||
; /* Wait for key */
|
||||
if (KBD->ac_cs & (A_OE|A_PE)) {
|
||||
code = KBD->ac_da; /* Silently ignore errors */
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
MFP->mf_iprb &= ~IB_AINT;
|
||||
MFP->mf_imrb |= IB_AINT;
|
||||
@ -345,3 +447,107 @@ kbdgetcn()
|
||||
splx (s);
|
||||
return code;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a command to the keyboard in 'polled' mode.
|
||||
*/
|
||||
static int
|
||||
kbd_wite_poll(cmd, len)
|
||||
u_char *cmd;
|
||||
int len;
|
||||
{
|
||||
int timeout;
|
||||
|
||||
while (len-- > 0) {
|
||||
KBD->ac_da = *cmd++;
|
||||
for (timeout = 100; !(KBD->ac_cs & A_TXRDY); timeout--)
|
||||
delay(10);
|
||||
if (!(KBD->ac_cs & A_TXRDY))
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a command to the keyboard. Return when command is send.
|
||||
*/
|
||||
static void
|
||||
kbd_write(cmd, len)
|
||||
u_char *cmd;
|
||||
int len;
|
||||
{
|
||||
struct kbd_softc *k = &kbd_softc;
|
||||
int sps;
|
||||
|
||||
/*
|
||||
* Get to splhigh, 'real' interrupts arrive at spl6!
|
||||
*/
|
||||
sps = splhigh();
|
||||
|
||||
/*
|
||||
* Make sure any privious write has ended...
|
||||
*/
|
||||
while (k->k_sendp != NULL)
|
||||
tsleep((caddr_t)&k->k_sendp, TTOPRI, "kbd_write1", 0);
|
||||
|
||||
/*
|
||||
* If the KBD-acia is not currently busy, send the first
|
||||
* character now.
|
||||
*/
|
||||
KBD->ac_cs = (k->k_soft_cs |= A_TXINT);
|
||||
if (KBD->ac_cs & A_TXRDY) {
|
||||
KBD->ac_da = *cmd++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're not yet done, wait until all characters are send.
|
||||
*/
|
||||
if (len > 0) {
|
||||
k->k_sendp = cmd;
|
||||
k->k_send_cnt = len;
|
||||
tsleep((caddr_t)&k->k_send_cnt, TTOPRI, "kbd_write2", 0);
|
||||
}
|
||||
splx(sps);
|
||||
|
||||
/*
|
||||
* Wakeup all procs waiting for us.
|
||||
*/
|
||||
wakeup((caddr_t)&k->k_sendp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup softc-fields to assemble a keyboard package.
|
||||
*/
|
||||
static void
|
||||
kbd_pkg_start(kp, msg_start)
|
||||
struct kbd_softc *kp;
|
||||
u_char msg_start;
|
||||
{
|
||||
kp->k_pkg_idx = 1;
|
||||
kp->k_package[0] = msg_start;
|
||||
switch (msg_start) {
|
||||
case 0xf6:
|
||||
kp->k_pkg_size = 8;
|
||||
break;
|
||||
case 0xf7:
|
||||
kp->k_pkg_size = 6;
|
||||
break;
|
||||
case 0xf8:
|
||||
case 0xf9:
|
||||
case 0xfa:
|
||||
case 0xfb:
|
||||
kp->k_pkg_size = 3;
|
||||
break;
|
||||
case 0xfc:
|
||||
kp->k_pkg_size = 7;
|
||||
break;
|
||||
case 0xfe:
|
||||
case 0xff:
|
||||
kp->k_pkg_size = 2;
|
||||
break;
|
||||
default:
|
||||
printf("kbd: Unknown packet 0x%x\n", msg_start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user