|  | /* | 
|  | * Device driver for the IIsi-style ADB on some Mac LC and II-class machines | 
|  | * | 
|  | * Based on via-cuda.c and via-macii.c, as well as the original | 
|  | * adb-bus.c, which in turn is somewhat influenced by (but uses no | 
|  | * code from) the NetBSD HWDIRECT ADB code.  Original IIsi driver work | 
|  | * was done by Robert Thompson and integrated into the old style | 
|  | * driver by Michael Schmitz. | 
|  | * | 
|  | * Original sources (c) Alan Cox, Paul Mackerras, and others. | 
|  | * | 
|  | * Rewritten for Unified ADB by David Huggins-Daines <dhd@debian.org> | 
|  | * | 
|  | * 7/13/2000- extensive changes by Andrew McPherson <andrew@macduff.dhs.org> | 
|  | * Works about 30% of the time now. | 
|  | */ | 
|  |  | 
|  | #include <linux/types.h> | 
|  | #include <linux/errno.h> | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/adb.h> | 
|  | #include <linux/cuda.h> | 
|  | #include <linux/delay.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <asm/macintosh.h> | 
|  | #include <asm/macints.h> | 
|  | #include <asm/mac_via.h> | 
|  |  | 
|  | static volatile unsigned char *via; | 
|  |  | 
|  | /* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */ | 
|  | #define RS		0x200		/* skip between registers */ | 
|  | #define B		0		/* B-side data */ | 
|  | #define A		RS		/* A-side data */ | 
|  | #define DIRB		(2*RS)		/* B-side direction (1=output) */ | 
|  | #define DIRA		(3*RS)		/* A-side direction (1=output) */ | 
|  | #define SR		(10*RS)		/* Shift register */ | 
|  | #define ACR		(11*RS)		/* Auxiliary control register */ | 
|  | #define IFR		(13*RS)		/* Interrupt flag register */ | 
|  | #define IER		(14*RS)		/* Interrupt enable register */ | 
|  |  | 
|  | /* Bits in B data register: all active low */ | 
|  | #define TREQ		0x08		/* Transfer request (input) */ | 
|  | #define TACK		0x10		/* Transfer acknowledge (output) */ | 
|  | #define TIP		0x20		/* Transfer in progress (output) */ | 
|  | #define ST_MASK		0x30		/* mask for selecting ADB state bits */ | 
|  |  | 
|  | /* Bits in ACR */ | 
|  | #define SR_CTRL		0x1c		/* Shift register control bits */ | 
|  | #define SR_EXT		0x0c		/* Shift on external clock */ | 
|  | #define SR_OUT		0x10		/* Shift out if 1 */ | 
|  |  | 
|  | /* Bits in IFR and IER */ | 
|  | #define IER_SET		0x80		/* set bits in IER */ | 
|  | #define IER_CLR		0		/* clear bits in IER */ | 
|  | #define SR_INT		0x04		/* Shift register full/empty */ | 
|  | #define SR_DATA		0x08		/* Shift register data */ | 
|  | #define SR_CLOCK	0x10		/* Shift register clock */ | 
|  |  | 
|  | #define ADB_DELAY 150 | 
|  |  | 
|  | #undef DEBUG_MACIISI_ADB | 
|  |  | 
|  | static struct adb_request* current_req; | 
|  | static struct adb_request* last_req; | 
|  | static unsigned char maciisi_rbuf[16]; | 
|  | static unsigned char *reply_ptr; | 
|  | static int data_index; | 
|  | static int reading_reply; | 
|  | static int reply_len; | 
|  | static int tmp; | 
|  | static int need_sync; | 
|  |  | 
|  | static enum maciisi_state { | 
|  | idle, | 
|  | sending, | 
|  | reading, | 
|  | } maciisi_state; | 
|  |  | 
|  | static int maciisi_probe(void); | 
|  | static int maciisi_init(void); | 
|  | static int maciisi_send_request(struct adb_request* req, int sync); | 
|  | static void maciisi_sync(struct adb_request *req); | 
|  | static int maciisi_write(struct adb_request* req); | 
|  | static irqreturn_t maciisi_interrupt(int irq, void* arg); | 
|  | static void maciisi_input(unsigned char *buf, int nb); | 
|  | static int maciisi_init_via(void); | 
|  | static void maciisi_poll(void); | 
|  | static int maciisi_start(void); | 
|  |  | 
|  | struct adb_driver via_maciisi_driver = { | 
|  | "Mac IIsi", | 
|  | maciisi_probe, | 
|  | maciisi_init, | 
|  | maciisi_send_request, | 
|  | NULL, /* maciisi_adb_autopoll, */ | 
|  | maciisi_poll, | 
|  | NULL /* maciisi_reset_adb_bus */ | 
|  | }; | 
|  |  | 
|  | static int | 
|  | maciisi_probe(void) | 
|  | { | 
|  | if (macintosh_config->adb_type != MAC_ADB_IISI) | 
|  | return -ENODEV; | 
|  |  | 
|  | via = via1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | maciisi_init(void) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | if (via == NULL) | 
|  | return -ENODEV; | 
|  |  | 
|  | if ((err = maciisi_init_via())) { | 
|  | printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err); | 
|  | via = NULL; | 
|  | return err; | 
|  | } | 
|  |  | 
|  | if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST, | 
|  | "ADB", maciisi_interrupt)) { | 
|  | printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB); | 
|  | return -EAGAIN; | 
|  | } | 
|  |  | 
|  | printk("adb: Mac IIsi driver v0.2 for Unified ADB.\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Flush data from the ADB controller */ | 
|  | static void | 
|  | maciisi_stfu(void) | 
|  | { | 
|  | int status = via[B] & (TIP|TREQ); | 
|  |  | 
|  | if (status & TREQ) { | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n"); | 
|  | #endif | 
|  | return; | 
|  | } | 
|  |  | 
|  | udelay(ADB_DELAY); | 
|  | via[ACR] &= ~SR_OUT; | 
|  | via[IER] = IER_CLR | SR_INT; | 
|  |  | 
|  | udelay(ADB_DELAY); | 
|  |  | 
|  | status = via[B] & (TIP|TREQ); | 
|  |  | 
|  | if (!(status & TREQ)) | 
|  | { | 
|  | via[B] |= TIP; | 
|  |  | 
|  | while(1) | 
|  | { | 
|  | int poll_timeout = ADB_DELAY * 5; | 
|  | /* Poll for SR interrupt */ | 
|  | while (!(via[IFR] & SR_INT) && poll_timeout-- > 0) | 
|  | status = via[B] & (TIP|TREQ); | 
|  |  | 
|  | tmp = via[SR]; /* Clear shift register */ | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d data %x\n", | 
|  | status, poll_timeout, tmp); | 
|  | #endif | 
|  | if(via[B] & TREQ) | 
|  | break; | 
|  |  | 
|  | /* ACK on-off */ | 
|  | via[B] |= TACK; | 
|  | udelay(ADB_DELAY); | 
|  | via[B] &= ~TACK; | 
|  | } | 
|  |  | 
|  | /* end frame */ | 
|  | via[B] &= ~TIP; | 
|  | udelay(ADB_DELAY); | 
|  | } | 
|  |  | 
|  | via[IER] = IER_SET | SR_INT; | 
|  | } | 
|  |  | 
|  | /* All specifically VIA-related initialization goes here */ | 
|  | static int | 
|  | maciisi_init_via(void) | 
|  | { | 
|  | int	i; | 
|  |  | 
|  | /* Set the lines up. We want TREQ as input TACK|TIP as output */ | 
|  | via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; | 
|  | /* Shift register on input */ | 
|  | via[ACR]  = (via[ACR] & ~SR_CTRL) | SR_EXT; | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ)); | 
|  | #endif | 
|  | /* Wipe any pending data and int */ | 
|  | tmp = via[SR]; | 
|  | /* Enable keyboard interrupts */ | 
|  | via[IER] = IER_SET | SR_INT; | 
|  | /* Set initial state: idle */ | 
|  | via[B] &= ~(TACK|TIP); | 
|  | /* Clear interrupt bit */ | 
|  | via[IFR] = SR_INT; | 
|  |  | 
|  | for(i = 0; i < 60; i++) { | 
|  | udelay(ADB_DELAY); | 
|  | maciisi_stfu(); | 
|  | udelay(ADB_DELAY); | 
|  | if(via[B] & TREQ) | 
|  | break; | 
|  | } | 
|  | if (i == 60) | 
|  | printk(KERN_ERR "maciisi_init_via: bus jam?\n"); | 
|  |  | 
|  | maciisi_state = idle; | 
|  | need_sync = 0; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Send a request, possibly waiting for a reply */ | 
|  | static int | 
|  | maciisi_send_request(struct adb_request* req, int sync) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | static int dump_packet = 0; | 
|  | #endif | 
|  |  | 
|  | if (via == NULL) { | 
|  | req->complete = 1; | 
|  | return -ENXIO; | 
|  | } | 
|  |  | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | if (dump_packet) { | 
|  | printk(KERN_DEBUG "maciisi_send_request:"); | 
|  | for (i = 0; i < req->nbytes; i++) { | 
|  | printk(" %.2x", req->data[i]); | 
|  | } | 
|  | printk(" sync %d\n", sync); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | req->reply_expected = 1; | 
|  |  | 
|  | i = maciisi_write(req); | 
|  | if (i) | 
|  | { | 
|  | /* Normally, if a packet requires syncing, that happens at the end of | 
|  | * maciisi_send_request. But if the transfer fails, it will be restarted | 
|  | * by maciisi_interrupt(). We use need_sync to tell maciisi_interrupt | 
|  | * when to sync a packet that it sends out. | 
|  | * | 
|  | * Suggestions on a better way to do this are welcome. | 
|  | */ | 
|  | if(i == -EBUSY && sync) | 
|  | need_sync = 1; | 
|  | else | 
|  | need_sync = 0; | 
|  | return i; | 
|  | } | 
|  | if(sync) | 
|  | maciisi_sync(req); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Poll the ADB chip until the request completes */ | 
|  | static void maciisi_sync(struct adb_request *req) | 
|  | { | 
|  | int count = 0; | 
|  |  | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "maciisi_sync called\n"); | 
|  | #endif | 
|  |  | 
|  | /* If for some reason the ADB chip shuts up on us, we want to avoid an endless loop. */ | 
|  | while (!req->complete && count++ < 50) { | 
|  | maciisi_poll(); | 
|  | } | 
|  | /* This could be BAD... when the ADB controller doesn't respond | 
|  | * for this long, it's probably not coming back :-( */ | 
|  | if (count > 50) /* Hopefully shouldn't happen */ | 
|  | printk(KERN_ERR "maciisi_send_request: poll timed out!\n"); | 
|  | } | 
|  |  | 
|  | int | 
|  | maciisi_request(struct adb_request *req, void (*done)(struct adb_request *), | 
|  | int nbytes, ...) | 
|  | { | 
|  | va_list list; | 
|  | int i; | 
|  |  | 
|  | req->nbytes = nbytes; | 
|  | req->done = done; | 
|  | req->reply_expected = 0; | 
|  | va_start(list, nbytes); | 
|  | for (i = 0; i < nbytes; i++) | 
|  | req->data[i++] = va_arg(list, int); | 
|  | va_end(list); | 
|  |  | 
|  | return maciisi_send_request(req, 1); | 
|  | } | 
|  |  | 
|  | /* Enqueue a request, and run the queue if possible */ | 
|  | static int | 
|  | maciisi_write(struct adb_request* req) | 
|  | { | 
|  | unsigned long flags; | 
|  | int i; | 
|  |  | 
|  | /* We will accept CUDA packets - the VIA sends them to us, so | 
|  | it figures that we should be able to send them to it */ | 
|  | if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { | 
|  | printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n"); | 
|  | req->complete = 1; | 
|  | return -EINVAL; | 
|  | } | 
|  | req->next = NULL; | 
|  | req->sent = 0; | 
|  | req->complete = 0; | 
|  | req->reply_len = 0; | 
|  |  | 
|  | local_irq_save(flags); | 
|  |  | 
|  | if (current_req) { | 
|  | last_req->next = req; | 
|  | last_req = req; | 
|  | } else { | 
|  | current_req = req; | 
|  | last_req = req; | 
|  | } | 
|  | if (maciisi_state == idle) | 
|  | { | 
|  | i = maciisi_start(); | 
|  | if(i != 0) | 
|  | { | 
|  | local_irq_restore(flags); | 
|  | return i; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state); | 
|  | #endif | 
|  | local_irq_restore(flags); | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | local_irq_restore(flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | maciisi_start(void) | 
|  | { | 
|  | struct adb_request* req; | 
|  | int status; | 
|  |  | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | status = via[B] & (TIP | TREQ); | 
|  |  | 
|  | printk(KERN_DEBUG "maciisi_start called, state=%d, status=%x, ifr=%x\n", maciisi_state, status, via[IFR]); | 
|  | #endif | 
|  |  | 
|  | if (maciisi_state != idle) { | 
|  | /* shouldn't happen */ | 
|  | printk(KERN_ERR "maciisi_start: maciisi_start called when driver busy!\n"); | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | req = current_req; | 
|  | if (req == NULL) | 
|  | return -EINVAL; | 
|  |  | 
|  | status = via[B] & (TIP|TREQ); | 
|  | if (!(status & TREQ)) { | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "maciisi_start: bus busy - aborting\n"); | 
|  | #endif | 
|  | return -EBUSY; | 
|  | } | 
|  |  | 
|  | /* Okay, send */ | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "maciisi_start: sending\n"); | 
|  | #endif | 
|  | /* Set state to active */ | 
|  | via[B] |= TIP; | 
|  | /* ACK off */ | 
|  | via[B] &= ~TACK; | 
|  | /* Delay */ | 
|  | udelay(ADB_DELAY); | 
|  | /* Shift out and send */ | 
|  | via[ACR] |= SR_OUT; | 
|  | via[SR] = req->data[0]; | 
|  | data_index = 1; | 
|  | /* ACK on */ | 
|  | via[B] |= TACK; | 
|  | maciisi_state = sending; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | maciisi_poll(void) | 
|  | { | 
|  | unsigned long flags; | 
|  |  | 
|  | local_irq_save(flags); | 
|  | if (via[IFR] & SR_INT) { | 
|  | maciisi_interrupt(0, NULL); | 
|  | } | 
|  | else /* avoid calling this function too quickly in a loop */ | 
|  | udelay(ADB_DELAY); | 
|  |  | 
|  | local_irq_restore(flags); | 
|  | } | 
|  |  | 
|  | /* Shift register interrupt - this is *supposed* to mean that the | 
|  | register is either full or empty. In practice, I have no idea what | 
|  | it means :( */ | 
|  | static irqreturn_t | 
|  | maciisi_interrupt(int irq, void* arg) | 
|  | { | 
|  | int status; | 
|  | struct adb_request *req; | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | static int dump_reply = 0; | 
|  | #endif | 
|  | int i; | 
|  | unsigned long flags; | 
|  |  | 
|  | local_irq_save(flags); | 
|  |  | 
|  | status = via[B] & (TIP|TREQ); | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]); | 
|  | #endif | 
|  |  | 
|  | if (!(via[IFR] & SR_INT)) { | 
|  | /* Shouldn't happen, we hope */ | 
|  | printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n"); | 
|  | local_irq_restore(flags); | 
|  | return IRQ_NONE; | 
|  | } | 
|  |  | 
|  | /* Clear the interrupt */ | 
|  | /* via[IFR] = SR_INT; */ | 
|  |  | 
|  | switch_start: | 
|  | switch (maciisi_state) { | 
|  | case idle: | 
|  | if (status & TIP) | 
|  | printk(KERN_ERR "maciisi_interrupt: state is idle but TIP asserted!\n"); | 
|  |  | 
|  | if(!reading_reply) | 
|  | udelay(ADB_DELAY); | 
|  | /* Shift in */ | 
|  | via[ACR] &= ~SR_OUT; | 
|  | /* Signal start of frame */ | 
|  | via[B] |= TIP; | 
|  | /* Clear the interrupt (throw this value on the floor, it's useless) */ | 
|  | tmp = via[SR]; | 
|  | /* ACK adb chip, high-low */ | 
|  | via[B] |= TACK; | 
|  | udelay(ADB_DELAY); | 
|  | via[B] &= ~TACK; | 
|  | reply_len = 0; | 
|  | maciisi_state = reading; | 
|  | if (reading_reply) { | 
|  | reply_ptr = current_req->reply; | 
|  | } else { | 
|  | reply_ptr = maciisi_rbuf; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case sending: | 
|  | /* via[SR]; */ | 
|  | /* Set ACK off */ | 
|  | via[B] &= ~TACK; | 
|  | req = current_req; | 
|  |  | 
|  | if (!(status & TREQ)) { | 
|  | /* collision */ | 
|  | printk(KERN_ERR "maciisi_interrupt: send collision\n"); | 
|  | /* Set idle and input */ | 
|  | via[ACR] &= ~SR_OUT; | 
|  | tmp = via[SR]; | 
|  | via[B] &= ~TIP; | 
|  | /* Must re-send */ | 
|  | reading_reply = 0; | 
|  | reply_len = 0; | 
|  | maciisi_state = idle; | 
|  | udelay(ADB_DELAY); | 
|  | /* process this now, because the IFR has been cleared */ | 
|  | goto switch_start; | 
|  | } | 
|  |  | 
|  | udelay(ADB_DELAY); | 
|  |  | 
|  | if (data_index >= req->nbytes) { | 
|  | /* Sent the whole packet, put the bus back in idle state */ | 
|  | /* Shift in, we are about to read a reply (hopefully) */ | 
|  | via[ACR] &= ~SR_OUT; | 
|  | tmp = via[SR]; | 
|  | /* End of frame */ | 
|  | via[B] &= ~TIP; | 
|  | req->sent = 1; | 
|  | maciisi_state = idle; | 
|  | if (req->reply_expected) { | 
|  | /* Note: only set this once we've | 
|  | successfully sent the packet */ | 
|  | reading_reply = 1; | 
|  | } else { | 
|  | current_req = req->next; | 
|  | if (req->done) | 
|  | (*req->done)(req); | 
|  | /* Do any queued requests now */ | 
|  | i = maciisi_start(); | 
|  | if(i == 0 && need_sync) { | 
|  | /* Packet needs to be synced */ | 
|  | maciisi_sync(current_req); | 
|  | } | 
|  | if(i != -EBUSY) | 
|  | need_sync = 0; | 
|  | } | 
|  | } else { | 
|  | /* Sending more stuff */ | 
|  | /* Shift out */ | 
|  | via[ACR] |= SR_OUT; | 
|  | /* Write */ | 
|  | via[SR] = req->data[data_index++]; | 
|  | /* Signal 'byte ready' */ | 
|  | via[B] |= TACK; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case reading: | 
|  | /* Shift in */ | 
|  | /* via[ACR] &= ~SR_OUT; */ /* Not in 2.2 */ | 
|  | if (reply_len++ > 16) { | 
|  | printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n"); | 
|  | via[B] |= TACK; | 
|  | udelay(ADB_DELAY); | 
|  | via[B] &= ~(TACK|TIP); | 
|  | maciisi_state = idle; | 
|  | i = maciisi_start(); | 
|  | if(i == 0 && need_sync) { | 
|  | /* Packet needs to be synced */ | 
|  | maciisi_sync(current_req); | 
|  | } | 
|  | if(i != -EBUSY) | 
|  | need_sync = 0; | 
|  | break; | 
|  | } | 
|  | /* Read data */ | 
|  | *reply_ptr++ = via[SR]; | 
|  | status = via[B] & (TIP|TREQ); | 
|  | /* ACK on/off */ | 
|  | via[B] |= TACK; | 
|  | udelay(ADB_DELAY); | 
|  | via[B] &= ~TACK; | 
|  | if (!(status & TREQ)) | 
|  | break; /* more stuff to deal with */ | 
|  |  | 
|  | /* end of frame */ | 
|  | via[B] &= ~TIP; | 
|  | tmp = via[SR]; /* That's what happens in 2.2 */ | 
|  | udelay(ADB_DELAY); /* Give controller time to recover */ | 
|  |  | 
|  | /* end of packet, deal with it */ | 
|  | if (reading_reply) { | 
|  | req = current_req; | 
|  | req->reply_len = reply_ptr - req->reply; | 
|  | if (req->data[0] == ADB_PACKET) { | 
|  | /* Have to adjust the reply from ADB commands */ | 
|  | if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { | 
|  | /* the 0x2 bit indicates no response */ | 
|  | req->reply_len = 0; | 
|  | } else { | 
|  | /* leave just the command and result bytes in the reply */ | 
|  | req->reply_len -= 2; | 
|  | memmove(req->reply, req->reply + 2, req->reply_len); | 
|  | } | 
|  | } | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | if (dump_reply) { | 
|  | int i; | 
|  | printk(KERN_DEBUG "maciisi_interrupt: reply is "); | 
|  | for (i = 0; i < req->reply_len; ++i) | 
|  | printk(" %.2x", req->reply[i]); | 
|  | printk("\n"); | 
|  | } | 
|  | #endif | 
|  | req->complete = 1; | 
|  | current_req = req->next; | 
|  | if (req->done) | 
|  | (*req->done)(req); | 
|  | /* Obviously, we got it */ | 
|  | reading_reply = 0; | 
|  | } else { | 
|  | maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf); | 
|  | } | 
|  | maciisi_state = idle; | 
|  | status = via[B] & (TIP|TREQ); | 
|  | if (!(status & TREQ)) { | 
|  | /* Timeout?! More likely, another packet coming in already */ | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n", | 
|  | status, via[IFR]); | 
|  | #endif | 
|  | #if 0 | 
|  | udelay(ADB_DELAY); | 
|  | via[B] |= TIP; | 
|  |  | 
|  | maciisi_state = reading; | 
|  | reading_reply = 0; | 
|  | reply_ptr = maciisi_rbuf; | 
|  | #else | 
|  | /* Process the packet now */ | 
|  | reading_reply = 0; | 
|  | goto switch_start; | 
|  | #endif | 
|  | /* We used to do this... but the controller might actually have data for us */ | 
|  | /* maciisi_stfu(); */ | 
|  | } | 
|  | else { | 
|  | /* Do any queued requests now if possible */ | 
|  | i = maciisi_start(); | 
|  | if(i == 0 && need_sync) { | 
|  | /* Packet needs to be synced */ | 
|  | maciisi_sync(current_req); | 
|  | } | 
|  | if(i != -EBUSY) | 
|  | need_sync = 0; | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state); | 
|  | } | 
|  | local_irq_restore(flags); | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | static void | 
|  | maciisi_input(unsigned char *buf, int nb) | 
|  | { | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | int i; | 
|  | #endif | 
|  |  | 
|  | switch (buf[0]) { | 
|  | case ADB_PACKET: | 
|  | adb_input(buf+2, nb-2, buf[1] & 0x40); | 
|  | break; | 
|  | default: | 
|  | #ifdef DEBUG_MACIISI_ADB | 
|  | printk(KERN_DEBUG "data from IIsi ADB (%d bytes):", nb); | 
|  | for (i = 0; i < nb; ++i) | 
|  | printk(" %.2x", buf[i]); | 
|  | printk("\n"); | 
|  | #endif | 
|  | break; | 
|  | } | 
|  | } |