X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hexed%2Fpc_transfer.c;fp=hexed%2Fpc_transfer.c;h=2263a6d232cba6683606965725a4077fda5d14b8;hb=8689c962a08dd52e25725851316aa51a7e22d432;hp=844054fc3f25b6f8d5ab3643456d15537b086e4d;hpb=d13f0e289f5e87d65926c09ba46b72d4e94eaeb3;p=megadrive.git diff --git a/hexed/pc_transfer.c b/hexed/pc_transfer.c index 844054f..2263a6d 100644 --- a/hexed/pc_transfer.c +++ b/hexed/pc_transfer.c @@ -1,8 +1,12 @@ #include #include +#include #include #include #include +#include + +#include "transfer.h" /* * PC: @@ -26,47 +30,189 @@ * 7 TH --> 10 ACK * 8 GND --- 21 GND * 9 TR <-- 17 /SLCT_IN + * + * start: TH low/high, TL high + * + * TH low - lower nibble: MD ready to recv | MD sent to PC + * TL low - lower niblle: sent to MD | ready to recv from MD + * TH high - upper nibble: MD ready to recv | MD sent to PC + * TL high - upper nibble: sent | ready to recv from MD */ -static void inthandler(int u) +#define ACK_TIMEOUT 2000000 + +#define PORT_DATA 888 +#define PORT_STATUS 889 +#define PORT_CONTROL 890 + +#define timediff(now, start) \ + ((now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec) + +static void do_exit(const char *msg) { /* switch TL back to high */ - outb(0xe0, 890); - printf("\n"); + outb(0xe0, PORT_CONTROL); + + if (msg) + printf("%s", msg); exit(1); } -int main(int argc, char *argv[]) +static void inthandler(int u) { - int size, byte, ret, i; - unsigned char *data; - char *p = NULL; - FILE *file; + do_exit("\n"); +} - if (argc != 4 || argv[1][0] != '-' || (argv[1][1] != 'r' && argv[1][1] != 'w')) { - printf("usage:\n%s {-r,-w} \n", argv[0]); - return 1; +static void wait_th_low(void) +{ + struct timeval start, now; + + gettimeofday(&start, NULL); + + while (inb(PORT_STATUS) & 0x40) { + gettimeofday(&now, NULL); + if (timediff(now, start) > ACK_TIMEOUT) + do_exit("timeout waiting TH low\n"); } +} - file = fopen(argv[2], argv[1][1] == 'r' ? "wb" : "rb"); - if (file == NULL) { - fprintf(stderr, "can't open file: %s\n", argv[2]); - return 1; +static void wait_th_high(void) +{ + struct timeval start, now; + + gettimeofday(&start, NULL); + + while (!(inb(PORT_STATUS) & 0x40)) { + gettimeofday(&now, NULL); + if (timediff(now, start) > ACK_TIMEOUT) + do_exit("timeout waiting TH high\n"); } +} + +static unsigned int recv_byte(void) +{ + unsigned int byte; + + outb(0xe2, PORT_CONTROL); /* TL low */ + + wait_th_low(); + + byte = inb(PORT_DATA) & 0x0f; + + outb(0xe0, PORT_CONTROL); /* TL high */ + + wait_th_high(); + + byte |= inb(PORT_DATA) << 4; + + return byte; +} + +static void send_byte(unsigned int byte) +{ + wait_th_low(); + + outb(byte & 0x0f, PORT_DATA); + outb(0xc2, PORT_CONTROL); /* TL low */ + + wait_th_high(); + + outb((byte >> 4) & 0x0f, PORT_DATA); + outb(0xc0, PORT_CONTROL); /* TL high */ +} + +static void send_cmd(unsigned int cmd) +{ + send_byte(CMD_PREFIX); + send_byte(cmd); +} + +static void usage(const char *argv0) +{ + fprintf(stderr, "usage:\n%s [args]\n" + "\tsend [size]\n" + "\trecv \n", argv0); + exit(1); +} + +static unsigned int atoi_or_die(const char *a) +{ + char *p = NULL; + unsigned int i; - size = (int)strtoul(argv[3], &p, 16); + i = strtoul(a, &p, 0); if (p == NULL || *p != 0) { - fprintf(stderr, "can't convert size %s\n", argv[3]); - return 1; + fprintf(stderr, "atoi: can't convert: %s\n", a); + exit(1); } - data = malloc(size); + return i; +} + +int main(int argc, char *argv[]) +{ + unsigned int addr = 0, size = 0, i = 0; + int ret; + unsigned char *data; + FILE *file = NULL; + + if (argc < 2) + usage(argv[0]); + + data = malloc(0x1000000); if (data == NULL) { - fprintf(stderr, "can't alloc %d bytes\n", size); + fprintf(stderr, "can't alloc %d bytes\n", 0x1000000); return 1; } - ret = ioperm(888, 3, 1); + /* parse args, read files.. */ + if (strcmp(argv[1], "send") == 0) + { + if (argc != 4 && argc != 5) + usage(argv[0]); + + file = fopen(argv[2], "rb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", argv[2]); + return 1; + } + + addr = atoi_or_die(argv[3]); + if (argv[4] == NULL) { + fseek(file, 0, SEEK_END); + size = ftell(file); + fseek(file, 0, SEEK_SET); + } + else + size = atoi_or_die(argv[4]); + + ret = fread(data, 1, size, file); + if (ret != size) { + fprintf(stderr, "fread returned %d/%d\n", ret, size); + perror(NULL); + return 1; + } + } + else if (strcmp(argv[1], "recv") == 0) + { + if (argc != 5) + usage(argv[0]); + + file = fopen(argv[2], "wb"); + if (file == NULL) { + fprintf(stderr, "can't open file: %s\n", argv[2]); + return 1; + } + + addr = atoi_or_die(argv[3]); + size = atoi_or_die(argv[4]); + + memset(data, 0, size); + } + else + usage(argv[0]); + + ret = ioperm(PORT_DATA, 3, 1); if (ret != 0) { perror("ioperm"); return 1; @@ -74,16 +220,28 @@ int main(int argc, char *argv[]) signal(SIGINT, inthandler); - printf("regs: %02x %02x %02x\n", inb(888), inb(889), inb(890)); - outb(0xe0, 890); + printf("regs: %02x %02x %02x\n", + inb(PORT_DATA), inb(PORT_STATUS), inb(PORT_CONTROL)); + outb(0xe8, PORT_CONTROL); /* TR low - request for transfer */ - while (!(inb(889) & 0x40)) { - printf("waiting for TH..\n"); - sleep(5); - } + if (inb(PORT_STATUS) & 0x40) + printf("waiting for TH low..\n"); + while (inb(PORT_STATUS) & 0x40) + sleep(1); + + outb(0xe0, PORT_CONTROL); - if (argv[1][1] == 'r') + if (strcmp(argv[1], "send") == 0) { + printf("send %06x %06x\n", addr, size); + send_cmd(CMD_MD_SEND); + send_byte((addr >> 16) & 0xff); + send_byte((addr >> 8) & 0xff); + send_byte((addr >> 0) & 0xff); + send_byte((size >> 16) & 0xff); + send_byte((size >> 8) & 0xff); + send_byte((size >> 0) & 0xff); + for (i = 0; i < size; i++) { if ((i & 0xff) == 0) { @@ -92,33 +250,19 @@ int main(int argc, char *argv[]) fflush(stdout); } - outb(0xe2, 890); /* TL low */ - - /* wait for TH low */ - while (inb(889) & 0x40) ; - - byte = inb(888) & 0x0f; - - outb(0xe0, 890); /* TL high */ - - /* wait for TH high */ - while (!(inb(889) & 0x40)) ; - - byte |= inb(888) << 4; - data[i] = byte; + send_byte(data[i]); } - - fwrite(data, 1, size, file); } - else + else if (strcmp(argv[1], "recv") == 0) { - ret = fread(data, 1, size, file); - if (ret < size) - printf("warning: read only %d/%d\n", ret, size); - - outb(0xc0, 890); /* out mode, TL hi */ - outb(data[0] & 0x0f, 888); - outb(0xc2, 890); /* out mode, TL low (start condition) */ + send_cmd(CMD_MD_RECV); + send_byte((addr >> 16) & 0xff); + send_byte((addr >> 8) & 0xff); + send_byte((addr >> 0) & 0xff); + send_byte((size >> 16) & 0xff); + send_byte((size >> 8) & 0xff); + send_byte((size >> 0) & 0xff); + outb(0xe0, PORT_CONTROL); /* TL high, recv mode */ for (i = 0; i < size; i++) { @@ -128,25 +272,18 @@ int main(int argc, char *argv[]) fflush(stdout); } - /* wait for TH low */ - while (inb(889) & 0x40) ; - - byte = data[i]; - - outb(byte & 0x0f, 888); - outb(0xc2, 890); /* TL low */ - - /* wait for TH high */ - while (!(inb(889) & 0x40)) ; - - outb(byte >> 4, 888); - outb(0xc0, 890); /* TL high */ + data[i] = recv_byte(); } + + fwrite(data, 1, size, file); } printf("\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf("%06x/%06x\n", i, size); fclose(file); + /* switch TL back to high, disable outputs */ + outb(0xe0, PORT_CONTROL); + return 0; }