extractedLnx/linux/arch/m68k/mac/adb-bus.c_adb_interrupt.c
void adb_interrupt(int irq, void *arg, struct pt_regs *regs)
{
int x, adbdir;
unsigned long flags;
struct adb_request *req;
last_status = status;
/* prevent races due to SCSI enabling ints */
save_flags(flags);
cli();
if (driver_running) {
restore_flags(flags);
return;
}
driver_running = 1;
#ifdef USE_ORIG
status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
#else
if (macintosh_config->adb_type==MAC_ADB_CUDA)
status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT);
else
/* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */
status = (via_read(via1, vBufB) & (ST_MASK|TREQ));
#endif
adbdir = (via_read(via1, vACR) & SR_OUT);
#if (ADBDEBUG & ADBDEBUG_INT)
if (console_loglevel == 10)
printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n",
adb_state, status, last_status, adbdir);
#endif
switch (adb_state)
{
case idle:
if(macintosh_config->adb_type==MAC_ADB_CUDA)
{
/* CUDA has sent us the first byte of data - unsolicited */
if (status != TREQ)
printk("cuda: state=idle, status=%x\n", status);
x = via_read(via1, vSR);
via_write(via1, vBufB, via_read(via1,vBufB)&~TIP);
}
else if(macintosh_config->adb_type==MAC_ADB_IISI)
{
udelay(150);
/* set SR to IN (??? no byte received else) */
via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT);
/* signal start of frame */
via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
/* read first byte */
x = via_read(via1, vSR);
first_byte = x;
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk("adb_macIIsi : receiving unsol. packet: %x (%x %x) ",
x, adb_state, status);
#endif
/* ACK adb chip */
via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
udelay(150);
via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
}
else if(macintosh_config->adb_type==MAC_ADB_II)
{
#if (ADBDEBUG & ADBDEBUG_STATUS)
if (status == TREQ && !adbdir)
/* that's: not IRQ, idle, input -> weird */
printk("adb_macII: idle, status=%x dir=%x\n",
status, adbdir);
#endif
x = via_read(via1, vSR);
first_byte = x;
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk("adb_macII: receiving unsol. packet: %x (%x %x) ",
x, adb_state, status);
#endif
/* set ADB state = even for first data byte */
via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
}
adb_state = reading;
reply_ptr = cuda_rbuf;
reply_len = 0;
reading_reply = 0;
prefix_len = 0;
if (macintosh_config->adb_type==MAC_ADB_II) {
*reply_ptr++ = ADB_PACKET;
*reply_ptr++ = first_byte;
*reply_ptr++ = command_byte; /*first_byte;*/
reply_len = 3;
prefix_len = 3;
}
break;
case awaiting_reply:
if(macintosh_config->adb_type==MAC_ADB_CUDA)
{
/* CUDA has sent us the first byte of data of a reply */
if (status != TREQ)
printk("cuda: state=awaiting_reply, status=%x\n", status);
x = via_read(via1, vSR);
via_write(via1,vBufB,
via_read(via1, vBufB)&~TIP);
}
else if(macintosh_config->adb_type==MAC_ADB_IISI)
{
/* set SR to IN */
via_write(via1, vACR,via_read(via1, vACR)&~SR_OUT);
/* signal start of frame */
via_write(via1, vBufB, via_read(via1, vBufB) | TIP);
/* read first byte */
x = via_read(via1, vSR);
first_byte = x;
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk("adb_macIIsi: reading reply: %x (%x %x) ",
x, adb_state, status);
#endif
#if 0
if( via_read(via1,vBufB) & TREQ)
ending = 1;
else
ending = 0;
#endif
/* ACK adb chip */
via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
udelay(150);
via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
}
else if(macintosh_config->adb_type==MAC_ADB_II)
{
/* handshake etc. for II ?? */
x = via_read(via1, vSR);
first_byte = x;
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk("adb_macII: reading reply: %x (%x %x) ",
x, adb_state, status);
#endif
/* set ADB state = even for first data byte */
via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
}
adb_state = reading;
reply_ptr = current_req->reply;
reading_reply = 1;
reply_len = 0;
prefix_len = 0;
if (macintosh_config->adb_type==MAC_ADB_II) {
*reply_ptr++ = ADB_PACKET;
*reply_ptr++ = first_byte;
*reply_ptr++ = first_byte; /* should be command byte */
reply_len = 3;
prefix_len = 3;
}
break;
case sent_first_byte:
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk(" sending: %x (%x %x) ",
current_req->data[1], adb_state, status);
#endif
if(macintosh_config->adb_type==MAC_ADB_CUDA)
{
if (status == TREQ + TIP + SR_OUT)
{
/* collision */
via_write(via1, vACR,
via_read(via1, vACR)&~SR_OUT);
x = via_read(via1, vSR);
via_write(via1, vBufB,
via_read(via1,vBufB)|TIP|TACK);
adb_state = idle;
}
else
{
/* assert status == TIP + SR_OUT */
if (status != TIP + SR_OUT)
printk("cuda: state=sent_first_byte status=%x\n", status);
via_write(via1,vSR,current_req->data[1]);
via_write(via1, vBufB,
via_read(via1, vBufB)^TACK);
data_index = 2;
adb_state = sending;
}
}
else if(macintosh_config->adb_type==MAC_ADB_IISI)
{
/* switch ACK off */
via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
if ( !(via_read(via1, vBufB) & TREQ) )
{
/* collision */
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk("adb_macIIsi: send collison, aborting!\n");
#endif
/* set shift in */
via_write(via1, vACR,
via_read(via1, vACR)&~SR_OUT);
/* clear SR int. */
x = via_read(via1, vSR);
/* set ADB state to 'idle' */
via_write(via1, vBufB,
via_read(via1,vBufB) & ~(TIP|TACK));
adb_state = idle;
}
else
{
/* delay */
udelay(ADB_DELAY);
/* set the shift register to shift out and send a byte */
#if 0
via_write(via1, vACR, via_read(via1, vACR) | SR_OUT);
#endif
via_write(via1, vSR, current_req->data[1]);
/* signal 'byte ready' */
via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
data_index=2;
adb_state = sending;
}
}
else if(macintosh_config->adb_type==MAC_ADB_II)
{
/* how to detect a collision here ?? */
/* maybe we're already done (Talk, or Poll)? */
if (data_index >= current_req->nbytes)
{
/* assert it's a Talk ?? */
if ( (command_byte&0xc) != 0xc
&& console_loglevel == 10 )
printk("ADB: single byte command, no Talk: %x!\n",
command_byte);
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk(" -> end (%d of %d) (%x %x)!\n",
data_index, current_req->nbytes, adb_state, status);
#endif
current_req->sent = 1;
if (current_req->reply_expected)
{
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk("ADB: reply expected on poll!\n");
#endif
adb_state = awaiting_reply;
reading_reply = 0;
} else {
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk("ADB: no reply for poll, not calling done()!\n");
#endif
req = current_req;
current_req = req->next;
#if 0 /* XXX Not sure about that one ... probably better enabled */
if (req->done)
(*req->done)(req);
#endif
adb_state = idle;
reading_reply = 0;
}
/* set to shift in */
via_write(via1, vACR,
via_read(via1, vACR) & ~SR_OUT);
x=via_read(via1, vSR);
/* set ADB state idle - might get SRQ */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
break;
}
#if (ADBDEBUG & ADBDEBUG_STATUS)
if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT))
printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n",
status, adbdir);
#endif
/* SR already set to shift out; send byte */
via_write(via1, vSR, current_req->data[1]);
/* set state to ST_EVEN (first byte was: ST_CMD) */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
data_index=2;
adb_state = sending;
}
break;
case sending:
req = current_req;
if (data_index >= req->nbytes)
{
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk(" -> end (%d of %d) (%x %x)!\n",
data_index-1, req->nbytes, adb_state, status);
#endif
/* end of packet */
if(macintosh_config->adb_type==MAC_ADB_CUDA)
{
via_write(via1, vACR,
via_read(via1, vACR)&~SR_OUT);
x = via_read(via1, vSR);
via_write(via1, vBufB,
via_read(via1,vBufB)|TACK|TIP);
}
else if(macintosh_config->adb_type==MAC_ADB_IISI)
{
/* XXX maybe clear ACK here ??? */
/* switch ACK off */
via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
/* delay */
udelay(ADB_DELAY);
/* set the shift register to shift in */
via_write(via1, vACR, via_read(via1, vACR)|SR_OUT);
/* clear SR int. */
x = via_read(via1, vSR);
/* set ADB state 'idle' (end of frame) */
via_write(via1, vBufB,
via_read(via1,vBufB) & ~(TACK|TIP));
}
else if(macintosh_config->adb_type==MAC_ADB_II)
{
/*
* XXX Not sure: maybe only switch to
* input mode on Talk ??
*/
/* set to shift in */
via_write(via1, vACR,
via_read(via1, vACR) & ~SR_OUT);
x=via_read(via1, vSR);
/* set ADB state idle - might get SRQ */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
}
req->sent = 1;
if (req->reply_expected)
{
/*
* maybe fake a reply here on Listen ??
* Otherwise, a Listen hangs on success
*/
if ( macintosh_config->adb_type==MAC_ADB_II
&& ((req->data[0]&0xc) == 0xc) )
adb_state = awaiting_reply;
else if ( macintosh_config->adb_type != MAC_ADB_II
&& ( req->data[0] == 0x0)
&& ((req->data[1]&0xc) == 0xc) )
adb_state = awaiting_reply;
else {
/*
* Reply expected, but none
* possible -> fake reply.
* Problem: sending next command
* should probably be done
* without setting bus to 'idle'!
* (except if no more commands)
*/
#if (ADBDEBUG & ADBDEBUG_PROT)
printk("ADB: reply expected on Listen, faking reply\n");
#endif
/* make it look weird */
/* XXX: return reply_len -1? */
/* XXX: fake ADB header? */
req->reply[0] = req->reply[1] = req->reply[2] = 0xFF;
req->reply_len = 3;
req->got_reply = 1;
current_req = req->next;
if (req->done)
(*req->done)(req);
/*
* ready with this one, run
* next command or repeat last
* Talk (=idle on II)
*/
/* set state to idle !! */
adb_state = idle;
if (current_req || retry_req)
adb_start();
}
}
else
{
current_req = req->next;
if (req->done)
(*req->done)(req);
/* not sure about this */
/*
* MS: Must set idle, no new request
* started else !
*/
adb_state = idle;
/*
* requires setting ADB state to idle,
* maybe read a byte ! (done above)
*/
if (current_req || retry_req)
adb_start();
}
}
else
{
#if (ADBDEBUG & ADBDEBUG_WRITE)
if (console_loglevel == 10)
printk(" %x (%x %x) ",
req->data[data_index], adb_state, status);
#endif
if(macintosh_config->adb_type==MAC_ADB_CUDA)
{
via_write(via1, vSR, req->data[data_index++]);
via_write(via1, vBufB,
via_read(via1, vBufB)^TACK);
}
else if(macintosh_config->adb_type==MAC_ADB_IISI)
{
/* switch ACK off */
via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
/* delay */
udelay(ADB_DELAY);
/* XXX: need to check for collision?? */
/* set the shift register to shift out and send a byte */
#if 0
via_write(via1, vACR, via_read(via1, vACR)|SR_OUT);
#endif
via_write(via1, vSR, req->data[data_index++]);
/* signal 'byte ready' */
via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
}
else if(macintosh_config->adb_type==MAC_ADB_II)
{
via_write(via1, vSR, req->data[data_index++]);
/* invert state bits, toggle ODD/EVEN */
x = via_read(via1, vBufB);
via_write(via1, vBufB,
(x&~ST_MASK)|~(x&ST_MASK));
}
}
break;
case reading:
/* timeout / SRQ handling for II hw */
#ifdef POLL_ON_TIMEOUT
if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
#else
if( (first_byte == 0xFF && (reply_len-prefix_len)==2
&& memcmp(reply_ptr-2,"\xFF\xFF",2)==0) ||
((reply_len-prefix_len)==3
&& memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
#endif
{
/*
* possible timeout (in fact, most probably a
* timeout, since SRQ can't be signaled without
* transfer on the bus).
* The last three bytes seen were FF, together
* with the starting byte (in case we started
* on 'idle' or 'awaiting_reply') this probably
* makes four. So this is mostl likely #5!
* The timeout signal is a pattern 1 0 1 0 0..
* on /INT, meaning we missed it :-(
*/
x = via_read(via1, vSR);
if (x != 0xFF)
printk("ADB: mistaken timeout/SRQ!\n");
/*
* ADB status bits: either even or odd.
* adb_state: need to set 'idle' here.
* Maybe saner: set 'need_poll' or
* 'need_resend' here, fall through to
* read_done ??
*/
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk(" -> read aborted: %x (%x %x)!\n",
x, adb_state, status);
#endif
#if 0 /* XXX leave status unchanged!! - need to check this again! */
/* XXX Only touch status on II !!! */
/* set ADB state to idle (required by adb_start()) */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
#endif
/*
* What if the timeout happens on reading a
* reply ?? Assemble error reply and call
* current_request->done()? Keep request
* on queue?
*/
/* prevent 'busy' in adb_start() */
need_poll = 1;
/*
* Timeout: /IRQ alternates high/low during
* 4 'FF' bytes (1 0 1 0 0...)
* We're on byte 5, so we need one
* more backlog here (TBI) ....
*/
if ((status&TREQ) != (last_status&TREQ)) {
#if (ADBDEBUG & ADBDEBUG_SRQ)
if (console_loglevel == 10)
printk("ADB: reply timeout, resending!\n");
#endif
/*
* first byte received should be the
* command byte timing out !!
*/
if (first_byte != 0xff)
command_byte = first_byte;
/*
* compute target for retransmit: if
* last_active is set, use that one,
* else use command_byte
*/
if (last_active == -1)
last_active = (command_byte&0xf0)>>4;
adb_state = idle;
/* resend if TALK, don't poll! */
if (current_req)
adb_start();
else
/*
* XXX: need to count the timeouts ??
* restart last active TALK ??
* If no current_req, reuse old one!
*/
adb_retransmit(last_active);
} else {
/*
* SRQ: NetBSD suggests /IRQ is asserted!?
*/
if (status&TREQ)
printk("ADB: SRQ signature w/o /INT!\n");
#if (ADBDEBUG & ADBDEBUG_SRQ)
if (console_loglevel == 10)
printk("ADB: empty SRQ packet!\n");
#endif
/* Terminate the SRQ packet and poll */
adb_state = idle;
adb_queue_poll();
}
/*
* Leave ADB status lines unchanged (means /IRQ
* will still be low when entering adb_start!)
*/
break;
}
/* end timeout / SRQ handling for II hw. */
if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
{
/* SRQ tacked on data packet */
/* Check /IRQ here ?? */
#if (ADBDEBUG & ADBDEBUG_SRQ)
if (console_loglevel == 10)
printk("\nADB: Packet with SRQ!\n");
#endif
/* Terminate the packet (SRQ never ends) */
x = via_read(via1, vSR);
adb_state = read_done;
reply_len -= 3;
reply_ptr -= 3;
need_poll = 1;
/* need to continue; next byte not seen else */
/*
* XXX: not at all sure here; maybe need to
* send away the reply and poll immediately?
*/
} else {
/* Sanity check */
if(reply_len>15)
reply_len=0;
/* read byte */
*reply_ptr = via_read(via1, vSR);
x = *reply_ptr;
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk(" %x (%x %x) ",
*reply_ptr, adb_state, status);
#endif
reply_ptr++;
reply_len++;
}
/* The usual handshake ... */
if (macintosh_config->adb_type==MAC_ADB_CUDA)
{
if (status == TIP)
{
/* that's all folks */
via_write(via1, vBufB,
via_read(via1, vBufB)|TACK|TIP);
adb_state = read_done;
}
else
{
/* assert status == TIP | TREQ */
if (status != TIP + TREQ)
printk("cuda: state=reading status=%x\n", status);
via_write(via1, vBufB,
via_read(via1, vBufB)^TACK);
}
}
else if (macintosh_config->adb_type==MAC_ADB_IISI)
{
/* ACK adb chip (maybe check for end first?) */
via_write(via1, vBufB, via_read(via1, vBufB) | TACK);
udelay(150);
via_write(via1, vBufB, via_read(via1, vBufB) & ~TACK);
/* end of frame?? */
if (status & TREQ)
{
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk("adb_IIsi: end of frame!\n");
#endif
/* that's all folks */
via_write(via1, vBufB,
via_read(via1, vBufB) & ~(TACK|TIP));
adb_state = read_done;
/* maybe process read_done here?? Handshake anyway?? */
}
}
else if (macintosh_config->adb_type==MAC_ADB_II)
{
/*
* NetBSD hints that the next to last byte
* is sent with IRQ !!
* Guido found out it's the last one (0x0),
* but IRQ should be asserted already.
* Problem with timeout detection: First
* transition to /IRQ might be second
* byte of timeout packet!
* Timeouts are signaled by 4x FF.
*/
if(!(status&TREQ) && x == 0x00) /* != 0xFF */
{
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk(" -> read done!\n");
#endif
#if 0 /* XXX: we take one more byte (why?), so handshake! */
/* set ADB state to idle */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
#else
/* invert state bits, toggle ODD/EVEN */
x = via_read(via1, vBufB);
via_write(via1, vBufB,
(x&~ST_MASK)|~(x&ST_MASK));
#endif
/* adjust packet length */
reply_len--;
reply_ptr--;
adb_state = read_done;
}
else
{
#if (ADBDEBUG & ADBDEBUG_STATUS)
if(status!=TIP+TREQ)
printk("macII_adb: state=reading status=%x\n", status);
#endif
/* not caught: ST_CMD */
/* required for re-entry 'reading'! */
if ((status&ST_MASK) == ST_IDLE) {
/* (in)sanity check - set even */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_EVEN);
} else {
/* invert state bits, toggle ODD/EVEN */
x = via_read(via1, vBufB);
via_write(via1, vBufB,
(x&~ST_MASK)|~(x&ST_MASK));
}
}
}
break;
case read_done:
x = via_read(via1, vSR);
#if (ADBDEBUG & ADBDEBUG_READ)
if (console_loglevel == 10)
printk("ADB: read done: %x (%x %x)!\n",
x, adb_state, status);
#endif
if (reading_reply)
{
req = current_req;
req->reply_len = reply_ptr - req->reply;
req->got_reply = 1;
current_req = req->next;
if (req->done)
(*req->done)(req);
}
else
{
adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
}
/*
* remember this device ID; it's the latest we got a
* reply from!
*/
last_reply = command_byte;
last_active = (command_byte&0xf0)>>4;
/*
* Assert status = ST_IDLE ??
*/
/*
* SRQ seen before, initiate poll now
*/
if (need_poll) {
#if (ADBDEBUG & ADBDEBUG_POLL)
if (console_loglevel == 10)
printk("ADB: initiate poll!\n");
#endif
adb_state = idle;
/*
* set ADB status bits?? (unchanged above!)
*/
adb_queue_poll();
need_poll = 0;
/* hope this is ok; queue_poll runs adb_start */
break;
}
/*
* /IRQ seen, so the ADB controller has data for us
*/
if (!(status&TREQ))
{
/* set ADB state to idle */
via_write(via1, vBufB,
(via_read(via1, vBufB)&~ST_MASK)|ST_IDLE);
adb_state = reading;
reply_ptr = cuda_rbuf;
reply_len = 0;
prefix_len = 0;
if (macintosh_config->adb_type==MAC_ADB_II) {
*reply_ptr++ = ADB_PACKET;
*reply_ptr++ = command_byte;
reply_len = 2;
prefix_len = 2;
}
reading_reply = 0;
}
else
{
/*
* no IRQ, send next packet or wait
*/
adb_state = idle;
if (current_req)
adb_start();
else
adb_retransmit(last_active);
}
break;
default:
#if (ADBDEBUG & ADBDEBUG_STATE)
printk("adb_interrupt: unknown adb_state %d?\n", adb_state);
#endif
}
/* reset mutex and interrupts */
driver_running = 0;
restore_flags(flags);
}
Generated by GNU enscript 1.6.4.