-
Notifications
You must be signed in to change notification settings - Fork 0
/
usb64drive.c
178 lines (138 loc) · 3.75 KB
/
usb64drive.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//
// usb64drive.c
//
// usb64drive; A open-source 64drive library.
// Copyright (C) 2014, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "usb64drive.h"
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifndef __USE_MISC
#define __USE_MISC
#include <termios.h>
#undef __USE_MISC
#endif
#define DEV_CMD_LOADRAM 0x20
#define DEV_CMD_DUMPRAM 0x30
#define DEV_CMD_SETSAVE 0x70
#define DEV_CMD_GETVER 0x80
#define DEV_CMD_UPGRADE 0x84
#define DEV_CMD_UPGREPORT 0x85
#define DEV_CMD_PI_RD_32 0x90
#define DEV_CMD_PI_WR_32 0x91
#define DEV_CMD_PI_WR_BL 0x94
#define DEV_CMD_PI_WR_BL_LONG 0x95
#define BANK_INVALID 0
#define BANK_CARTROM 1
#define BANK_SRAM256 2
#define BANK_SRAM768 3
#define BANK_FLASHRAM1M 4
#define BANK_FLASHPKM1M 5
#define BANK_EEPROM16 6
#define BANK_LAST 7
static ssize_t usb64drive_send_rw_cmd(int fd, int cmd,
int bank, size_t addr, uint8_t *host_buf, size_t size);
static const uint8_t usb64drive_dev_magic[] = {0x55, 0x44, 0x45, 0x56};
void usb64drive_close(int fd) {
close(fd);
}
int usb64drive_open(const char *path) {
struct termios tty;
int fd;
if ((fd = open(path, O_RDWR | O_NOCTTY | O_SYNC)) < 0)
return -1;
memset(&tty, 0, sizeof(tty));
if (tcgetattr(fd, &tty) != 0)
return -1;
cfsetispeed(&tty, B9600);
cfsetospeed(&tty, B9600);
// 8-bit chars.
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
// Ignore break signal.
tty.c_iflag &= ~IGNBRK;
// No signaling chars.
tty.c_lflag = 0;
// No remapping, no delays.
tty.c_oflag = 0;
// No blocking reads, 0.5 sec read timeout.
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 5;
// Shut off XON/XOFF.
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
// Ignore modem controls, enable reading.
tty.c_cflag |= (CLOCAL | CREAD);
// Shut off parity.
tty.c_cflag &= ~(PARENB | PARODD | CMSPAR);
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
// Gimme my CR.
tty.c_iflag &= ~(ICRNL | INLCR);
if (tcsetattr(fd, TCSANOW, &tty) != 0)
return -1;
return fd;
}
int usb64drive_get_version(int fd, unsigned *version) {
uint8_t tx[4] = {DEV_CMD_GETVER, 0x43, 0x4D, 0x44};
uint8_t rx[8];
if (write(fd, tx, sizeof(tx)) != sizeof(tx))
return -1;
if (read(fd, rx, sizeof(rx)) != sizeof(rx))
return -1;
// Check magic.
if (memcmp(rx + 4, usb64drive_dev_magic, sizeof(usb64drive_dev_magic))) {
errno = EPROTO;
return -1;
}
*version =
(rx[0] << 24) |
(rx[1] << 16) |
(rx[2] << 8 ) |
(rx[3] << 0 );
return 0;
}
ssize_t usb64drive_send_rw_cmd(int fd, int cmd,
int bank, size_t addr, uint8_t *host_buf, size_t size) {
ssize_t i, chk;
uint8_t tx[12] = {
cmd, 0x43, 0x4D, 0x44,
addr >> 24, addr >> 16, addr >> 8, addr >> 0,
bank, size >> 16, size >> 8, size
};
if (write(fd, tx, sizeof(tx)) != sizeof(tx))
return -1;
size &= 0x00FFFFFFU;
for (i = 0; i < (ssize_t) size; i += chk) {
if ((chk = (cmd == DEV_CMD_DUMPRAM)
? read(fd, host_buf + i, size - i)
: write(fd, host_buf + i, size - i)
) < 0) {
return -1;
}
}
return size;
}
int usb64drive_write_rom(int fd, FILE *f) {
uint8_t buf[32768];
size_t addr;
for (addr = 0; !feof(f); addr += sizeof(buf)) {
while (fread(buf, sizeof(buf), 1, f) != 1) {
if (feof(f))
break;
if (ferror(f))
return -1;
}
if (usb64drive_send_rw_cmd(fd, DEV_CMD_LOADRAM,
BANK_CARTROM, addr, buf, sizeof(buf)) < 0)
return 0;
}
return 0;
}