📄 via-macii.c
字号:
* 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 ? */ restore_flags(flags); return; } else { need_poll = 0; } } /* * 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 */ command_byte = req->data[1]; /* Output mode */ via[ACR] |= SR_OUT; /* Load data */ via[SR] = req->data[1]; /* set ADB state to 'command' */ via[B] = (via[B] & ~ST_MASK) | ST_CMD; macii_state = sent_first_byte; data_index = 2; restore_flags(flags);}/* * The notorious ADB interrupt handler - does all of the protocol handling, * except for starting new send operations. Relies heavily on the ADB * controller sending and receiving data, thereby generating SR interrupts * for us. This means there has to be always activity on the ADB bus, otherwise * 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 * 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, * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start * and end of a receive packet are signaled by asserting /IRQ on the interrupt * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB * 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). */void macii_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; status = via[B] & (ST_MASK|TREQ); adbdir = via[ACR] & SR_OUT; switch (macii_state) { case idle: x = via[SR]; first_byte = x; /* set ADB state = even for first data byte */ via[B] = (via[B] & ~ST_MASK) | ST_EVEN; reply_buf[0] = first_byte; /* was command_byte?? */ reply_ptr = reply_buf + 1; reply_len = 1; prefix_len = 1; reading_reply = 0; macii_state = reading; break; case awaiting_reply: /* handshake etc. for II ?? */ x = via[SR]; first_byte = x; /* set ADB state = even for first data byte */ 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; case sent_first_byte: req = current_req; /* maybe we're already done (Talk, or Poll)? */ if (data_index >= req->nbytes) { /* reset to shift in */ /* If it's a Listen command and we're done, someone's doing weird stuff. */ if (((command_byte & 0x0C) == 0x08) && (console_loglevel == 10)) printk("macii_interrupt: 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; if (req->reply_expected) { macii_state = awaiting_reply; } else { req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); macii_state = idle; if (current_req || retry_req) macii_start(); else macii_retransmit((command_byte & 0xF0) >> 4); } } else { /* SR already set to shift out; send byte */ via[SR] = current_req->data[data_index++]; /* set state to ST_EVEN (first byte was: ST_CMD) */ via[B] = (via[B] & ~ST_MASK) | ST_EVEN; macii_state = sending; } break; case sending: req = current_req; if (data_index >= req->nbytes) { /* 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; if (req->reply_expected) { macii_state = awaiting_reply; } else { req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); macii_state = idle; if (current_req || retry_req) macii_start(); else macii_retransmit((command_byte & 0xF0) >> 4); } } else { via[SR] = req->data[data_index++]; /* invert state bits, toggle ODD/EVEN */ via[B] ^= ST_MASK; } break; 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]; if (x != 0xFF) printk("macii_interrupt: mistaken timeout/SRQ!\n"); if ((status & TREQ) == (last_status & TREQ)) { /* Not a timeout. Unsolicited SRQ? weird. */ /* Terminate the SRQ packet and poll */ need_poll = 1; } /* There's no packet to get, so reply is blank */ via[B] ^= ST_MASK; reply_ptr -= (reply_len-prefix_len); reply_len = prefix_len; macii_state = read_done; 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 */ /* 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_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) && (x == 0x00)) { /* != 0xFF */ /* invert state bits, toggle ODD/EVEN */ via[B] ^= ST_MASK; /* adjust packet length */ 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; } } break; case read_done: x = via[SR]; if (reading_reply) { req = current_req; req->reply_len = reply_ptr - req->reply; req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); } else { adb_input(reply_buf, reply_ptr - reply_buf, regs, 0); } /* * 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 */ if (need_poll) { macii_state = idle; macii_queue_poll(); need_poll = 0; break; } /* /IRQ seen, so the ADB controller has data for us */ if (!(status & TREQ)) { /* set ADB state to idle */ via[B] = (via[B] & ~ST_MASK) | ST_IDLE; 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) macii_start(); else macii_retransmit(last_active); } break; default: break; } /* reset mutex and interrupts */ driver_running = 0; restore_flags(flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -