1235 lines
27 KiB
C
1235 lines
27 KiB
C
/*-
|
|
* 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.1 1994/07/08 07:55:49 lkestel Exp $
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* $Log: adbsys.c,v $
|
|
* 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 < 3000000))
|
|
hey++;
|
|
|
|
#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);
|
|
}
|