810 lines
17 KiB
C
810 lines
17 KiB
C
/* $NetBSD: kbd.c,v 1.46 2003/09/21 19:16:48 jdolecek Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* kbd.c
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.46 2003/09/21 19:16:48 jdolecek Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/device.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/file.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/conf.h>
|
|
#include <dev/cons.h>
|
|
#include <machine/cpu.h>
|
|
#include <amiga/amiga/device.h>
|
|
#include <amiga/amiga/custom.h>
|
|
#ifdef DRACO
|
|
#include <m68k/asm_single.h>
|
|
#include <amiga/amiga/drcustom.h>
|
|
#endif
|
|
#include <amiga/amiga/cia.h>
|
|
#include <amiga/dev/itevar.h>
|
|
#include <amiga/dev/kbdreg.h>
|
|
#include <amiga/dev/kbdmap.h>
|
|
#include <amiga/dev/event_var.h>
|
|
#include <amiga/dev/vuid_event.h>
|
|
|
|
#include "kbd.h"
|
|
#include "ite.h"
|
|
|
|
/* WSKBD */
|
|
|
|
/*
|
|
* If NWSKBD>0 we try to attach an wskbd device to us. What follows
|
|
* is definitions of callback functions and structures that are passed
|
|
* to wscons when initializing.
|
|
*/
|
|
|
|
/*
|
|
* Now with wscons this driver exhibits some weird behaviour.
|
|
* It may act both as a driver of its own and the md part of the
|
|
* wskbd driver. Therefore it can be accessed through /dev/kbd
|
|
* and /dev/wskbd0 both.
|
|
*
|
|
* The data from they keyboard may end up in at least four different
|
|
* places:
|
|
* - If this driver has been opened (/dev/kbd) and the
|
|
* direct mode (TIOCDIRECT) has been set, data goes to
|
|
* the process who opened the device. Data will transmit itself
|
|
* as described by the firm_event structure.
|
|
* - If wskbd support is compiled in and a wskbd driver has been
|
|
* attached then the data is sent to it. Wskbd in turn may
|
|
* - Send the data in the wscons_event form to a process that
|
|
* has opened /dev/wskbd0
|
|
* - Feed the data to a virtual terminal.
|
|
* - If an ite is present the data may be fed to it.
|
|
*/
|
|
|
|
#include "wskbd.h"
|
|
|
|
#if NWSKBD>0
|
|
#include <dev/wscons/wsconsio.h>
|
|
#include <dev/wscons/wskbdvar.h>
|
|
#include <dev/wscons/wsksymdef.h>
|
|
#include <dev/wscons/wsksymvar.h>
|
|
#include <amiga/dev/wskbdmap_amiga.h>
|
|
|
|
/* accessops */
|
|
int kbd_enable(void *, int);
|
|
void kbd_set_leds(void *, int);
|
|
int kbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
|
|
|
|
/* console ops */
|
|
void kbd_getc(void *, u_int *, int *);
|
|
void kbd_pollc(void *, int);
|
|
void kbd_bell(void *, u_int, u_int, u_int);
|
|
|
|
static struct wskbd_accessops kbd_accessops = {
|
|
kbd_enable,
|
|
kbd_set_leds,
|
|
kbd_ioctl
|
|
};
|
|
|
|
static struct wskbd_consops kbd_consops = {
|
|
kbd_getc,
|
|
kbd_pollc,
|
|
kbd_bell
|
|
};
|
|
|
|
/*
|
|
* Pointer to keymaps. They are defined in wskbdmap_amiga.c.
|
|
*/
|
|
static struct wskbd_mapdata kbd_mapdata = {
|
|
amigakbd_keydesctab,
|
|
KB_US
|
|
};
|
|
|
|
#endif /* WSKBD */
|
|
|
|
struct kbd_softc {
|
|
int k_event_mode; /* if true, collect events, else pass to ite */
|
|
struct evvar k_events; /* event queue state */
|
|
#ifdef DRACO
|
|
u_char k_rlprfx; /* MF-II rel. prefix has been seen */
|
|
u_char k_mf2;
|
|
#endif
|
|
|
|
#if NWSKBD>0
|
|
struct device *k_wskbddev; /* pointer to wskbd for sending strokes */
|
|
int k_pollingmode; /* polling mode on? whatever it isss... */
|
|
#endif
|
|
};
|
|
struct kbd_softc kbd_softc;
|
|
|
|
int kbdmatch(struct device *, struct cfdata *, void *);
|
|
void kbdattach(struct device *, struct device *, void *);
|
|
void kbdintr(int);
|
|
void kbdstuffchar(u_char);
|
|
|
|
int drkbdgetc(void);
|
|
int drkbdrputc(u_int8_t);
|
|
int drkbdputc(u_int8_t);
|
|
int drkbdputc2(u_int8_t, u_int8_t);
|
|
int drkbdwaitfor(int);
|
|
|
|
CFATTACH_DECL(kbd, sizeof(struct device),
|
|
kbdmatch, kbdattach, NULL, NULL);
|
|
|
|
dev_type_open(kbdopen);
|
|
dev_type_close(kbdclose);
|
|
dev_type_read(kbdread);
|
|
dev_type_ioctl(kbdioctl);
|
|
dev_type_poll(kbdpoll);
|
|
dev_type_kqfilter(kbdkqfilter);
|
|
|
|
const struct cdevsw kbd_cdevsw = {
|
|
kbdopen, kbdclose, kbdread, nowrite, kbdioctl,
|
|
nostop, notty, kbdpoll, nommap, kbdkqfilter,
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
int
|
|
kbdmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
|
|
{
|
|
|
|
if (matchname((char *)auxp, "kbd"))
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
kbdattach(struct device *pdp, struct device *dp, void *auxp)
|
|
{
|
|
#ifdef DRACO
|
|
kbdenable();
|
|
if (kbd_softc.k_mf2)
|
|
printf(": QuickLogic type MF-II\n");
|
|
else
|
|
printf(": CIA A type Amiga\n");
|
|
#else
|
|
printf(": CIA A type Amiga\n");
|
|
#endif
|
|
|
|
#if NWSKBD>0
|
|
if (dp != NULL) {
|
|
/*
|
|
* Try to attach the wskbd.
|
|
*/
|
|
struct wskbddev_attach_args waa;
|
|
|
|
/* Maybe should be done before this?... */
|
|
wskbd_cnattach(&kbd_consops, NULL, &kbd_mapdata);
|
|
|
|
waa.console = 1;
|
|
waa.keymap = &kbd_mapdata;
|
|
waa.accessops = &kbd_accessops;
|
|
waa.accesscookie = NULL;
|
|
kbd_softc.k_wskbddev = config_found(dp, &waa, wskbddevprint);
|
|
|
|
kbd_softc.k_pollingmode = 0;
|
|
}
|
|
kbdenable();
|
|
#endif /* WSKBD */
|
|
}
|
|
|
|
/* definitions for amiga keyboard encoding. */
|
|
#define KEY_CODE(c) ((c) & 0x7f)
|
|
#define KEY_UP(c) ((c) & 0x80)
|
|
|
|
#define DATLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
|
|
#define DATHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
|
|
|
|
#define CLKLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
|
|
#define CLKHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
|
|
|
|
void
|
|
kbdenable(void)
|
|
{
|
|
static int kbd_inited = 0;
|
|
|
|
int s;
|
|
|
|
#ifdef DRACO
|
|
int id;
|
|
#endif
|
|
/*
|
|
* collides with external ints from SCSI, watch out for this when
|
|
* enabling/disabling interrupts there !!
|
|
*/
|
|
s = splhigh(); /* don't lower; might be called from early ddb */
|
|
if (kbd_inited) {
|
|
splx(s);
|
|
return;
|
|
}
|
|
kbd_inited = 1;
|
|
#ifdef DRACO
|
|
if (is_draco()) {
|
|
|
|
CLKLO;
|
|
delay(5000);
|
|
draco_ioct->io_kbdrst = 0;
|
|
|
|
if (drkbdputc(0xf2))
|
|
goto LnoMFII;
|
|
|
|
id = drkbdgetc() << 8;
|
|
id |= drkbdgetc();
|
|
|
|
if (id != 0xab83)
|
|
goto LnoMFII;
|
|
|
|
if (drkbdputc2(0xf0, 3)) /* mode 3 */
|
|
goto LnoMFII;
|
|
|
|
if (drkbdputc(0xf8)) /* make/break, no typematic */
|
|
goto LnoMFII;
|
|
|
|
if (drkbdputc(0xf4)) /* enable */
|
|
goto LnoMFII;
|
|
kbd_softc.k_mf2 = 1;
|
|
single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDINTENA);
|
|
|
|
ciaa.icr = CIA_ICR_SP; /* CIA SP interrupt disable */
|
|
ciaa.cra &= ~(1<<6); /* serial line == input */
|
|
splx(s);
|
|
return;
|
|
|
|
LnoMFII:
|
|
kbd_softc.k_mf2 = 0;
|
|
single_inst_bset_b(*draco_intena, DRIRQ_INT2);
|
|
ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
|
|
/* SP interrupt enable */
|
|
ciaa.cra &= ~(1<<6); /* serial line == input */
|
|
splx(s);
|
|
return;
|
|
|
|
} else {
|
|
#endif
|
|
custom.intena = INTF_SETCLR | INTF_PORTS;
|
|
ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */
|
|
ciaa.cra &= ~(1<<6); /* serial line == input */
|
|
#ifdef DRACO
|
|
}
|
|
#endif
|
|
kbd_softc.k_event_mode = 0;
|
|
kbd_softc.k_events.ev_io = 0;
|
|
splx(s);
|
|
}
|
|
|
|
#ifdef DRACO
|
|
/*
|
|
* call this with kbd interrupt blocked
|
|
*/
|
|
|
|
int
|
|
drkbdgetc(void)
|
|
{
|
|
u_int8_t in;
|
|
|
|
while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
|
|
in = draco_ioct->io_kbddata;
|
|
draco_ioct->io_kbdrst = 0;
|
|
|
|
return in;
|
|
}
|
|
|
|
#define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout
|
|
#define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout
|
|
|
|
int
|
|
drkbdwaitfor(int bit)
|
|
{
|
|
int i;
|
|
|
|
|
|
|
|
i = 60000; /* about 50 ms max */
|
|
|
|
do {
|
|
if ((draco_ioct->io_status & DRSTAT_KBDCLKIN) == bit)
|
|
return 0;
|
|
|
|
} while (--i >= 0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Output a raw byte to the keyboard (+ parity and stop bit).
|
|
* return 0 on success, 1 on timeout.
|
|
*/
|
|
int
|
|
drkbdrputc(u_int8_t c)
|
|
{
|
|
u_int8_t parity;
|
|
int bitcnt;
|
|
|
|
DATLO; CLKHI; WAIT1;
|
|
parity = 0;
|
|
|
|
for (bitcnt=7; bitcnt >= 0; bitcnt--) {
|
|
WAIT0;
|
|
if (c & 1) {
|
|
DATHI;
|
|
} else {
|
|
++parity;
|
|
DATLO;
|
|
}
|
|
c >>= 1;
|
|
WAIT1;
|
|
}
|
|
WAIT0;
|
|
/* parity bit */
|
|
if (parity & 1) {
|
|
DATLO;
|
|
} else {
|
|
DATHI;
|
|
}
|
|
WAIT1;
|
|
/* stop bit */
|
|
WAIT0; DATHI; WAIT1;
|
|
|
|
WAIT0; /* XXX should check the ack bit here... */
|
|
WAIT1;
|
|
draco_ioct->io_kbdrst = 0;
|
|
return 0;
|
|
|
|
Ltimeout:
|
|
DATHI;
|
|
draco_ioct->io_kbdrst = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Output one cooked byte to the keyboard, with wait for ACK or RESEND,
|
|
* and retry if necessary. 0 == success, 1 == timeout
|
|
*/
|
|
int
|
|
drkbdputc(u_int8_t c)
|
|
{
|
|
int rc;
|
|
|
|
do {
|
|
if (drkbdrputc(c))
|
|
return(-1);
|
|
|
|
rc = drkbdgetc();
|
|
} while (rc == 0xfe);
|
|
return (!(rc == 0xfa));
|
|
}
|
|
|
|
/*
|
|
* same for twobyte sequence
|
|
*/
|
|
|
|
int
|
|
drkbdputc2(u_int8_t c1, u_int8_t c2)
|
|
{
|
|
int rc;
|
|
|
|
do {
|
|
do {
|
|
if (drkbdrputc(c1))
|
|
return(-1);
|
|
|
|
rc = drkbdgetc();
|
|
} while (rc == 0xfe);
|
|
if (rc != 0xfa)
|
|
return (-1);
|
|
|
|
if (drkbdrputc(c2))
|
|
return(-1);
|
|
|
|
rc = drkbdgetc();
|
|
} while (rc == 0xfe);
|
|
return (!(rc == 0xfa));
|
|
}
|
|
#endif
|
|
|
|
int
|
|
kbdopen(dev_t dev, int flags, int mode, struct proc *p)
|
|
{
|
|
|
|
kbdenable();
|
|
if (kbd_softc.k_events.ev_io)
|
|
return EBUSY;
|
|
|
|
kbd_softc.k_events.ev_io = p;
|
|
ev_init(&kbd_softc.k_events);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
kbdclose(dev_t dev, int flags, int mode, struct proc *p)
|
|
{
|
|
|
|
/* Turn off event mode, dump the queue */
|
|
kbd_softc.k_event_mode = 0;
|
|
ev_fini(&kbd_softc.k_events);
|
|
kbd_softc.k_events.ev_io = NULL;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
kbdread(dev_t dev, struct uio *uio, int flags)
|
|
{
|
|
return ev_read (&kbd_softc.k_events, uio, flags);
|
|
}
|
|
|
|
int
|
|
kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag,
|
|
struct proc *p)
|
|
{
|
|
register struct kbd_softc *k = &kbd_softc;
|
|
|
|
switch (cmd) {
|
|
case KIOCTRANS:
|
|
if (*(int *)data == TR_UNTRANS_EVENT)
|
|
return 0;
|
|
break;
|
|
|
|
case KIOCGTRANS:
|
|
/* Get translation mode */
|
|
*(int *)data = TR_UNTRANS_EVENT;
|
|
return 0;
|
|
|
|
case KIOCSDIRECT:
|
|
k->k_event_mode = *(int *)data;
|
|
return 0;
|
|
|
|
case FIONBIO: /* we will remove this someday (soon???) */
|
|
return 0;
|
|
|
|
case FIOASYNC:
|
|
k->k_events.ev_async = *(int *)data != 0;
|
|
return 0;
|
|
|
|
case FIOSETOWN:
|
|
if (-*(int *)data != k->k_events.ev_io->p_pgid
|
|
&& *(int *)data != k->k_events.ev_io->p_pid)
|
|
return EPERM;
|
|
return 0;
|
|
|
|
case TIOCSPGRP:
|
|
if (*(int *)data != k->k_events.ev_io->p_pgid)
|
|
return EPERM;
|
|
return 0;
|
|
|
|
default:
|
|
return ENOTTY;
|
|
}
|
|
|
|
/* We identified the ioctl, but we do not handle it. */
|
|
return EOPNOTSUPP; /* misuse, but what the heck */
|
|
}
|
|
|
|
int
|
|
kbdpoll(dev_t dev, int events, struct proc *p)
|
|
{
|
|
return ev_poll (&kbd_softc.k_events, events, p);
|
|
}
|
|
|
|
int
|
|
kbdkqfilter(dev, kn)
|
|
dev_t dev;
|
|
struct knote *kn;
|
|
{
|
|
|
|
return (ev_kqfilter(&kbd_softc.k_events, kn));
|
|
}
|
|
|
|
void
|
|
kbdintr(int mask)
|
|
{
|
|
u_char c;
|
|
#ifdef KBDRESET
|
|
static int reset_warn;
|
|
#endif
|
|
|
|
/*
|
|
* now only invoked from generic CIA interrupt handler if there *is*
|
|
* a keyboard interrupt pending
|
|
*/
|
|
|
|
c = ~ciaa.sdr; /* keyboard data is inverted */
|
|
/* ack */
|
|
ciaa.cra |= (1 << 6); /* serial line output */
|
|
#ifdef KBDRESET
|
|
if (reset_warn && c == 0xf0) {
|
|
#ifdef DEBUG
|
|
printf ("kbdintr: !!!! Reset Warning !!!!\n");
|
|
#endif
|
|
bootsync();
|
|
reset_warn = 0;
|
|
DELAY(30000000);
|
|
}
|
|
#endif
|
|
/* wait 200 microseconds (for bloody Cherry keyboards..) */
|
|
DELAY(2000); /* fudge delay a bit for some keyboards */
|
|
ciaa.cra &= ~(1 << 6);
|
|
|
|
/* process the character */
|
|
c = (c >> 1) | (c << 7); /* rotate right once */
|
|
|
|
#ifdef KBDRESET
|
|
if (c == 0x78) {
|
|
#ifdef DEBUG
|
|
printf ("kbdintr: Reset Warning started\n");
|
|
#endif
|
|
++reset_warn;
|
|
return;
|
|
}
|
|
#endif
|
|
kbdstuffchar(c);
|
|
}
|
|
|
|
#ifdef DRACO
|
|
/* maps MF-II keycodes to Amiga keycodes */
|
|
|
|
const u_char drkbdtab[] = {
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50,
|
|
0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51,
|
|
|
|
0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52,
|
|
0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53,
|
|
|
|
0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54,
|
|
0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55,
|
|
|
|
0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56,
|
|
0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57,
|
|
/* --- */
|
|
0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58,
|
|
0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59,
|
|
|
|
0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff,
|
|
0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff,
|
|
|
|
0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46,
|
|
0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62,
|
|
|
|
0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b,
|
|
0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff,
|
|
/* --- */
|
|
0xff, 0xff, 0xff, 0xff, 0x5d
|
|
};
|
|
#endif
|
|
|
|
|
|
int
|
|
kbdgetcn(void)
|
|
{
|
|
int s;
|
|
u_char ints, mask, c, in;
|
|
|
|
#ifdef DRACO
|
|
if (is_draco() && kbd_softc.k_mf2) {
|
|
do {
|
|
c = 0;
|
|
s = spltty ();
|
|
while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
|
|
in = draco_ioct->io_kbddata;
|
|
draco_ioct->io_kbdrst = 0;
|
|
if (in == 0xF0) { /* release prefix */
|
|
c = 0x80;
|
|
while ((draco_ioct->io_status &
|
|
DRSTAT_KBDRECV) == 0);
|
|
in = draco_ioct->io_kbddata;
|
|
draco_ioct->io_kbdrst = 0;
|
|
}
|
|
splx(s);
|
|
#ifdef DRACORAWKEYDEBUG
|
|
printf("<%02x>", in);
|
|
#endif
|
|
c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in];
|
|
} while (c == 0xff);
|
|
return (c);
|
|
}
|
|
#endif
|
|
s = spltty();
|
|
for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP);
|
|
ints |= mask) ;
|
|
|
|
in = ciaa.sdr;
|
|
c = ~in;
|
|
|
|
/* ack */
|
|
ciaa.cra |= (1 << 6); /* serial line output */
|
|
ciaa.sdr = 0xff; /* ack */
|
|
/* wait 200 microseconds */
|
|
DELAY(2000); /* XXXX only works as long as DELAY doesn't
|
|
* use a timer and waits.. */
|
|
ciaa.cra &= ~(1 << 6);
|
|
ciaa.sdr = in;
|
|
|
|
splx (s);
|
|
c = (c >> 1) | (c << 7);
|
|
|
|
/* take care that no CIA-interrupts are lost */
|
|
if (ints)
|
|
dispatch_cia_ints (0, ints);
|
|
|
|
return c;
|
|
}
|
|
|
|
void
|
|
kbdstuffchar(u_char c)
|
|
{
|
|
struct firm_event *fe;
|
|
struct kbd_softc *k = &kbd_softc;
|
|
int put;
|
|
|
|
#if NWSKBD>0
|
|
/*
|
|
* If we have attached a wskbd and not in polling mode and
|
|
* nobody has opened us directly, then send the keystroke
|
|
* to the wskbd.
|
|
*/
|
|
|
|
if (kbd_softc.k_pollingmode == 0
|
|
&& kbd_softc.k_wskbddev != NULL
|
|
&& k->k_event_mode == 0) {
|
|
wskbd_input(kbd_softc.k_wskbddev,
|
|
KEY_UP(c) ?
|
|
WSCONS_EVENT_KEY_UP :
|
|
WSCONS_EVENT_KEY_DOWN,
|
|
KEY_CODE(c));
|
|
return;
|
|
}
|
|
|
|
#endif /* NWSKBD */
|
|
|
|
/*
|
|
* If not in event mode, deliver straight to ite to process
|
|
* key stroke
|
|
*/
|
|
|
|
if (! k->k_event_mode) {
|
|
#if NITE>0
|
|
ite_filter (c, ITEFILT_TTY);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Keyboard is generating events. Turn this keystroke into an
|
|
* event and put it in the queue. If the queue is full, the
|
|
* keystroke is lost (sorry!).
|
|
*/
|
|
|
|
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) {
|
|
log(LOG_WARNING, "keyboard event queue overflow\n");
|
|
/* ??? */
|
|
return;
|
|
}
|
|
fe->id = KEY_CODE(c);
|
|
fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
|
|
fe->time = time;
|
|
k->k_events.ev_put = put;
|
|
EV_WAKEUP(&k->k_events);
|
|
}
|
|
|
|
|
|
#ifdef DRACO
|
|
void
|
|
drkbdintr(void)
|
|
{
|
|
u_char in;
|
|
struct kbd_softc *k = &kbd_softc;
|
|
|
|
in = draco_ioct->io_kbddata;
|
|
draco_ioct->io_kbdrst = 0;
|
|
|
|
if (in == 0xF0)
|
|
k->k_rlprfx = 0x80;
|
|
else {
|
|
kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff :
|
|
drkbdtab[in] | k->k_rlprfx);
|
|
k->k_rlprfx = 0;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if NWSKBD>0
|
|
/*
|
|
* These are the callback functions that are passed to wscons.
|
|
* They really don't do anything worth noting, just call the
|
|
* other functions above.
|
|
*/
|
|
|
|
int
|
|
kbd_enable(void *c, int on)
|
|
{
|
|
/* Wonder what this is supposed to do... */
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
kbd_set_leds(void *c, int leds)
|
|
{
|
|
}
|
|
|
|
int
|
|
kbd_ioctl(void *c, u_long cmd, caddr_t data, int flag, struct proc *p)
|
|
{
|
|
switch (cmd)
|
|
{
|
|
case WSKBDIO_COMPLEXBELL:
|
|
return 0;
|
|
case WSKBDIO_SETLEDS:
|
|
return 0;
|
|
case WSKBDIO_GETLEDS:
|
|
*(int*)data = 0;
|
|
return 0;
|
|
case WSKBDIO_GTYPE:
|
|
*(u_int*)data = WSKBD_TYPE_AMIGA;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* We are supposed to return EPASSTHROUGH to wscons if we didn't
|
|
* understand.
|
|
*/
|
|
return (EPASSTHROUGH);
|
|
}
|
|
|
|
void
|
|
kbd_getc(void *c, u_int *type, int *data)
|
|
{
|
|
int key;
|
|
|
|
key = kbdgetcn();
|
|
|
|
*data = KEY_CODE(key);
|
|
*type = KEY_UP(key) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
|
|
}
|
|
|
|
void
|
|
kbd_pollc(void *c, int on)
|
|
{
|
|
kbd_softc.k_pollingmode = on;
|
|
}
|
|
|
|
void
|
|
kbd_bell(void *c, u_int x, u_int y, u_int z)
|
|
{
|
|
}
|
|
#endif /* WSKBD */
|