1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-01-11 23:43:04 +00:00
2025-07-27 23:20:42 +02:00

331 lines
8.1 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "user_io.h"
#include "data_io.h"
#include "debug.h"
#include "spi.h"
#ifdef HAVE_QSPI
#include "qspi.h"
#endif
// core supports direct ROM upload via SS4
char rom_direct_upload = 0;
static data_io_processor_t* PROCESSORS[MAX_DATA_IO_PROCESSORS];
void data_io_init() {
memset(PROCESSORS, 0, sizeof(PROCESSORS));
}
void data_io_set_index(char index) {
EnableFpga();
SPI(DIO_FILE_INDEX);
SPI(index);
DisableFpga();
}
void data_io_file_tx_start(void) {
EnableFpga();
SPI(DIO_FILE_TX);
SPI(0xff);
DisableFpga();
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI)
qspi_start_write();
#endif
}
void data_io_file_tx_done(void) {
// signal end of transmission
EnableFpga();
SPI(DIO_FILE_TX);
SPI(0x00);
DisableFpga();
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI)
qspi_end();
#endif
iprintf("\n");
}
///////////////////////////
// TRANSMIT FILE TO FPGA //
///////////////////////////
void data_io_file_tx_prepare(FIL *file, char index, const char *ext) {
char e[3];
iprintf("Preparing transmission for index %d\n", index);
e[0] = e[1] = e[2] = ' ';
if (ext) {
if (ext[0]) e[0] = toupper(ext[0]);
if (ext[1]) e[1] = toupper(ext[1]);
if (ext[2]) e[2] = toupper(ext[2]);
}
// set index byte (0=bios rom, 1-n=OSD entry index)
data_io_set_index(index);
// send directory entry
EnableFpga();
SPI(DIO_FILE_INFO);
FSIZE_t fsize = f_size(file);
spi_n(0, 8); // name
spi8(e[0]);spi8(e[1]);spi8(e[2]); // ext
spi8(file->obj.attr); // attr
spi8(0); // unsigned char LowerCase; /* NT VFAT lower case flags */
spi8(0); // unsigned char CreateHundredth; /* hundredth of seconds in CTime */
spi16(0); // unsigned short CreateTime; /* create time */
spi16(0); // unsigned short CreateDate; /* create date */
spi16(0); // unsigned short AccessDate; /* access date */
spi16le(file->obj.sclust >> 16); // unsigned short HighCluster; /* high bytes of cluster number */
spi16(0); // unsigned short ModifyTime; /* last update time */
spi16(0); // unsigned short ModifyDate; /* last update date */
spi16le(file->obj.sclust); // unsigned short StartCluster; /* starting cluster of file */
spi32le(fsize);
DisableFpga();
// prepare transmission of new file
data_io_file_tx_start();
}
static void data_io_file_tx_send(FIL *file) {
FSIZE_t bytes2send = f_size(file);
UINT br;
/* transmit the entire file using one transfer */
iprintf("Selected %llu bytes to send\n", bytes2send);
while(bytes2send) {
iprintf(".");
unsigned short c, chunk = (bytes2send>SECTOR_BUFFER_SIZE)?SECTOR_BUFFER_SIZE:bytes2send;
char *p;
if (rom_direct_upload && fat_uses_mmc()) {
// upload directly from the SD-Card if the core supports that
bytes2send = (file->obj.objsize + 511) & 0xfffffe00;
file->obj.objsize = bytes2send; // hack to foul FatFs think the last block is a full sector
DISKLED_ON
f_read(file, 0, bytes2send, &br);
DISKLED_OFF
bytes2send = 0;
} else {
DISKLED_ON
f_read(file, sector_buffer, chunk, &br);
DISKLED_OFF
#ifdef HAVE_QSPI
if (user_io_get_core_features() & FEAT_QSPI) {
qspi_write_block(sector_buffer, chunk);
} else {
#endif
EnableFpga();
SPI(DIO_FILE_TX_DAT);
// spi_write(sector_buffer, chunk); // DMA -- too fast for some cores
for(p = sector_buffer, c=0;c < chunk;c++)
SPI(*p++);
DisableFpga();
#ifdef HAVE_QSPI
}
#endif
bytes2send -= chunk;
}
}
}
static void data_io_file_tx_fill(unsigned char fill, unsigned int len) {
EnableFpga();
SPI(DIO_FILE_TX_DAT);
while(len--) {
SPI(fill);
}
DisableFpga();
}
void data_io_file_tx(FIL *file, char index, const char *ext) {
data_io_file_tx_prepare(file, index, ext);
data_io_file_tx_send(file);
data_io_file_tx_done();
}
static data_io_processor_t* data_io_get_processor(const char *processor_id) {
for (int i = 0; i < MAX_DATA_IO_PROCESSORS; i++) {
if (PROCESSORS[i]) {
if (PROCESSORS[i]->id && strncmp(PROCESSORS[i]->id, processor_id, 3) == 0) {
return PROCESSORS[i];
}
} else {
break;
}
}
return NULL;
}
char data_io_add_processor(data_io_processor_t *processor) {
if (processor) {
for (int i = 0; i < MAX_DATA_IO_PROCESSORS; i++) {
if (!PROCESSORS[i]) {
PROCESSORS[i] = processor;
return 0;
}
}
}
return -1;
}
void data_io_file_tx_processor(FIL *file, char index, const char *ext, const char *name, const char *processor_id) {
iprintf("data_io_file_tx_processor idx: %d ext: %s\n", index, ext);
data_io_processor_t *processor;
if (processor_id && (processor = data_io_get_processor(processor_id))) {
processor->file_tx_send(file, index, name, ext);
} else {
iprintf("Processor for %s not found. Defaulting to normal upload\n", processor_id);
data_io_file_tx_prepare(file, index, ext);
data_io_file_tx_send(file);
data_io_file_tx_done();
}
}
// send 'fill' byte 'len' times
void data_io_fill_tx(unsigned char fill, unsigned int len, char index) {
data_io_file_tx_prepare(0, index, 0);
data_io_file_tx_fill(fill, len);
data_io_file_tx_done();
}
////////////////////////////
// RECEIVE FILE FROM FPGA //
////////////////////////////
static void data_io_file_rx_prepare(char index) {
iprintf("Preparing receiving for index %d\n", index);
// set index byte (0=bios rom, 1-n=OSD entry index)
data_io_set_index(index);
// prepare transmission of new file
EnableFpga();
SPI(DIO_FILE_RX);
SPI(0xff);
DisableFpga();
}
static void data_io_file_rx_receive(FIL *file, unsigned int len) {
unsigned int bytes2receive = len;
char first = 1;
UINT bw;
/* receive the entire file using one transfer */
iprintf("Selected %lu bytes to receive\n", bytes2receive);
while(bytes2receive) {
iprintf(".");
unsigned short c, chunk = (bytes2receive>2048)?2048:bytes2receive;
char *p;
EnableFpga();
SPI(DIO_FILE_RX_DAT);
if (first) {
SPI(0);
first=0;
}
for(p = sector_buffer, c=0;c < chunk;c++)
*p++ = SPI(0xFF);
DisableFpga();
bytes2receive -= chunk;
DISKLED_ON
f_write(file, sector_buffer, chunk, &bw);
DISKLED_OFF
}
}
static void data_io_file_rx_done(void) {
// signal end of transmission
EnableFpga();
SPI(DIO_FILE_RX);
SPI(0x00);
DisableFpga();
iprintf("\n");
}
void data_io_file_rx(FIL *file, char index, unsigned int len) {
data_io_file_rx_prepare(index);
data_io_file_rx_receive(file, len);
data_io_file_rx_done();
}
////////////////
// ROM UPLOAD //
////////////////
void data_io_rom_upload(char *rname, char mode) {
FIL file;
FRESULT res;
static char first = 1;
char fname[67];
// new ini parsing starts, prepare uploads
if(mode == 0) {
first = 1;
return;
}
// ini parsing done
if(mode == 2) {
// has something been uploaded?
// -> then end transfer
if(!first) {
iprintf("upload ends\n");
data_io_file_tx_done();
user_io_8bit_set_status(0, UIO_STATUS_RESET);
}
return;
}
// try to change into core dir. Stay in root if that doesn't exist
user_io_change_into_core_dir();
strncpy(fname, rname, sizeof(fname)-5);
fname[sizeof(fname)-6] = 0;
strcat(fname,".ROM");
iprintf("rom upload '%s'\n", fname);
res=f_open(&file, fname, FA_READ);
if (res== FR_OK) {
if(first) {
// set reset
user_io_8bit_set_status(UIO_STATUS_RESET, UIO_STATUS_RESET);
data_io_file_tx_prepare(&file, 0, "ROM");
first = 0;
}
// user_io_file_tx(&f, 0);
data_io_file_tx_send(&file);
f_close(&file);
} else
iprintf("Error opening file %s (%d)!\n", fname, res);
ChangeDirectoryName("/");
ScanDirectory(SCAN_INIT, "RBF", SCAN_LFN | SCAN_SYSDIR);
}