/* Enqueue a request, and run the queue if possible */ static int maciisi_write(struct adb_request* req) { unsigned long flags; printk(KERN_DEBUG "maciisi_write called, state=%d ifr=%x\n", maciisi_state, via[IFR]); /* 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 = 0; req->sent = 0; req->complete = 0; req->reply_len = 0; save_flags(flags); cli(); if (current_req) { last_req->next = req; last_req = req; } else { current_req = req; last_req = req; } if (maciisi_state == idle) maciisi_start(); else printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state); restore_flags(flags); return 0; }
/* 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; }
/* 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 void maciisi_interrupt(int irq, void* arg, struct pt_regs* regs) { int status; struct adb_request *req; static int dump_reply = 1; if (!(via[IFR] & SR_INT)) { /* Shouldn't happen, we hope */ printk(KERN_DEBUG "maciisi_interrupt: called without interrupt flag set\n"); return; } status = via[B] & (TIP|TREQ); printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]); switch_start: switch (maciisi_state) { case idle: printk(KERN_DEBUG "maciisi_interrupt: state=idle, status %x\n", status); if (status & TIP) printk(KERN_DEBUG "maciisi_interrupt: state is idle but TIP asserted!\n"); 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) */ 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 { printk(KERN_DEBUG "maciisi_interrupt: received unsolicited packet\n"); reply_ptr = maciisi_rbuf; } break; case sending: printk(KERN_DEBUG "maciisi_interrupt: state=sending, status=%x\n", status); /* Clear interrupt */ via[SR]; /* Set ACK off */ via[B] &= ~TACK; req = current_req; if (!(status & TREQ)) { /* collision */ printk(KERN_DEBUG "maciisi_interrupt: send collision\n"); /* Set idle and input */ via[B] &= ~TIP; via[ACR] &= ~SR_OUT; /* Must re-send */ reading_reply = 0; reply_len = 0; maciisi_state = idle; /* process this now, because the IFR has been cleared */ goto switch_start; } 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; /* 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); } } else { /* Sending more stuff */ /* Shift out */ via[ACR] |= SR_OUT; /* Delay */ udelay(ADB_DELAY); /* Write */ via[SR] = req->data[data_index++]; /* Signal 'byte ready' */ via[B] |= TACK; } break; case reading: printk(KERN_DEBUG "maciisi_interrupt: state=reading, status=%x\n", status); /* Shift in */ via[ACR] &= ~SR_OUT; 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; maciisi_start(); break; } *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; /* 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); } } 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"); } 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, regs); } maciisi_state = idle; status = via[B] & (TIP|TREQ); if (!(status & TREQ)) { /* Timeout?! */ printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n", status, via[IFR]); maciisi_stfu(); } /* Do any queued requests now if possible */ maciisi_start(); break; default: printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state); } }
/* 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 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)) { printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n"); local_irq_restore(flags); return IRQ_NONE; } 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); via[ACR] &= ~SR_OUT; via[B] |= TIP; tmp = via[SR]; 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[B] &= ~TACK; req = current_req; if (!(status & TREQ)) { printk(KERN_ERR "maciisi_interrupt: send collision\n"); via[ACR] &= ~SR_OUT; tmp = via[SR]; via[B] &= ~TIP; reading_reply = 0; reply_len = 0; maciisi_state = idle; udelay(ADB_DELAY); goto switch_start; } udelay(ADB_DELAY); if (data_index >= req->nbytes) { via[ACR] &= ~SR_OUT; tmp = via[SR]; via[B] &= ~TIP; req->sent = 1; maciisi_state = idle; if (req->reply_expected) { reading_reply = 1; } else { current_req = req->next; if (req->done) (*req->done)(req); i = maciisi_start(); if(i == 0 && need_sync) { maciisi_sync(current_req); } if(i != -EBUSY) need_sync = 0; } } else { via[ACR] |= SR_OUT; via[SR] = req->data[data_index++]; via[B] |= TACK; } break; case reading: 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) { maciisi_sync(current_req); } if(i != -EBUSY) need_sync = 0; break; } *reply_ptr++ = via[SR]; status = via[B] & (TIP|TREQ); via[B] |= TACK; udelay(ADB_DELAY); via[B] &= ~TACK; if (!(status & TREQ)) break; via[B] &= ~TIP; tmp = via[SR]; udelay(ADB_DELAY); if (reading_reply) { req = current_req; req->reply_len = reply_ptr - req->reply; if (req->data[0] == ADB_PACKET) { if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { req->reply_len = 0; } else { 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); reading_reply = 0; } else { maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf); } maciisi_state = idle; status = via[B] & (TIP|TREQ); if (!(status & TREQ)) { #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 reading_reply = 0; goto switch_start; #endif } else { i = maciisi_start(); if(i == 0 && need_sync) { 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; }