static uint8_t ioWrite2Loop(Write2Fn_t writeFn, uint16_t len) { uint8_t data[2]; usbInitIo(len, ENDPOINT_DIR_OUT); while (len != 0) { if (usbRecvByte(&data[0]) != 0 || usbRecvByte(&data[1]) != 0) break; writeFn(data); len -= 2; } usbIoDone(); return 0; }
static uint8_t ioWriteLoop(WriteFn_t writeFn, uint16_t len) { uint8_t data; usbInitIo(len, ENDPOINT_DIR_OUT); while (len-- != 0) { if (usbRecvByte(&data) != 0) break; writeFn(data); } usbIoDone(); return 0; }
static uint8_t ioWriteNibLoop(uint16_t len) { uint16_t i; uint8_t data, *ptr; // Probably an error, but handle it anyway. if (len == 0) return 0; suppressNibCmd = false; usbInitIo(len, ENDPOINT_DIR_OUT); iec_release(IO_DATA); /* * We're ready to go, kick off the actual data transfer by writing * all saved writes. We keep a queue because the 1541 and 1571 drive * code may send different numbers of bytes here. */ for (ptr = savedNibWrites; ptr != savedNibWritePtr; ptr++) nib_parburst_write(*ptr); savedNibWritePtr = savedNibWrites; for (i = 0; i < len; i++) { // Get the byte via USB if (usbRecvByte(&data) != 0) break; // Write a byte to the parport if (nib_write_handshaked(data, i & 1) < 0) { DEBUGF(DBG_ERROR, "nbwrh1 to\n"); return -1; } } /* * All bytes written ok, so write a final zero byte and read back the * dummy result. */ nib_write_handshaked(0, i & 1); nib_parburst_read(); usbIoDone(); return 0; }
static uint8_t ioWriteNibSrqLoop(uint16_t len) { uint16_t i; uint8_t data, *ptr; // nibtools drive code requires at least one data byte. if (len == 0) return 0; suppressNibCmd = false; usbInitIo(len, ENDPOINT_DIR_OUT); iec_release(IO_SRQ | IO_CLK | IO_DATA | IO_ATN); /* * We're ready to go, kick off the actual data transfer by writing * all saved writes. We keep a queue because the 1541 and 1571 drive * code may send different numbers of bytes here. */ for (ptr = savedNibWrites; ptr != savedNibWritePtr; ptr++) nib_srqburst_write(*ptr); savedNibWritePtr = savedNibWrites; for (i = 0; i < len; i++) { // Get data byte from USB. if (usbRecvByte(&data) != 0) break; // Write data byte via SRQ, break if timeout error. if (nib_srq_write_handshaked(data, i & 1) != 0) { DEBUGF(DBG_ERROR, "nbwrh1 to\n"); return -1; } } // Read back the dummy result. nib_srqburst_read(); usbIoDone(); return 0; }
// Execute pending USART read/write operations void usartExecute(void) { usbSelectEndpoint(OUT_ENDPOINT_ADDR); if ( usbOutPacketReady() ) { uint8 byte, chan; uint16 count; do { // Read/write flag & channel chan = usbRecvByte(); usartSendByte(chan); // Count high byte byte = usbRecvByte(); usartSendByte(byte); count = byte; // Count low byte byte = usbRecvByte(); usartSendByte(byte); count <<= 8; count |= byte; // Check to see if it's a read or a write if ( chan & 0x80 ) { // The host is reading a channel usbAckPacket(); // acknowledge the OUT packet usbSelectEndpoint(IN_ENDPOINT_ADDR); // switch to the IN endpoint #if USART_DEBUG == 1 debugSendFlashString(PSTR("READ(")); debugSendByteHex(count); debugSendByte(')'); debugSendByte('\r'); #endif while ( !(UCSR1A & (1<<TXC1)) ); // wait for send complete __asm volatile( "nop\nnop\nnop\nnop\n" // give things a chance to settle "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" "nop\nnop\nnop\nnop\n" ::); UCSR1B = (1<<RXEN1); // TX disabled, RX enabled while ( !usbInPacketReady() ); USART_OUT &= ~bmTX; // TX low says "I'm ready" do { byte = usartRecvByte(); if ( !usbReadWriteAllowed() ) { USART_OUT |= bmTX; // TX high says "I'm not ready" usbFlushPacket(); while ( !usbInPacketReady() ); USART_OUT &= ~bmTX; // TX low says "OK I'm ready now" } usbPutByte(byte); count--; } while ( count ); UCSR1B = (1<<TXEN1); // TX enabled, RX disabled USART_OUT |= bmTX; // TX high says "I acknowledge receipt of your data" usbFlushPacket(); // flush final packet usbSelectEndpoint(OUT_ENDPOINT_ADDR); // ready for next command return; // there cannot be any more work to do } else { // The host is writing a channel #if USART_DEBUG == 1 debugSendFlashString(PSTR("WRITE(")); debugSendByteHex(count); debugSendByte(')'); debugSendByte('\r'); #endif do { byte = usbRecvByte(); while ( PIND & bmRX ); // ensure RX is still low usartSendByte(byte); count--; } while ( count ); } } while ( usbReadWriteAllowed() ); usbAckPacket(); }
/* * Write bytes to the drive via the CBM default protocol. * Returns number of successful written bytes or 0 on error. */ static uint16_t iec_raw_write(uint16_t len, uint8_t flags) { uint8_t atn, talk, data; uint16_t rv; rv = len; atn = flags & XUM_WRITE_ATN; talk = flags & XUM_WRITE_TALK; eoi = 0; DEBUGF(DBG_INFO, "cwr %d, atn %d, talk %d\n", len, atn, talk); if (len == 0) return 0; usbInitIo(len, ENDPOINT_DIR_OUT); /* * First, check if any device is present on the bus. * If ATN and RST are both low (active), we know that at least one * drive is attached but none are powered up. In this case, we * bail out early. Otherwise, we'd get stuck in wait_for_listener(). */ if (!iec_wait_timeout_2ms(IO_ATN|IO_RESET, 0)) { DEBUGF(DBG_ERROR, "write: no devs on bus\n"); usbIoDone(); return 0; } iec_release(IO_DATA); iec_set(IO_CLK | (atn ? IO_ATN : 0)); IEC_DELAY(); // Wait for any device to pull data after we set CLK. This is actually // IEC_T_AT (1 ms) but we allow a bit longer. if (!iec_wait_timeout_2ms(IO_DATA, IO_DATA)) { DEBUGF(DBG_ERROR, "write: no devs\n"); iec_release(IO_CLK | IO_ATN); usbIoDone(); return 0; } /* * Wait a short while for drive to be ready for us to release CLK. * This uses the typical value for IEC_T_NE. Even though it has no * minimum, the transfer starts to be unreliable for Tne somewhere * below 10 us. */ DELAY_US(IEC_T_NE); // Respond with data as soon as device is ready (max time Tne, 200 us). while (len != 0) { // Be sure DATA line has been pulled by device. If not, we timed // out without a device being ready. if (!iec_get(IO_DATA)) { DEBUGF(DBG_ERROR, "write: dev not pres\n"); rv = 0; break; } // Release CLK and wait forever for listener to release data. if (!wait_for_listener()) { DEBUGF(DBG_ERROR, "write: w4l abrt\n"); rv = 0; break; } /* * Signal EOI by waiting so long (IEC_T_YE, > 200 us) that * listener pulls DATA, then wait for it to be released. * The device will do so in IEC_T_EI, >= 60 us. * * If we're not signalling EOI, we must set CLK (below) in less * than 200 us after wait_for_listener() (IEC_T_RY). */ if (len == 1 && !atn) { iec_wait_timeout_2ms(IO_DATA, IO_DATA); iec_wait_timeout_2ms(IO_DATA, 0); } iec_set(IO_CLK); // Get a data byte from host, quitting if it signalled an abort. if (usbRecvByte(&data) != 0) { rv = 0; break; } if (send_byte(data)) { len--; DELAY_US(IEC_T_BB); } else { DEBUGF(DBG_ERROR, "write: io err\n"); rv = 0; break; } wdt_reset(); } usbIoDone(); /* * We rely on the per-byte IEC_T_BB delay (above) being more than * the minimum time before releasing ATN (IEC_T_R). */ if (rv != 0) { // Talk-ATN turn around (talker and listener exchange roles). if (talk) { // Hold DATA and release ATN, waiting talk-ATN release time. iec_set_release(IO_DATA, IO_ATN); DELAY_US(IEC_T_TK); // Now release CLK and wait for device to grab it. iec_release(IO_CLK); IEC_DELAY(); // Wait forever for device (IEC_T_DC). while (!iec_get(IO_CLK)) { if (!TimerWorker()) { rv = 0; break; } } } else iec_release(IO_ATN); } else { /* * If there was an error, release all lines before returning. * Delay the minimum time to releasing ATN after frame, just in * case the IEC_T_BB delay (above) was skipped. It is only performed * if send_byte() succeeded and not in this error case. */ DELAY_US(IEC_T_R); iec_release(IO_CLK | IO_ATN); } DEBUGF(DBG_INFO, "wrv=%d\n", rv); return rv; }
/* * Write bytes to the drive via the CBM default protocol. * Returns number of successful written bytes or 0 on error. */ static uint16_t ieee_raw_write(uint16_t len, uint8_t flags) { uint8_t atn, talk, data, device, sa; uint16_t rv; rv = len; atn = flags & XUM_WRITE_ATN; talk = flags & XUM_WRITE_TALK; eoi = 0; ieee_status = 0; usbInitIo(len, ENDPOINT_DIR_OUT); if(atn && len >= 1) { // get device# from USB if (usbRecvByte(&device) != 0) { return 0; } len--; if(len == 0 || ((device & 0x1f) == 0x1f)) { // unlisten, untalk if (device & 0x40) { IeeeUntalk(); } if (device & 0x20) { IeeeUnlisten(); } } else { // get secondary-address from USB if (usbRecvByte(&sa) != 0) { return 0; } len--; if (talk) { IeeeTalk(device, sa); len = 0; } else if(len > 2) { // open } else switch(sa & 0xf0) { case 0xE0: // close IeeeClose(device, sa); break; case 0xF0: // open IeeeOpen(device, sa, NULL); break; case 0x60: // listen IeeeListen(device, sa); break; default: // error???? break; } } } // send data // while (len != 0) { // Get a data byte from host, quitting if it signalled an abort. if (usbRecvByte(&data) != 0) { rv = 0; break; } if (IeeeBsout(data)) { rv = 0; break; } len--; // watchdog wdt_reset(); } usbIoDone(); return rv; }