mega-usb: initial code
[megadrive.git] / mega-usb / mega-usb.c
CommitLineData
9f5a788d 1#define _BSD_SOURCE
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <termios.h>
10#include <unistd.h>
11
12static int setup(int fd)
13{
14 speed_t ispeed, ospeed;
15 struct termios tty;
16 int ret;
17
18 memset(&tty, 0, sizeof(tty));
19
20 ret = tcgetattr(fd, &tty);
21 if (ret != 0)
22 {
23 perror("tcgetattr");
24 return 1;
25 }
26
27 tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
28 | INLCR | IGNCR | ICRNL | IXON);
29 tty.c_oflag &= ~OPOST;
30 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
31 tty.c_cflag &= ~(CSIZE | PARENB);
32 tty.c_cflag |= CS8;
33
34 //tty.c_cc[VMIN] = 1;
35 //tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
36
37 ret = tcsetattr(fd, TCSANOW, &tty);
38 if (ret != 0) {
39 perror("tcsetattr");
40 return ret;
41 }
42
43 return 0;
44}
45
46static int write_to_cart(int fd, const void *data, size_t size)
47{
48 int ret;
49
50 ret = write(fd, data, size);
51 if (ret != size) {
52 perror("write");
53 exit(1);
54 //return -1;
55 }
56
57 return 0;
58}
59
60static int read_from_cart(int fd, void *data, size_t size)
61{
62 int ret;
63
64 ret = read(fd, data, size);
65 if (ret != (int)size) {
66 perror("read");
67 exit(1);
68 //return -1;
69 }
70
71 return 0;
72}
73
74#define send_cmd(fd, cmd) \
75 write_to_cart(fd, cmd, sizeof(cmd) - 1)
76
77static int read_check_byte(int fd, char expect)
78{
79 char r = '0';
80 int ret;
81
82 ret = read_from_cart(fd, &r, 1);
83 if (ret != 0) {
84 fprintf(stderr, "missing response, need '%c'\n", expect);
85 return -1;
86 }
87
88 if (r != expect) {
89 fprintf(stderr, "unexpected response: '%c', need '%c'\n",
90 r, expect);
91 return -1;
92 }
93
94 return 0;
95}
96
97static int write_with_check(int fd, const void *data, size_t size, char chk)
98{
99 int ret;
100
101 ret = write_to_cart(fd, data, size);
102 if (ret)
103 return ret;
104
105 ret = read_check_byte(fd, chk);
106 if (ret != 0) {
107 if (size < 16)
108 fprintf(stderr, "data sent: '%16s'\n",
109 (const char *)data);
110 exit(1);
111 //return -1;
112 }
113
114 return 0;
115}
116
117#define send_cmd_check_k(fd, cmd) \
118 write_with_check(fd, cmd, sizeof(cmd) - 1, 'k')
119
120int main(int argc, char *argv[])
121{
122 const char *portname = "/dev/ttyUSB0";
123 char buf[0x10000];
124 size_t size;
125 int blocks;
126 FILE *f;
127 int ret;
128 int fd;
129 int i;
130
131 fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
132 if (fd < 0) {
133 perror("open");
134 return 1;
135 }
136
137 setup(fd);
138
139 send_cmd_check_k(fd, " *T");
140
141 if (argv[1] != NULL)
142 {
143 f = fopen(argv[1], "rb");
144 if (f == NULL)
145 {
146 perror("fopen");
147 return 1;
148 }
149 fseek(f, 0, SEEK_END);
150 size = ftell(f);
151 fseek(f, 0, SEEK_SET);
152 if (size > 0xf00000) {
153 fprintf(stderr, "size too large: %zd\n", size);
154 return 1;
155 }
156
157 blocks = (size + 0xffff) >> 16;
158 send_cmd(fd, "*g");
159 write_with_check(fd, &blocks, 1, 'k');
160
161 // at this point, 'd' will arrive even if we don't
162 // write any more data, what's the point of that?
163
164 for (i = 0; i < blocks; i++) {
165 ret = fread(buf, 1, sizeof(buf), f);
166 if (i != blocks - 1 && ret != sizeof(buf)) {
167 fprintf(stderr, "failed to read block %d/%d\n",
168 i, blocks);
169 }
170 if (ret < sizeof(buf))
171 memset(buf + ret, 0, sizeof(buf) - ret);
172
173 write_to_cart(fd, buf, sizeof(buf));
174 }
175
176 ret = read_check_byte(fd, 'd');
177 if (ret)
178 return 1;
179
180 send_cmd_check_k(fd, "*rm");
181 }
182
183 printf("all ok\n");
184
185 return 0;
186}