/*
* 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
*/
/*
* If NWSKBD>0 we try to attach a 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.
*/
/*ARGSUSED*/
int
kbdmatch(device_t parent, cfdata_t cf, void *aux)
{
if (matchname((char *)aux, "kbd"))
return(1);
return(0);
}
/*ARGSUSED*/
void
kbdattach(device_t parent, device_t self, void *aux)
{
#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
/*
* This is called when somebody wants to use kbd as the console keyboard.
*/
void
kbd_cnattach(void)
{
#if NWSKBD>0
wskbd_cnattach(&kbd_consops, NULL, &kbd_mapdata);
kbd_softc.k_console = 1;
#endif
}
#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;
#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;
/*
* 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;
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(200); /* 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.
*/
/*
* 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!).
*/
#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, void *data, int flag, struct lwp *l)
{
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;