/*- * 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 #include #include #include #include #include #include #include #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); }