diff --git a/sys/arch/atari/dev/kbd.c b/sys/arch/atari/dev/kbd.c index f3cd3300b28c..0611fb8531f7 100644 --- a/sys/arch/atari/dev/kbd.c +++ b/sys/arch/atari/dev/kbd.c @@ -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; + } +}