Index: firmware/target/arm/ata-sd-pp.c =================================================================== --- firmware/target/arm/ata-sd-pp.c (Revision 17762) +++ firmware/target/arm/ata-sd-pp.c (Arbeitskopie) @@ -478,6 +478,30 @@ } while (--cnt > 0); /* tail loop is faster */ } +#ifdef SANSA_E200 +static inline void copy_write_sectors_usb(const unsigned char** buf) +{ + /* No need to check for alignment as the USB buffer will always be aligned. */ + asm volatile ( + "ldmia %[buf]!, { r2, r4, r6, r8 } \r\n" + "mov r3, r2, lsr #16 \r\n" + "mov r5, r4, lsr #16 \r\n" + "mov r7, r6, lsr #16 \r\n" + "mov r9, r8, lsr #16 \r\n" + "stmia %[data], { r2-r9 } \r\n" + "ldmia %[buf]!, { r2, r4, r6, r8 } \r\n" + "mov r3, r2, lsr #16 \r\n" + "mov r5, r4, lsr #16 \r\n" + "mov r7, r6, lsr #16 \r\n" + "mov r9, r8, lsr #16 \r\n" + "stmia %[data], { r2-r9 } \r\n" + : [buf]"+&r"(*buf) + : [data]"r"(&DATA_REG) + : "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" + ); +} +#endif + static int sd_select_bank(unsigned char bank) { unsigned char card_data[512]; @@ -975,26 +999,56 @@ buf_end = outbuf + count * currcard->block_size - 2*FIFO_LEN; - for (buf = outbuf; buf <= buf_end;) +#ifdef SANSA_E200 + if (usb_exclusive_ata()) { - if (buf == buf_end) + /* Duplicating the loop to avoid calling usb_exclusive_ata() inside. */ + for (buf = outbuf; buf <= buf_end;) { - /* Set SD_STATE_REG to PRG for the last buffer fill */ - SD_STATE_REG = PRG; - } + if (buf == buf_end) + { + /* Set SD_STATE_REG to PRG for the last buffer fill */ + SD_STATE_REG = PRG; + } - udelay(2); /* needed here (loop is too fast :-) */ + /* Wait for the FIFO to empty */ + /* Not using sd_poll_status here because yielding */ + /* may disturb the timing. */ + while ((STATUS_REG & FIFO_EMPTY) == 0); + + udelay(3); /* Needed on e200. */ + /* Too short or too long delay will raise */ + /* the 'two bytes inserted' bug. */ + /* Too short delay may cause lockup as well. */ - /* Wait for the FIFO to empty */ - if (sd_poll_status(FIFO_EMPTY, 0x80000)) - { - copy_write_sectors(&buf); /* Copy one chunk of 16 words */ + copy_write_sectors_usb(&buf); /* TODO: Switch bank if necessary */ - continue; } + } + else +#endif + { + for (buf = outbuf; buf <= buf_end;) + { + if (buf == buf_end) + { + /* Set SD_STATE_REG to PRG for the last buffer fill */ + SD_STATE_REG = PRG; + } - ret = -EC_FIFO_WR_EMPTY; - goto ata_write_error; + udelay(2); /* needed here (loop is too fast :-) */ + + /* Wait for the FIFO to empty */ + if (sd_poll_status(FIFO_EMPTY, 0x80000)) + { + copy_write_sectors(&buf); /* Copy one chunk of 16 words */ + /* TODO: Switch bank if necessary */ + continue; + } + + ret = -EC_FIFO_WR_EMPTY; + goto ata_write_error; + } } last_disk_activity = current_tick;