NetBSD/sys/arch/mac68k/dev/adbsys.c

1240 lines
27 KiB
C
Raw Normal View History

/*-
* Copyright (C) 1993, 1994 Allen K. Briggs, Chris P. Caputo,
* Michael L. Finch, Bradley A. Grantham, and
* Lawrence A. Kesteloot
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Alice Group.
* 4. The names of the Alice Group or any of its members may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``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 ALICE GROUP 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.
*
* $Id: adbsys.c,v 1.2 1994/07/09 17:21:13 briggs Exp $
*
*/
/*
* $Log: adbsys.c,v $
* Revision 1.2 1994/07/09 17:21:13 briggs
* Cleanup a printf, raise the probe timeout, and notice if the probe
* does time out.
*
* Revision 1.1 1994/07/08 07:55:49 lkestel
* 6x10.h: shifted font over by two pixels.
* keyboard.h: added constants for commonly used keys and reformatted
* array so that gcc would be happy.
* adbsys.c: new adb system.
* bounds.h: bound-checking macros.
* ite.c: new built-in mini-console.
* 8x14.h: no longer used by built-in console.
* adb.c: replaced by adbsys.c
*
*
* 12/22/93 ~10PM I wrote a new ADB system.
*/
/* I can't believe how much SOFTWARE these guys expected to write */
/* just to get the damn events from the keyboard and mouse!!! */
/* Why couldn't the data just arrive at my doorstep gift-wrapped? */
#include <sys/types.h>
#include <sys/param.h>
#include <machine/param.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <sys/select.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include "../mac68k/via.h"
#include "adbsys.h"
#include "bounds.h"
extern unsigned char keyboard[128][3];
#define spladb splhigh
/* Man, am I paranoid. */
#define ADB_DEBUG 1
/* Fix adb_panic()s */
#if ADB_DEBUG
#define ADB_PANIC(a) adb_panic(a)
#else /* not ADB_DEBUG */
#define ADB_PANIC(a)
#endif /* ADB_DEBUG */
/* ADB subsystem possible states */
#define ADB_SYS_IDLE 0x500
#define ADB_SYS_RESTART 0x100
#define ADB_SYS_BUSY 0x200
#define ADB_SYS_LOOKING 0x300
#define ADB_SYS_NOTREADY 0x400
#define ADB_SYS_CHECKACTIVE 0x600
#define ADB_SYS_PROBING 0x700
#define ADB_SYS_MOVING 0x800
/* state bits for shoving down VIA */
#define ADB_ST_MASK 0x30
#define ADB_ST_IDLE 0x30
#define ADB_ST_EVEN 0x10
#define ADB_ST_ODD 0x20
#define ADB_ST_CMD 0x00
/* fields of ADB command byte */
#define ADB_ADDR_MASK 0xf0
#define ADB_CMD_MASK 0x0C
#define ADB_REG_MASK 0x03
/* possible ADB commands */
#define ADB_CMD_TALK 0x0C
#define ADB_CMD_LISTEN 0x08
#define ADB_CMD_FLUSH 0x01
#define ADB_CMD_RESET 0x00
/* macros for making/extracting ADB command data. */
#define ADB_CMD2ADDR(cmd) (((cmd) & ADB_ADDR_MASK) >> 4)
#define ADB_CMD2CMD(cmd) ((cmd) & ADB_CMD_MASK)
#define ADB_CMD2REG(cmd) ((cmd) & ADB_REG_MASK)
/* note that this macro does no bounds checking. */
#define ADB_MKCMD(addr, cmd, reg) (((addr) << 4) | (cmd) | (reg))
/* ADB device table */
struct adb_dev_s adb_devs[ADB_MAX_DEVS];
/* ADB subsystem state variables */
enum adb_system_e adb_system_type = MacIIADB;
int adb_bus_state = ADB_ST_IDLE; /* What I think ADB bus state is */
int adb_sys_state = ADB_SYS_NOTREADY; /* ADB subsystem state */
int adb_cur_cmd; /* current command *bits* */
int adb_cur_reg; /* current transaction register */
int adb_lastactive = -1; /* last active dev (should we skip?) */
static struct adb_event_s cur_event; /* current event package */
static unsigned char *cur_buf = cur_event.bytes;
/* byte data buffer */
int adb_bytes_sent = 0; /* bytes sent so far */
static int curaddr; /* current probing address */
static int avail; /* last available address */
static int lastmoved; /* where last dev was moved */
#if !defined(ADB_MAX_EVENTS)
#define ADB_MAX_EVENTS 200 /* maybe should be higher for slower macs? */
#endif /* !defined(ADB_MAX_EVENTS) */
static adb_event_t adb_evq[ADB_MAX_EVENTS]; /* ADB event queue */
static int adb_evq_tail = 0; /* event queue tail */
static int adb_evq_len = 0; /* event queue length */
static int adb_isopen = 0; /* Are we queuing events for adb_read? */
int adb_polling = 0; /* Are we polling? (Debugger mode) */
static struct selinfo adb_selinfo; /* select() info */
static struct proc *adb_ioproc = NULL; /* process to wakeup */
static int adb_rptdelay = 13; /* ticks before auto-repeat */
static int adb_rptinterval = 3; /* ticks between auto-repeat */
static int adb_repeating = 0; /* key that is auto-repeating */
static adb_event_t adb_rptevent; /* event to auto-repeat */
void adb_init_II();
void adb_init_PB();
void adb_init_SI();
long adb_intr_II(void);
long adb_intr_PB(void);
long adb_intr_SI(void);
void adb_start_xaction_II(int cmd, int sys_state);
void adb_start_xaction_PB(int cmd, int sys_state);
void adb_start_xaction_SI(int cmd, int sys_state);
extern long (*via1itab[7])();
/* External Entry Points ------------------------- */
void adb_init()
{
/* Interrupt was already set up by machdep.c:set_machdep() */
switch(adb_system_type){
case MacIIADB:
adb_init_II();
break;
case MacIIsiADB:
adb_init_SI();
break;
case MacPBADB:
adb_init_PB();
break;
}
}
long adb_intr()
{
switch(adb_system_type){
case MacIIADB:
return(adb_intr_II());
break;
case MacIIsiADB:
return(adb_intr_SI());
break;
case MacPBADB:
return(adb_intr_PB());
break;
}
return(0);
}
/* Begin a transaction */
void adb_start_xaction(
int cmd,
int sys)
{
switch(adb_system_type){
case MacIIADB:
adb_start_xaction_II(cmd, sys);
break;
case MacIIsiADB:
adb_start_xaction_SI(cmd, sys);
break;
case MacPBADB:
adb_start_xaction_PB(cmd, sys);
break;
}
}
/* Send a device these bytes */
void adb_send(
int dev,
int reg,
int bytecount,
unsigned char *bytes)
{
int i;
while(adb_sys_state != ADB_SYS_IDLE);
for(i = 0; i < bytecount; i++)
cur_buf[i] = bytes[i];
cur_event.byte_count = bytecount;
adb_start_xaction(ADB_MKCMD(dev, ADB_CMD_LISTEN, reg), ADB_SYS_BUSY);
}
int adb_where[2000], adb_index = 0;
#if ADB_DEBUG /* then define debug stuff */
#define W(w) ((adb_index < 2000) ? (adb_where[adb_index++] = w) : 0)
#define W_backup() (adb_index--)
#else /* ! ADB_DEBUG */
#define W(w)
#define W_backup()
#endif /* ADB_DEBUG */
void adb_dump()
{
register int where;
printf("ADB sequence strings: ");
for(where = 0; where < adb_index; where++){
switch(adb_where[where]){
case 0:
printf("Started transaction, device %d, cmd %d, reg %d.\n",
ADB_CMD2ADDR(adb_where[where + 1]), ADB_CMD2CMD(adb_where[where + 1]),
ADB_CMD2REG(adb_where[where + 1]));
where++;
break;
case 0xdd:
printf("Continuing talk, device %d, cmd %d, reg %d.\n",
ADB_CMD2ADDR(adb_where[where + 1]),
ADB_CMD2CMD(adb_where[where + 1]),
ADB_CMD2REG(adb_where[where + 1]));
where++;
break;
case 0xde:
/* interrupt with no data. */
printf("Interrupt with no service request.\n");
break;
case 0xff:
printf("Made bus IDLE.\n");
break;
case 0xaa:
printf("Xaction complete, ");
switch(adb_where[where + 1]){
case 0x91:
printf("bus idle, calling continue_talk.\n");
where++;
break;
case 0x12:
printf("sys busy.\n");
where++;
break;
case 0x23:
printf("SYS_RESTART case.\n");
where++;
break;
case 0x34:
printf("SYS_LOOKING case.");
if(adb_where[where + 2] == 0xed){
printf(" (last possible device had no data!)");
where++;
}
where++;
printf("\n");
break;
case 0x45:
printf("SYS_CHECKACTIVE case.\n");
where++;
break;
}
break;
case 0xbb:
printf("Interrupt: state|int = %02x, ", adb_where[where + 1]);
where ++;
switch(adb_where[where + 1]){
case 0xf1:
printf("ADBSYS not initialized.\n");
where++;
break;
case 0x12:
printf("ST_IDLE.\n");
where++;
break;
case 0x23:
printf("ST_CMD.\n");
where++;
break;
case 0x34:
printf("ST_EVEN, data = %d.\n", adb_where[where + 2]);
where += 2;
break;
case 0x45:
printf("ST_ODD, data = %d.\n", adb_where[where + 2]);
where += 2;
break;
default:
printf("unknown! 0x%x\n", adb_where[where + 1]);
break;
}
}
}
}
void adb_panic(char *str)
{
register int where;
splhigh();
/* panic(str); */
printf("%s\nADB Panicked\n", str);
#if ADB_DEBUG
adb_dump();
printf("waiting forever...\n", str);
while(1);
#else /* not ADB_DEBUG */
panic("ADB failed horribly");
#endif /* ADB_DEBUG */
}
/*----------------------------------------------------------------------------
PowerBook ADB subsystem functions
*/
long adb_intr_PB(void){return(1);}
void adb_init_PB(void){};
void adb_start_xaction_PB(int cmd, int sys_state){};
void adb_finish_xaction_PB(){};
/*----------------------------------------------------------------------------
Macintosh IIsi series ADB subsystem functions
*/
long adb_intr_SI(void){return(1);}
void adb_init_SI(void){};
void adb_start_xaction_SI(int cmd, int sys_state){};
void adb_finish_xaction_SI(){};
/*----------------------------------------------------------------------------
Macintosh II series ADB subsystem functions
*/
int adb_finish_xaction_II();
void adb_start_xaction_II(int cmd, int sys_state);
void adb_make_idle_II();
void adb_start_xaction_II(
int cmd,
int sys_state)
{
register int s;
struct timeval nowtime;
s = spladb();
W(0);
/* make IDLE to kill any existing transactions */
via_reg(VIA1, vDirB) = ADB_ST_MASK;
via_reg(VIA1, vBufB) = ADB_ST_IDLE;
cur_event.addr = ADB_CMD2ADDR(cmd);
microtime(&cur_event.timestamp);
adb_cur_cmd = ADB_CMD2CMD(cmd);
adb_cur_reg = ADB_CMD2REG(cmd);
W(cmd);
if(adb_cur_cmd == ADB_CMD_TALK)
cur_event.byte_count = 0;
adb_sys_state = sys_state;
via_SR_output(VIA1);
via_reg(VIA1, vSR) = cmd;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_CMD;
splx(s);
}
void adb_continue_talk_II(
unsigned char command)
{
if(((via_reg(VIA1, vBufB) & DB1I_vFDBInt) == 0) &&
(ADB_CMD2CMD(command) == ADB_CMD_TALK))
{
W(0xdd);
W(command);
adb_lastactive = cur_event.addr = ADB_CMD2ADDR(command);
adb_cur_cmd = ADB_CMD2CMD(command);
adb_cur_reg = ADB_CMD2REG(command);
cur_event.byte_count = 0;
microtime(&cur_event.timestamp);
adb_sys_state = ADB_SYS_CHECKACTIVE;
via_SR_input(VIA1);
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_EVEN;
}else{
W(0xde);
adb_make_idle_II();
}
}
void adb_make_idle_II()
{
W(0xff);
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_IDLE;
adb_sys_state = ADB_SYS_IDLE;
via_SR_input(VIA1);
adb_lastactive = -1;
}
void adb_init_II()
{
int hey;
static int already = 0;
int are_devs;
if(already != 0){
printf("adb_init(): called to init *again!*\n");
}
already = 1;
#if ADB_DEBUG
printf("Desktop bus initializing...\n");
#endif
for(hey = 0; hey < ADB_MAX_DEVS; hey++) /* 0 & 1 reserved, however */
adb_devs[hey].handler_id = -1; /* there is no device there. */
/* begin peeking! */
adb_start_xaction_II(ADB_MKCMD(2, ADB_CMD_TALK, 3), ADB_SYS_RESTART);
hey = 0;
while((adb_sys_state == ADB_SYS_RESTART) && (hey < 6000000))
hey++;
if (hey >= 6000000) printf("adb_init(): timed out!!!!!\n");
#if 1 /* only kept around for old DESKTOP code */
for(hey = 2; hey < ADB_MAX_DEVS; hey++)
adb_devs[hey].handler_id == -1;
adb_devs[2].handler_id = 2;
adb_devs[2].default_addr = 2;
adb_devs[3].handler_id = 1;
adb_devs[3].default_addr = 3;
#endif
adb_make_idle_II();
are_devs = 0;
#if 1 /* only kept around for old desktop code */
for(hey = 2; hey < ADB_MAX_DEVS; hey++){
if(adb_devs[hey].handler_id != -1){
printf("adb: ");
switch(adb_devs[hey].default_addr){
case 2:
switch(adb_devs[hey].handler_id){
case 1:
printf("ADB keyboard");
break;
case 2:
printf("ADB extended keyboard");
break;
default:
printf("mapped device (%d)", adb_devs[hey].handler_id);
break;
}
break;
case 3:
switch(adb_devs[hey].handler_id){
case 1:
printf("100 dpi mouse");
break;
case 2:
printf("200 dpi mouse");
break;
default:
printf("relative positioning device (mouse?) (%d)", adb_devs[hey].handler_id);
break;
}
break;
case 4:
printf("absolute positioning device (tablet?) (%d)", adb_devs[hey].handler_id);
break;
default:
printf("unknown type device, (def %d, handler %d)", adb_devs[hey].default_addr, adb_devs[hey].handler_id);
break;
}
printf(" at %d\n", hey);
are_devs = 1;
}
}
if(!are_devs)
printf("adb: no devices on bus?\n");
#endif
}
void adb_enqevent(
adb_event_t *event)
{
int s;
if(adb_evq_tail < 0 || adb_evq_tail >= ADB_MAX_EVENTS)
panic("adb: event queue tail is out of bounds");
if(adb_evq_len < 0 || adb_evq_len > ADB_MAX_EVENTS)
panic("adb: event queue len is out of bounds");
s = splhigh();
if(adb_evq_len == ADB_MAX_EVENTS){
splx(s);
return; /* Oh, well... */
}
adb_evq[(adb_evq_len + adb_evq_tail) % ADB_MAX_EVENTS] =
*event;
adb_evq_len++;
selwakeup(&adb_selinfo);
if(adb_ioproc)
psignal(adb_ioproc, SIGIO);
splx(s);
}
void adb_handoff(
adb_event_t *event)
{
if(adb_isopen && !adb_polling){
adb_enqevent(event);
}else{
#if 1
# if 0
printf("adb:l %d %d %d %d %d %d\n", event->addr, event->hand_id,
event->def_addr, event->byte_count, event->bytes[0],
event->bytes[1]);
# endif
if(event->def_addr == 2)
ite_intr(event);
#else /* ADB_EVENTS */
desktop_intr(event);
#endif /* ADB_EVENTS */
}
}
void adb_autorepeat(
void *key)
{
adb_rptevent.bytes[0] |= 0x80;
microtime(&adb_rptevent.timestamp);
adb_handoff(&adb_rptevent); /* do key up */
adb_rptevent.bytes[0] &= 0x7f;
microtime(&adb_rptevent.timestamp);
adb_handoff(&adb_rptevent); /* do key down */
if(adb_repeating){
timeout(adb_autorepeat, (caddr_t)key,
adb_rptinterval);
}
}
void adb_mungesend(
adb_event_t *event)
{
int adb_key;
if(event->def_addr == 2){
if(!(event->u.k.key & 0x80) &&
keyboard[event->u.k.key & 0x7f][0] != 0){
/* ignore shift & control */
if(adb_repeating){
adb_repeating = 0;
untimeout(adb_autorepeat,
(caddr_t)adb_rptevent.u.k.key);
}
adb_key = event->u.k.key & 0x7f;
adb_rptevent = *event;
timeout(adb_autorepeat,
(caddr_t)adb_key, adb_rptdelay);
adb_repeating = 1;
}else{
if(adb_repeating){
adb_repeating = 0;
untimeout(adb_autorepeat,
(caddr_t)adb_rptevent.u.k.key);
}
adb_rptevent = *event;
}
}
adb_handoff(event);
}
void adb_processevent(
adb_event_t *event)
{
int key;
adb_event_t new_event;
new_event = *event;
switch(event->def_addr){
case ADBADDR_KBD:
new_event.u.k.key = event->bytes[0];
new_event.bytes[1] = 0xff;
adb_mungesend(&new_event);
if(event->bytes[1] != 0xff){
new_event.u.k.key = event->bytes[1];
new_event.bytes[0] = event->bytes[1];
new_event.bytes[1] = 0xff;
adb_mungesend(&new_event);
}
break;
case ADBADDR_MS:
new_event.u.m.buttons = ((event->bytes[0] &
0x80) >> 7) ^ 0x1;
new_event.u.m.dx = ((signed int)(event->bytes[1] &
0x3f)) - ((event->bytes[1] &
0x40) ? 64 : 0);
new_event.u.m.dy = ((signed int)(event->bytes[0] &
0x3f)) - ((event->bytes[0] &
0x40) ? 64 : 0);
adb_mungesend(&new_event);
break;
default: /* God only knows. */
adb_mungesend(event);
}
}
int adb_finish_xaction_II()
{
register int cur_dev;
register int address, handler_id;
register int i;
W(0xaa);
switch(adb_sys_state){
case ADB_SYS_IDLE:
W(0x91);
/* whoa. */
ADB_PANIC("adb: timed out when system was IDLE?\n");
break;
case ADB_SYS_BUSY:
W(0x12); /* well, this transaction is over */
/* Tell the nice gentleman that his transaction */
/* timed out */
adb_make_idle_II();
break;
case ADB_SYS_RESTART:
W(0x23); /* well, this guy timed out. */
/* were we waiting for a command or a byte? */
#if 1
if((adb_bus_state == ADB_ST_EVEN ||
adb_bus_state == ADB_ST_ODD) &&
(cur_event.byte_count > 0)){
/* OOoo! Must have completed talk reg 3! */
if(cur_event.byte_count != 2){
ADB_PANIC("adb: someone sent <> 2 bytes from reg 3!\n");
}
if(cur_buf[0] != 0xff){
address = cur_event.addr;
handler_id = cur_buf[1];
CHECKBOUNDS(adb_devs, address);
if(address > 4) /* fake 3 butt mouse */
adb_devs[address].default_addr
= 2;
else
adb_devs[address].default_addr
= address;
adb_devs[address].handler_id = handler_id;
}
}
cur_event.addr++;
if(cur_event.addr == 5)
cur_event.addr = 8;
/* Better check out the next one. */
if(cur_event.addr < 16 ){
adb_start_xaction_II(ADB_MKCMD(cur_event. addr, ADB_CMD_TALK, 3),
ADB_SYS_RESTART);
}else{
adb_make_idle_II();
}
#else /* not 1 */
curaddr = 2;
avail = 15;
lastmoved = -1;
adb_start_xaction_II(ADB_MKCMD(curaddr, ADB_CMD_TALK,
3), ADB_SYS_PROBING);
#endif
break;
case ADB_SYS_LOOKING:
W(0x34);
/* device timed out, but after sending data? */
cur_dev = cur_event.addr;
if(cur_event.byte_count != 0){ /* device had data */
adb_make_idle_II();
cur_event.hand_id =
adb_devs[cur_dev].handler_id;
cur_event.def_addr =
adb_devs[cur_dev].default_addr;
adb_processevent(&cur_event);
adb_make_idle_II();
}else{
cur_dev++;
#if !ADB_DEBUG || 1
while((cur_dev < ADB_MAX_DEVS) &&
(adb_devs[cur_dev].handler_id == -1))
cur_dev++;
#endif /* ADB_DEBUG */
if(cur_dev < /*ADB_MAX_DEVS*/5){
adb_start_xaction_II(ADB_MKCMD(cur_dev, ADB_CMD_TALK, 0),
ADB_SYS_LOOKING);
}else{
/* ADB_PANIC("adb: I got a timeout on the last device"
" that could have had data.\n"); */
W(0xed);
adb_make_idle_II();
}
}
break;
case ADB_SYS_CHECKACTIVE:
W(0x45);
cur_dev = cur_event.addr;
if(cur_event.byte_count != 0){ /* device had data */
adb_make_idle_II();
cur_event.hand_id =
adb_devs[cur_dev].handler_id;
cur_event.def_addr =
adb_devs[cur_dev].default_addr;
adb_processevent(&cur_event);
adb_make_idle_II();
}else{
adb_start_xaction_II(ADB_MKCMD(2, ADB_CMD_TALK, 0),
ADB_SYS_LOOKING);
}
break;
case ADB_SYS_PROBING:
if(cur_event.byte_count == 2){
/* cur_event.byte_count = 2; */
cur_buf[1] = (cur_buf[0] & 0xf0)
| avail;
cur_buf[0] = adb_devs[avail].handler_id;
lastmoved = avail;
avail--;
adb_start_xaction_II(ADB_MKCMD(curaddr,
ADB_CMD_LISTEN, 3), ADB_SYS_MOVING);
}else{
if(lastmoved != -1){
cur_buf[0] = adb_devs[avail].
handler_id;
cur_buf[1] = 0x20 | curaddr;
avail++;
curaddr++;
adb_start_xaction_II(ADB_MKCMD(lastmoved,
ADB_CMD_LISTEN, 3),
ADB_SYS_MOVING);
lastmoved = -1;
}else{
curaddr++;
if(curaddr > 4)
adb_make_idle_II();
else
adb_start_xaction_II(ADB_MKCMD(curaddr, ADB_CMD_TALK, 3), ADB_SYS_PROBING);
}
}
break;
case ADB_SYS_MOVING:
adb_devs[cur_buf[1] & 0xf].handler_id =
adb_devs[cur_event.addr].handler_id;
adb_devs[cur_buf[1] & 0xf].default_addr =
adb_devs[cur_event.addr].default_addr;
if(curaddr > 4)
adb_make_idle_II();
else
adb_start_xaction_II(ADB_MKCMD(curaddr,
ADB_CMD_TALK, 3), ADB_SYS_PROBING);
break;
}
}
/* Macintosh II, IIx, IIcx, SE/30, IIci ADB interrupt */
long adb_intr_II(void)
{
unsigned char bytedata;
int s;
register int cur_dev;
register int address, handler_id;
struct timeval now_time, old_time;
register int diff;
int timedout;
s = spladb();
bytedata = via_reg(VIA1, vSR); /* have to read to clear interrupt */
/* see fig. 12 and 13 in SY6522 docs */
W(0xbb);
W(via_reg(VIA1, vBufB));
if(adb_sys_state == ADB_SYS_NOTREADY){
W_backup(); /* No point in wasting paper. */
W_backup(); /* No point in wasting paper. */
/* W(0xf1); */
splx(s);
return(1);
}
switch(adb_bus_state){
case ADB_ST_IDLE:
W(0x12);
if(adb_sys_state != ADB_SYS_IDLE){
ADB_PANIC("adb: somehow, we got a not IDLE IDLE.\n");
adb_make_idle_II(); /* We're trying to get work done here! */
}else{
adb_continue_talk_II(bytedata);
}
break;
case ADB_ST_CMD:
W(0x23);
if((adb_cur_cmd == ADB_CMD_TALK) ||
(adb_cur_cmd == ADB_CMD_LISTEN)){
if(adb_cur_cmd == ADB_CMD_TALK){ /* Allow data to shift in */
via_SR_input(VIA1);
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_EVEN;
}else{
via_reg(VIA1, vDirB) = ADB_ST_MASK;
via_reg(VIA1, vSR) = cur_buf[0];
adb_bytes_sent = 1;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_EVEN;
}
}else{
adb_make_idle_II();
/* if a reset was sent, we should initiate a RESTART */
if(adb_cur_cmd == ADB_CMD_RESET){
adb_start_xaction_II(ADB_MKCMD(2, ADB_CMD_TALK, 3),
ADB_SYS_RESTART);
}
}
break;
case ADB_ST_EVEN:
W(0x34);
W(bytedata);
if(adb_cur_cmd == ADB_CMD_TALK){
if(((via_reg(VIA1, vBufB) & DB1I_vFDBInt) == 0) ||
(cur_event.byte_count == 8)){
/* There is no data for this byte. */
adb_finish_xaction_II();
}else{
if(cur_event.byte_count < sizeof(cur_buf)){
CHECKBOUNDS(cur_buf, cur_event.byte_count);
cur_buf[cur_event.byte_count++] = bytedata;
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_ODD;
}else{
#if ADB_DEBUG
adb_panic("adb: too many incoming bytes??\n");
#endif /* ADB_DEBUG */
adb_finish_xaction_II();
}
}
}else if(adb_cur_cmd == ADB_CMD_LISTEN){
if(adb_bytes_sent >= cur_event.byte_count)
adb_finish_xaction_II();
via_reg(VIA1, vSR) = cur_buf[adb_bytes_sent++];
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) =
ADB_ST_ODD;
}else{
/* What to do if LISTEN or anything else? */
adb_panic("adb: What am I doing"
" (adb_intr, BUS_EVEN)\n");
}
break;
case ADB_ST_ODD:
W(0x45);
W(bytedata);
if(adb_cur_cmd == ADB_CMD_TALK){
if(((via_reg(VIA1, vBufB) & DB1I_vFDBInt) == 0) ||
(cur_event.byte_count == 8)){
/* There is no data for this byte. */
adb_finish_xaction_II();
}else{
if(cur_event.byte_count < sizeof(cur_buf)){
CHECKBOUNDS(cur_buf, cur_event.byte_count);
cur_buf[cur_event.byte_count++] = bytedata;
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) = ADB_ST_EVEN;
}else{
#if ADB_DEBUG
adb_panic("adb: too many incoming bytes??\n");
#endif /* ADB_DEBUG */
adb_finish_xaction_II();
}
}
}else if(adb_cur_cmd == ADB_CMD_LISTEN){
if(adb_bytes_sent >= cur_event.byte_count)
adb_finish_xaction_II();
via_reg(VIA1, vSR) =
cur_buf[adb_bytes_sent++];
via_reg(VIA1, vDirB) = ADB_ST_MASK;
adb_bus_state = via_reg(VIA1, vBufB) =
ADB_ST_EVEN;
}else{
/* What to do if LISTEN or anything else? */
adb_panic("adb: What am I doing (adb_intr, BUS_ODD)\n");
}
break;
default:
adb_panic("adb: internal bus state defaulted in interrupt.\n");
}
splx(s);
return(1);
}
static void
adbattach(parent, dev, aux)
struct device *parent, *dev;
void *aux;
{
printf(" adb event device.\n");
/* adb_init(); -- called from autoconf... In case ddb needs it? */
}
extern int matchbyname();
struct cfdriver adbcd =
{ NULL,
"adb",
matchbyname,
adbattach,
DV_DULL,
sizeof(struct device),
NULL,
0 };
int adbopen(
dev_t dev,
int flag,
int mode,
struct proc *p)
{
register int unit;
int error = 0;
int s;
unit = minor(dev);
if(unit != 0)
return(ENXIO);
s = splhigh();
if (adb_isopen && p->p_ucred->cr_uid != 0)
{
splx(s);
return(EBUSY);
}
splx(s);
adb_evq_tail = 0;
adb_evq_len = 0;
adb_isopen = 1;
adb_ioproc = p;
return (error);
}
int adbclose(
dev_t dev,
int flag,
int mode,
struct proc *p)
{
register int unit;
int s;
int kbd;
adb_isopen = 0;
adb_ioproc = NULL;
return (0);
}
int adbread(
dev_t dev,
struct uio *uio,
int flag)
{
int s, error;
int willfit;
int total;
int firstmove;
int moremove;
if (uio->uio_resid < sizeof(adb_event_t))
return (EMSGSIZE); /* close enough. */
s = splhigh();
if(adb_evq_len == 0){
splx(s);
return(0);
}
willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
total = (adb_evq_len < willfit) ? adb_evq_len : willfit;
firstmove = (adb_evq_tail + total > ADB_MAX_EVENTS)
? (ADB_MAX_EVENTS - adb_evq_tail) : total;
if(error = uiomove((caddr_t)&adb_evq[adb_evq_tail],
firstmove * sizeof(adb_event_t), uio))
{
splx(s);
return(error);
}
moremove = total - firstmove;
if (moremove > 0)
if(error = uiomove((caddr_t)&adb_evq[0],
moremove * sizeof(adb_event_t), uio))
{
splx(s);
return(error);
}
adb_evq_tail = (adb_evq_tail + total) % ADB_MAX_EVENTS;
adb_evq_len -= total;
splx(s);
return (0);
}
int adbwrite(
dev_t dev,
struct uio *uio,
int flag)
{
return 0;
}
int adbioctl(
dev_t dev,
int cmd,
caddr_t data,
int flag,
struct proc *p)
{
switch(cmd){
case ADBIOC_GETDEVS: {
adb_devinfo_t *di = (void *)data;
int i;
for(i = 0; i < ADB_MAX_DEVS; i++)
di->dev[i] = adb_devs[i];
break;
}
case ADBIOC_SETLIGHTS:{
adb_setlights_t *sl = (void *)data;
unsigned char lights[2];
lights[1] = sl->lights;
adb_send(sl->addr, 2, 2, lights);
break;
}
case ADBIOC_GETREPEAT:{
adb_rptinfo_t *ri = (void *)data;
ri->delay_ticks = adb_rptdelay;
ri->interval_ticks = adb_rptinterval;
break;
}
case ADBIOC_SETREPEAT:{
adb_rptinfo_t *ri = (void *)data;
adb_rptdelay = ri->delay_ticks;
adb_rptinterval = ri->interval_ticks;
break;
}
default:
return(EINVAL);
}
return(0);
}
int adbselect(
dev_t dev,
int rw,
struct proc *p)
{
switch (rw) {
case FREAD:
/* succeed if there is something to read */
if (adb_evq_len > 0)
return (1);
selrecord(p, &adb_selinfo);
break;
case FWRITE:
return (1); /* always fails => never blocks */
break;
}
return (0);
}