mega-usb: initial code
[megadrive.git] / mega-usb / mega-usb.c
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
12 static 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
46 static 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
60 static 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
77 static 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
97 static 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
120 int 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 }