Commit d95fd5fc authored by Finn Thain's avatar Finn Thain Committed by Linus Torvalds

m68k: Mac II ADB fixes

Fix a crash caused by requests placed in the queue with the completed flag
already set. This lead to some ADB_SYNC requests returning early and their
request structs being popped off the stack while still queued. Stack corruption
ensued or an invalid request callback pointer was invoked or both. Eliminate
macii_retransmit() and its buggy implementation of macii_write(). Have
macii_queue_poll() fully initialise the request queues.

Fix a bug in macii_queue_poll() where the last_req pointer was not being set.
This caused some requests to leave the queue before being completed (and would
also corrupt the stack under certain conditions).

Fix a race in macii_start that could set the state machine to "reading" while
current_req was null.

No longer send poll commands with the ADBREQ_REPLY flag -- doing that caused
the replies to be stored in the request buffer where they were forgotten
about.

Don't autopoll by continuously sending new Talk commands. Get the controller to
do that for us. This reduces the ADB interrupt rate on an idle bus to about 5
per second. Only autopoll the devices that were probed.

Explicitly clear the interrupt flag when polling.

Use disable_irq rather than local_irq_save when polling.

Remove excess local_irq_save/restore pairs.

Improve bus timeout and service request detection.

Remove unused code (last_reply, adb_dir etc) and unneeded code (prefix_len,
first_byte etc).

Change TIP and TACK to their correct names on this ADB controller (ST_EVEN and
ST_ODD).

Add some commentry.

Add a generous quantity of sanity checks (BUG_ONs).

Let m68k macs use the adb_sync boot param too.

Tested on Mac II, Mac IIci, Quadra 650, Quadra 700 etc.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 217f6710
...@@ -513,3 +513,13 @@ void check_bugs(void) ...@@ -513,3 +513,13 @@ void check_bugs(void)
} }
#endif /* !CONFIG_M68KFPU_EMU */ #endif /* !CONFIG_M68KFPU_EMU */
} }
#ifdef CONFIG_ADB
static int __init adb_probe_sync_enable (char *str) {
extern int __adb_probe_sync;
__adb_probe_sync = 1;
return 1;
}
__setup("adb_sync", adb_probe_sync_enable);
#endif /* CONFIG_ADB */
...@@ -12,6 +12,15 @@ ...@@ -12,6 +12,15 @@
* 1999-08-02 (jmt) - Initial rewrite for Unified ADB. * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
* 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org> * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
* - Big overhaul, should actually work now. * - Big overhaul, should actually work now.
* 2006-12-31 Finn Thain <fthain@telegraphics.com.au> - Another overhaul.
*
* Suggested reading:
* Inside Macintosh, ch. 5 ADB Manager
* Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus
* Rockwell R6522 VIA datasheet
*
* Apple's "ADB Analyzer" bus sniffer is invaluable:
* ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
*/ */
#include <stdarg.h> #include <stdarg.h>
...@@ -26,7 +35,6 @@ ...@@ -26,7 +35,6 @@
#include <asm/macints.h> #include <asm/macints.h>
#include <asm/machw.h> #include <asm/machw.h>
#include <asm/mac_via.h> #include <asm/mac_via.h>
#include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
static volatile unsigned char *via; static volatile unsigned char *via;
...@@ -51,9 +59,7 @@ static volatile unsigned char *via; ...@@ -51,9 +59,7 @@ static volatile unsigned char *via;
#define ANH (15*RS) /* A-side data, no handshake */ #define ANH (15*RS) /* A-side data, no handshake */
/* Bits in B data register: all active low */ /* Bits in B data register: all active low */
#define TREQ 0x08 /* Transfer request (input) */ #define CTLR_IRQ 0x08 /* Controller rcv status (input) */
#define TACK 0x10 /* Transfer acknowledge (output) */
#define TIP 0x20 /* Transfer in progress (output) */
#define ST_MASK 0x30 /* mask for selecting ADB state bits */ #define ST_MASK 0x30 /* mask for selecting ADB state bits */
/* Bits in ACR */ /* Bits in ACR */
...@@ -65,8 +71,6 @@ static volatile unsigned char *via; ...@@ -65,8 +71,6 @@ static volatile unsigned char *via;
#define IER_SET 0x80 /* set bits in IER */ #define IER_SET 0x80 /* set bits in IER */
#define IER_CLR 0 /* clear bits in IER */ #define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */ #define SR_INT 0x04 /* Shift register full/empty */
#define SR_DATA 0x08 /* Shift register data */
#define SR_CLOCK 0x10 /* Shift register clock */
/* ADB transaction states according to GMHW */ /* ADB transaction states according to GMHW */
#define ST_CMD 0x00 /* ADB state: command byte */ #define ST_CMD 0x00 /* ADB state: command byte */
...@@ -77,7 +81,6 @@ static volatile unsigned char *via; ...@@ -77,7 +81,6 @@ static volatile unsigned char *via;
static int macii_init_via(void); static int macii_init_via(void);
static void macii_start(void); static void macii_start(void);
static irqreturn_t macii_interrupt(int irq, void *arg); static irqreturn_t macii_interrupt(int irq, void *arg);
static void macii_retransmit(int);
static void macii_queue_poll(void); static void macii_queue_poll(void);
static int macii_probe(void); static int macii_probe(void);
...@@ -103,29 +106,37 @@ static enum macii_state { ...@@ -103,29 +106,37 @@ static enum macii_state {
sending, sending,
reading, reading,
read_done, read_done,
awaiting_reply
} macii_state; } macii_state;
static int need_poll; static struct adb_request *current_req; /* first request struct in the queue */
static int command_byte; static struct adb_request *last_req; /* last request struct in the queue */
static int last_reply; static unsigned char reply_buf[16]; /* storage for autopolled replies */
static int last_active; static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */
static int reading_reply; /* store reply in reply_buf else req->reply */
static struct adb_request *current_req; static int data_index; /* index of the next byte to send from req->data */
static struct adb_request *last_req; static int reply_len; /* number of bytes received in reply_buf or req->reply */
static struct adb_request *retry_req; static int status; /* VIA's ADB status bits captured upon interrupt */
static unsigned char reply_buf[16]; static int last_status; /* status bits as at previous interrupt */
static unsigned char *reply_ptr; static int srq_asserted; /* have to poll for the device that asserted it */
static int reply_len; static int command_byte; /* the most recent command byte transmitted */
static int reading_reply; static int autopoll_devs; /* bits set are device addresses to be polled */
static int data_index;
static int first_byte; /* Sanity check for request queue. Doesn't check for cycles. */
static int prefix_len; static int request_is_queued(struct adb_request *req) {
static int status = ST_IDLE|TREQ; struct adb_request *cur;
static int last_status; unsigned long flags;
static int driver_running; local_irq_save(flags);
cur = current_req;
/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ while (cur) {
if (cur == req) {
local_irq_restore(flags);
return 1;
}
cur = cur->next;
}
local_irq_restore(flags);
return 0;
}
/* Check for MacII style ADB */ /* Check for MacII style ADB */
static int macii_probe(void) static int macii_probe(void)
...@@ -147,15 +158,16 @@ int macii_init(void) ...@@ -147,15 +158,16 @@ int macii_init(void)
local_irq_save(flags); local_irq_save(flags);
err = macii_init_via(); err = macii_init_via();
if (err) return err; if (err) goto out;
err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
macii_interrupt); macii_interrupt);
if (err) return err; if (err) goto out;
macii_state = idle; macii_state = idle;
out:
local_irq_restore(flags); local_irq_restore(flags);
return 0; return err;
} }
/* initialize the hardware */ /* initialize the hardware */
...@@ -163,12 +175,12 @@ static int macii_init_via(void) ...@@ -163,12 +175,12 @@ static int macii_init_via(void)
{ {
unsigned char x; unsigned char x;
/* Set the lines up. We want TREQ as input TACK|TIP as output */ /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */
via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ;
/* Set up state: idle */ /* Set up state: idle */
via[B] |= ST_IDLE; via[B] |= ST_IDLE;
last_status = via[B] & (ST_MASK|TREQ); last_status = via[B] & (ST_MASK|CTLR_IRQ);
/* Shift register on input */ /* Shift register on input */
via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
...@@ -179,81 +191,72 @@ static int macii_init_via(void) ...@@ -179,81 +191,72 @@ static int macii_init_via(void)
return 0; return 0;
} }
/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */ /* Send an ADB poll (Talk Register 0 command prepended to the request queue) */
static void macii_queue_poll(void) static void macii_queue_poll(void)
{ {
static int device = 0; /* No point polling the active device as it will never assert SRQ, so
static int in_poll=0; * poll the next device in the autopoll list. This could leave us
* stuck in a polling loop if an unprobed device is asserting SRQ.
* In theory, that could only happen if a device was plugged in after
* probing started. Unplugging it again will break the cycle.
* (Simply polling the next higher device often ends up polling almost
* every device (after wrapping around), which takes too long.)
*/
int device_mask;
int next_device;
static struct adb_request req; static struct adb_request req;
unsigned long flags;
if (in_poll) printk("macii_queue_poll: double poll!\n"); if (!autopoll_devs) return;
in_poll++; device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1;
if (++device > 15) device = 1; if (autopoll_devs & ~device_mask)
next_device = ffs(autopoll_devs & ~device_mask) - 1;
else
next_device = ffs(autopoll_devs) - 1;
adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, BUG_ON(request_is_queued(&req));
ADB_READREG(device, 0));
local_irq_save(flags); adb_request(&req, NULL, ADBREQ_NOSEND, 1,
ADB_READREG(next_device, 0));
req.sent = 0;
req.complete = 0;
req.reply_len = 0;
req.next = current_req; req.next = current_req;
current_req = &req;
local_irq_restore(flags);
macii_start();
in_poll--;
}
/* Send an ADB retransmit (Talk, appended to the request queue) */
static void macii_retransmit(int device)
{
static int in_retransmit = 0;
static struct adb_request rt;
unsigned long flags;
if (in_retransmit) printk("macii_retransmit: double retransmit!\n");
in_retransmit++;
adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
ADB_READREG(device, 0));
local_irq_save(flags);
if (current_req != NULL) { if (current_req != NULL) {
last_req->next = &rt; current_req = &req;
last_req = &rt;
} else { } else {
current_req = &rt; current_req = &req;
last_req = &rt; last_req = &req;
} }
if (macii_state == idle) macii_start();
local_irq_restore(flags);
in_retransmit--;
} }
/* Send an ADB request; if sync, poll out the reply 'till it's done */ /* Send an ADB request; if sync, poll out the reply 'till it's done */
static int macii_send_request(struct adb_request *req, int sync) static int macii_send_request(struct adb_request *req, int sync)
{ {
int i; int err;
unsigned long flags;
BUG_ON(request_is_queued(req));
i = macii_write(req); local_irq_save(flags);
if (i) return i; err = macii_write(req);
local_irq_restore(flags);
if (sync) { if (!err && sync) {
while (!req->complete) macii_poll(); while (!req->complete) {
macii_poll();
} }
return 0; BUG_ON(request_is_queued(req));
}
return err;
} }
/* Send an ADB request */ /* Send an ADB request (append to request queue) */
static int macii_write(struct adb_request *req) static int macii_write(struct adb_request *req)
{ {
unsigned long flags;
if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) { if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
req->complete = 1; req->complete = 1;
return -EINVAL; return -EINVAL;
...@@ -264,8 +267,6 @@ static int macii_write(struct adb_request *req) ...@@ -264,8 +267,6 @@ static int macii_write(struct adb_request *req)
req->complete = 0; req->complete = 0;
req->reply_len = 0; req->reply_len = 0;
local_irq_save(flags);
if (current_req != NULL) { if (current_req != NULL) {
last_req->next = req; last_req->next = req;
last_req = req; last_req = req;
...@@ -274,28 +275,52 @@ static int macii_write(struct adb_request *req) ...@@ -274,28 +275,52 @@ static int macii_write(struct adb_request *req)
last_req = req; last_req = req;
if (macii_state == idle) macii_start(); if (macii_state == idle) macii_start();
} }
local_irq_restore(flags);
return 0; return 0;
} }
/* Start auto-polling */ /* Start auto-polling */
static int macii_autopoll(int devs) static int macii_autopoll(int devs)
{ {
/* Just ping a random default address */ static struct adb_request req;
if (!(current_req || retry_req)) unsigned long flags;
macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3); int err = 0;
/* bit 1 == device 1, and so on. */
autopoll_devs = devs & 0xFFFE;
if (!autopoll_devs) return 0;
local_irq_save(flags);
if (current_req == NULL) {
/* Send a Talk Reg 0. The controller will repeatedly transmit
* this as long as it is idle.
*/
adb_request(&req, NULL, ADBREQ_NOSEND, 1,
ADB_READREG(ffs(autopoll_devs) - 1, 0));
err = macii_write(&req);
}
local_irq_restore(flags);
return err;
}
static inline int need_autopoll(void) {
/* Was the last command Talk Reg 0
* and is the target on the autopoll list?
*/
if ((command_byte & 0x0F) == 0x0C &&
((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs))
return 0; return 0;
return 1;
} }
/* Prod the chip without interrupts */ /* Prod the chip without interrupts */
static void macii_poll(void) static void macii_poll(void)
{ {
unsigned long flags; disable_irq(IRQ_MAC_ADB);
macii_interrupt(0, NULL);
local_irq_save(flags); enable_irq(IRQ_MAC_ADB);
if (via[IFR] & SR_INT) macii_interrupt(0, NULL);
local_irq_restore(flags);
} }
/* Reset the bus */ /* Reset the bus */
...@@ -303,72 +328,33 @@ static int macii_reset_bus(void) ...@@ -303,72 +328,33 @@ static int macii_reset_bus(void)
{ {
static struct adb_request req; static struct adb_request req;
if (request_is_queued(&req))
return 0;
/* Command = 0, Address = ignored */ /* Command = 0, Address = ignored */
adb_request(&req, NULL, 0, 1, ADB_BUSRESET); adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
/* Don't want any more requests during the Global Reset low time. */
udelay(3000);
return 0; return 0;
} }
/* Start sending ADB packet */ /* Start sending ADB packet */
static void macii_start(void) static void macii_start(void)
{ {
unsigned long flags;
struct adb_request *req; struct adb_request *req;
req = current_req; req = current_req;
if (!req) return;
/* assert macii_state == idle */ BUG_ON(req == NULL);
if (macii_state != idle) {
printk("macii_start: called while driver busy (%p %x %x)!\n",
req, macii_state, (uint) via1[B] & (ST_MASK|TREQ));
return;
}
local_irq_save(flags); BUG_ON(macii_state != idle);
/* /* Now send it. Be careful though, that first byte of the request
* IRQ signaled ?? (means ADB controller wants to send, or might * is actually ADB_PACKET; the real data begins at index 1!
* be end of packet if we were reading) * And req->nbytes is the number of bytes of real data plus one.
*/
#if 0 /* FIXME: This is broke broke broke, for some reason */
if ((via[B] & TREQ) == 0) {
printk("macii_start: weird poll stuff. huh?\n");
/*
* FIXME - we need to restart this on a timer
* or a collision at boot hangs us.
* Never set macii_state to idle here, or macii_start
* won't be called again from send_request!
* (need to re-check other cases ...)
*/
/*
* if the interrupt handler set the need_poll
* flag, it's hopefully a SRQ poll or re-Talk
* so we try to send here anyway
*/
if (!need_poll) {
if (console_loglevel == 10)
printk("macii_start: device busy - retry %p state %d status %x!\n",
req, macii_state,
(uint) via[B] & (ST_MASK|TREQ));
retry_req = req;
/* set ADB status here ? */
local_irq_restore(flags);
return;
} else {
need_poll = 0;
}
}
#endif
/*
* Another retry pending? (sanity check)
*/ */
if (retry_req) {
retry_req = NULL;
}
/* Now send it. Be careful though, that first byte of the request */
/* is actually ADB_PACKET; the real data begins at index 1! */
/* store command byte */ /* store command byte */
command_byte = req->data[1]; command_byte = req->data[1];
...@@ -381,115 +367,97 @@ static void macii_start(void) ...@@ -381,115 +367,97 @@ static void macii_start(void)
macii_state = sending; macii_state = sending;
data_index = 2; data_index = 2;
local_irq_restore(flags);
} }
/* /*
* The notorious ADB interrupt handler - does all of the protocol handling, * The notorious ADB interrupt handler - does all of the protocol handling.
* except for starting new send operations. Relies heavily on the ADB * Relies on the ADB controller sending and receiving data, thereby
* controller sending and receiving data, thereby generating SR interrupts * generating shift register interrupts (SR_INT) for us. This means there has
* for us. This means there has to be always activity on the ADB bus, otherwise * to be activity on the ADB bus. The chip will poll to achieve this.
* the whole process dies and has to be re-kicked by sending TALK requests ...
* CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
* ADB the problem isn't solved yet (retransmit of the latest active TALK seems
* a good choice; either on timeout or on a timer interrupt).
* *
* The basic ADB state machine was left unchanged from the original MacII code * The basic ADB state machine was left unchanged from the original MacII code
* by Alan Cox, which was based on the CUDA driver for PowerMac. * by Alan Cox, which was based on the CUDA driver for PowerMac.
* The syntax of the ADB status lines seems to be totally different on MacII, * The syntax of the ADB status lines is totally different on MacII,
* though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle
* sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving.
* and end of a receive packet are signaled by asserting /IRQ on the interrupt * Start and end of a receive packet are signalled by asserting /IRQ on the
* line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused
* every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the * with the VIA shift register interrupt. /IRQ never actually interrupts the
* end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB * processor, it's just an ordinary input.)
* protocol with a logic analyzer!!)
*
* Note: As of 21/10/97, the MacII ADB part works including timeout detection
* and retransmit (Talk to the last active device).
*/ */
static irqreturn_t macii_interrupt(int irq, void *arg) static irqreturn_t macii_interrupt(int irq, void *arg)
{ {
int x, adbdir; int x;
unsigned long flags; static int entered;
struct adb_request *req; struct adb_request *req;
last_status = status; if (!arg) {
/* Clear the SR IRQ flag when polling. */
/* prevent races due to SCSI enabling ints */ if (via[IFR] & SR_INT)
local_irq_save(flags); via[IFR] = SR_INT;
else
if (driver_running) {
local_irq_restore(flags);
return IRQ_NONE; return IRQ_NONE;
} }
driver_running = 1; BUG_ON(entered++);
status = via[B] & (ST_MASK|TREQ); last_status = status;
adbdir = via[ACR] & SR_OUT; status = via[B] & (ST_MASK|CTLR_IRQ);
switch (macii_state) { switch (macii_state) {
case idle: case idle:
x = via[SR]; if (reading_reply) {
first_byte = x; reply_ptr = current_req->reply;
/* set ADB state = even for first data byte */ } else {
via[B] = (via[B] & ~ST_MASK) | ST_EVEN; BUG_ON(current_req != NULL);
reply_ptr = reply_buf;
}
reply_buf[0] = first_byte; /* was command_byte?? */ x = via[SR];
reply_ptr = reply_buf + 1;
reply_len = 1;
prefix_len = 1;
reading_reply = 0;
if ((status & CTLR_IRQ) && (x == 0xFF)) {
/* Bus timeout without SRQ sequence:
* data is "FF" while CTLR_IRQ is "H"
*/
reply_len = 0;
srq_asserted = 0;
macii_state = read_done;
} else {
macii_state = reading; macii_state = reading;
break; *reply_ptr = x;
reply_len = 1;
}
case awaiting_reply:
/* handshake etc. for II ?? */
x = via[SR];
first_byte = x;
/* set ADB state = even for first data byte */ /* set ADB state = even for first data byte */
via[B] = (via[B] & ~ST_MASK) | ST_EVEN; via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
current_req->reply[0] = first_byte;
reply_ptr = current_req->reply + 1;
reply_len = 1;
prefix_len = 1;
reading_reply = 1;
macii_state = reading;
break; break;
case sending: case sending:
req = current_req; req = current_req;
if (data_index >= req->nbytes) { if (data_index >= req->nbytes) {
/* print an error message if a listen command has no data */
if (((command_byte & 0x0C) == 0x08)
/* && (console_loglevel == 10) */
&& (data_index == 2))
printk("MacII ADB: listen command with no data: %x!\n",
command_byte);
/* reset to shift in */
via[ACR] &= ~SR_OUT;
x = via[SR];
/* set ADB state idle - might get SRQ */
via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
req->sent = 1; req->sent = 1;
macii_state = idle;
if (req->reply_expected) { if (req->reply_expected) {
macii_state = awaiting_reply; reading_reply = 1;
} else { } else {
req->complete = 1; req->complete = 1;
current_req = req->next; current_req = req->next;
if (req->done) (*req->done)(req); if (req->done) (*req->done)(req);
macii_state = idle;
if (current_req || retry_req) if (current_req)
macii_start(); macii_start();
else else
macii_retransmit((command_byte & 0xF0) >> 4); if (need_autopoll())
macii_autopoll(autopoll_devs);
}
if (macii_state == idle) {
/* reset to shift in */
via[ACR] &= ~SR_OUT;
x = via[SR];
/* set ADB state idle - might get SRQ */
via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
} }
} else { } else {
via[SR] = req->data[data_index++]; via[SR] = req->data[data_index++];
...@@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int irq, void *arg) ...@@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int irq, void *arg)
break; break;
case reading: case reading:
/* timeout / SRQ handling for II hw */
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))
{
/*
* 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[SR]; x = via[SR];
if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n"); BUG_ON((status & ST_MASK) == ST_CMD ||
(status & ST_MASK) == ST_IDLE);
/* Bus timeout with SRQ sequence:
* data is "XX FF" while CTLR_IRQ is "L L"
* End of packet without SRQ sequence:
* data is "XX...YY 00" while CTLR_IRQ is "L...H L"
* End of packet SRQ sequence:
* data is "XX...YY 00" while CTLR_IRQ is "L...L L"
* (where XX is the first response byte and
* YY is the last byte of valid response data.)
*/
if ((status & TREQ) == (last_status & TREQ)) { srq_asserted = 0;
/* Not a timeout. Unsolicited SRQ? weird. */ if (!(status & CTLR_IRQ)) {
/* Terminate the SRQ packet and poll */ if (x == 0xFF) {
need_poll = 1; if (!(last_status & CTLR_IRQ)) {
macii_state = read_done;
reply_len = 0;
srq_asserted = 1;
} }
/* There's no packet to get, so reply is blank */ } else if (x == 0x00) {
via[B] ^= ST_MASK;
reply_ptr -= (reply_len-prefix_len);
reply_len = prefix_len;
macii_state = read_done; macii_state = read_done;
break; if (!(last_status & CTLR_IRQ))
} /* end timeout / SRQ handling for II hw. */ srq_asserted = 1;
}
}
if((reply_len-prefix_len)>3 if (macii_state == reading) {
&& memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) BUG_ON(reply_len > 15);
{
/* SRQ tacked on data packet */
/* Terminate the packet (SRQ never ends) */
x = via[SR];
macii_state = read_done;
reply_len -= 3;
reply_ptr -= 3;
need_poll = 1;
/* need to continue; next byte not seen else */
} else {
/* Sanity check */
if (reply_len > 15) reply_len = 0;
/* read byte */
x = via[SR];
*reply_ptr = x;
reply_ptr++; reply_ptr++;
*reply_ptr = x;
reply_len++; reply_len++;
} }
/* The usual handshake ... */
/*
* 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) == 0) && (x == 0x00)) { /* != 0xFF */
/* invert state bits, toggle ODD/EVEN */
via[B] ^= ST_MASK;
/* adjust packet length */ /* invert state bits, toggle ODD/EVEN */
reply_len--;
reply_ptr--;
macii_state = read_done;
} else {
/* not caught: ST_CMD */
/* required for re-entry 'reading'! */
if ((status & ST_MASK) == ST_IDLE) {
/* (in)sanity check - set even */
via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
} else {
/* invert state bits */
via[B] ^= ST_MASK; via[B] ^= ST_MASK;
}
}
break; break;
case read_done: case read_done:
x = via[SR]; x = via[SR];
if (reading_reply) { if (reading_reply) {
reading_reply = 0;
req = current_req; req = current_req;
req->reply_len = reply_ptr - req->reply; req->reply_len = reply_len;
req->complete = 1; req->complete = 1;
current_req = req->next; current_req = req->next;
if (req->done) (*req->done)(req); if (req->done) (*req->done)(req);
} else { } else if (reply_len && autopoll_devs)
adb_input(reply_buf, reply_ptr - reply_buf, 0); adb_input(reply_buf, reply_len, 0);
}
/* macii_state = idle;
* remember this device ID; it's the latest we got a
* reply from!
*/
last_reply = command_byte;
last_active = (command_byte & 0xF0) >> 4;
/* SRQ seen before, initiate poll now */ /* SRQ seen before, initiate poll now */
if (need_poll) { if (srq_asserted)
macii_state = idle;
macii_queue_poll(); macii_queue_poll();
need_poll = 0;
break;
}
/* set ADB state to idle */
via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
/* /IRQ seen, so the ADB controller has data for us */
if ((via[B] & TREQ) != 0) {
macii_state = reading;
reply_buf[0] = command_byte;
reply_ptr = reply_buf + 1;
reply_len = 1;
prefix_len = 1;
reading_reply = 0;
} else {
/* no IRQ, send next packet or wait */
macii_state = idle;
if (current_req) if (current_req)
macii_start(); macii_start();
else else
macii_retransmit(last_active); if (need_autopoll())
} macii_autopoll(autopoll_devs);
if (macii_state == idle)
via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
break; break;
default: default:
break; break;
} }
/* reset mutex and interrupts */
driver_running = 0; entered--;
local_irq_restore(flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment