summaryrefslogtreecommitdiff
path: root/utils/mks5lboot/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mks5lboot/main.c')
-rw-r--r--utils/mks5lboot/main.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/utils/mks5lboot/main.c b/utils/mks5lboot/main.c
new file mode 100644
index 0000000000..31e16eca82
--- /dev/null
+++ b/utils/mks5lboot/main.c
@@ -0,0 +1,296 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:$
9 *
10 * Copyright (C) 2015 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29
30#include "mks5lboot.h"
31
32/* Win32 compatibility */
33#ifndef O_BINARY
34#define O_BINARY 0
35#endif
36
37#ifdef WIN32
38#include <windows.h>
39#define sleep_ms(ms) Sleep(ms)
40#else
41#include <time.h>
42static void sleep_ms(unsigned int ms)
43{
44 struct timespec req;
45 req.tv_sec = ms / 1000;
46 req.tv_nsec = (ms % 1000) * 1000000;
47 nanosleep(&req, NULL);
48}
49#endif
50
51#define DEFAULT_LOOP_PERIOD 1 /* seconds */
52
53#define _ERR(format, ...) \
54 do { \
55 snprintf(errstr, errstrsize, "[ERR] "format, __VA_ARGS__); \
56 goto error; \
57 } while(0)
58
59static int write_file(char *outfile, unsigned char* buf,
60 int bufsize, char* errstr, int errstrsize)
61{
62 int fd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
63 if (fd < 0)
64 _ERR("Could not open %s for writing", outfile);
65
66 if (write(fd, buf, bufsize) != bufsize)
67 _ERR("Could not write file %s", outfile);
68
69 return 1;
70
71error:
72 return 0;
73}
74
75static unsigned char *read_file(char *infile, int *bufsize,
76 char* errstr, int errstrsize)
77{
78 unsigned char *buf;
79 int fd;
80 struct stat s;
81
82 fd = open(infile, O_RDONLY|O_BINARY);
83 if (fd < 0)
84 _ERR("Could not open %s for reading", infile);
85
86 if (fstat(fd, &s) < 0)
87 _ERR("Checking size of input file %s", infile);
88
89 *bufsize = s.st_size;
90
91 buf = malloc(*bufsize);
92 if (buf == NULL)
93 _ERR("Could not allocate memory for %s", infile);
94
95 if (read(fd, buf, *bufsize) != *bufsize)
96 _ERR("Could not read file %s", infile);
97
98 return buf;
99
100error:
101 return NULL;
102}
103
104static void usage(void)
105{
106 fprintf(stderr,
107 "Usage:\n"
108 " mks5lboot --bl-inst <bootloader.ipod> [-p <pid>] [--single]\n"
109 " --bl-uninst <platform> [-p <pid>]\n"
110 " --dfuscan [--loop [<sec>]] [-p <pid>]\n"
111 " --dfusend <infile.dfu> [-p <pid>]\n"
112 " --dfureset [--loop [<sec>]] [-p <pid>]\n"
113 " --mkdfu-inst <bootloader.ipod> <outfile.dfu> [--single]\n"
114 " --mkdfu-uninst <platform> <outfile.dfu>\n"
115 " --mkdfu-raw <filename.bin> <outfile.dfu>\n"
116 "\n"
117 "Commands:\n"
118 " --bl-inst Install file <bootloader.ipod> into an iPod device\n"
119 " (same as --mkdfu-inst and --dfusend).\n"
120 " --bl-uninst Remove a bootloader from an iPod device (same as\n"
121 " --mkdfu-uninst and --dfusend).\n"
122 "\n"
123 " --dfuscan scan for DFU USB devices and outputs the status.\n"
124 " --dfusend send DFU image <infile.dfu> to the device.\n"
125 " --dfureset reset DFU USB device bus.\n"
126 "\n"
127 " --mkdfu-inst Build a DFU image containing an installer for\n"
128 " <bootloader.ipod>, save it as <outfile.dfu>.\n"
129 " --mkdfu-uninst Build a DFU image containing an uninstaler for\n"
130 " <platform> devices, save it as <outfile.dfu>.\n"
131 " --mkdfu-raw Build a DFU image containing raw executable\n"
132 " code, save it ass <outfile.dfu>. <infile.bin>\n"
133 " is the code you want to run, it is loaded at\n"
134 " address 0x%08x and executed.\n"
135 "\n"
136 " <bootloader.ipod> is the rockbox bootloader that you want to\n"
137 " install (previously scrambled with tools/scramble utility).\n"
138 "\n"
139 " <platform> is the name of the platform (type of device) for\n"
140 " which the DFU uninstaller will be built. Currently supported\n"
141 " platform names are:\n"
142 " ipod6g: iPod Classic 6G\n"
143 "\n"
144 "Options:\n"
145 " -p, --pid <pid> Use a specific <pid> (Product Id) USB device,\n"
146 " if this option is ommited then it uses the\n"
147 " first USB DFU device found.\n"
148 " -l, --loop <sec> Run the command every <sec> seconds, default\n"
149 " period (<sec> ommited) is %d seconds.\n"
150 " -S, --single Be careful using this option. The bootloader\n"
151 " is installed for single boot, the original\n"
152 " Apple NOR boot is destroyed (if it exists),\n"
153 " and only Rockbox can be used.\n"
154 , DFU_LOADADDR + BIN_OFFSET
155 , DEFAULT_LOOP_PERIOD);
156
157 exit(1);
158}
159
160int main(int argc, char* argv[])
161{
162 char *dfuoutfile = NULL;
163 char *dfuinfile = NULL;
164 char *dfu_arg = NULL;
165 int dfu_type = DFU_NONE;
166 int n_cmds = 0;
167 int scan = 0;
168 int pid = 0;
169 int reset = 0;
170 int loop = 0;
171 int single = 0;
172 char errstr[200];
173 unsigned char *dfubuf;
174 int dfusize;
175
176 fprintf(stderr,
177#if defined(WIN32) && defined(USE_LIBUSBAPI)
178 "mks5lboot Version " VERSION " (libusb)\n"
179#else
180 "mks5lboot Version " VERSION "\n"
181#endif
182 "This is free software; see the source for copying conditions. There is NO\n"
183 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
184 "\n");
185 fflush(stderr);
186
187 while (--argc)
188 {
189 argv++;
190 if (!memcmp(*argv, "--bl", 4)) {
191 if (!strcmp(*argv+4, "-inst")) dfu_type = DFU_INST;
192 else if (!strcmp(*argv+4, "-uninst")) dfu_type = DFU_UNINST;
193 else usage();
194 if (!--argc) usage();
195 dfu_arg = *++argv;
196 n_cmds++;
197 }
198 else if (!memcmp(*argv, "--mkdfu", 7)) {
199 if (!strcmp(*argv+7, "-inst")) dfu_type = DFU_INST;
200 else if (!strcmp(*argv+7, "-uninst")) dfu_type = DFU_UNINST;
201 else if (!strcmp(*argv+7, "-raw")) dfu_type = DFU_RAW;
202 else usage();
203 if (!--argc) usage();
204 dfu_arg = *++argv;
205 if (!--argc) usage();
206 dfuoutfile = *++argv;
207 n_cmds++;
208 }
209 else if (!strcmp(*argv, "--dfusend")) {
210 if (!--argc) usage();
211 dfuinfile = *++argv;
212 n_cmds++;
213 }
214 else if (!strcmp(*argv, "--dfuscan")) {
215 scan = 1;
216 n_cmds++;
217 }
218 else if (!strcmp(*argv, "--dfureset")) {
219 scan = 1;
220 reset = 1;
221 n_cmds++;
222 }
223 else if (!strcmp(*argv, "--pid") || !strcmp(*argv, "-p")) {
224 if (!--argc) usage();
225 if (sscanf(*++argv, "%x", &pid) != 1) usage();
226 }
227 else if (!strcmp(*argv, "--loop") || !strcmp (*argv, "-l")) {
228 if (!(argc-1) || *(argv+1)[0] == '-') {
229 loop = DEFAULT_LOOP_PERIOD;
230 }
231 else {
232 if ((sscanf(*++argv, "%d", &loop) != 1) || !loop) usage();
233 argc--;
234 }
235 }
236 else if (!strcmp(*argv, "--single") || !strcmp(*argv, "-S")) {
237 single = 1;
238 }
239 else if (!strcmp(*argv, "--debug")) {
240 ipoddfu_debug(1);
241 }
242 else
243 usage();
244 }
245
246 if (n_cmds != 1)
247 usage();
248
249 if ((dfu_type == DFU_INST) && single)
250 dfu_type = DFU_INST_SINGLE;
251
252 if (scan) {
253 int cnt = 0;
254 while (1) {
255 int state, res;
256 if (loop) printf("[%d] ", cnt);
257 else printf("[INFO] ");
258 printf("DFU %s:\n", reset ? "reset":"scan");
259 res = ipoddfu_scan(pid, &state, reset, errstr, sizeof(errstr));
260 if (res == 0)
261 printf("%s\n", errstr);
262 else
263 printf("[INFO] DFU device state: %d\n", state);
264 if (!loop)
265 exit(!res);
266 fflush(stdout);
267 sleep_ms(loop*1000);
268 cnt += loop;
269 }
270 }
271
272 if (dfuinfile)
273 dfubuf = read_file(dfuinfile, &dfusize, errstr, sizeof(errstr));
274 else
275 dfubuf = mkdfu(dfu_type, dfu_arg, &dfusize, errstr, sizeof(errstr));
276
277 if (!dfubuf)
278 goto error;
279
280 if (dfuoutfile) {
281 if (write_file(dfuoutfile, dfubuf, dfusize, errstr, sizeof(errstr))) {
282 printf("[INFO] Created file %s (%d bytes)\n", dfuoutfile, dfusize);
283 exit(0);
284 }
285 }
286 else {
287 if (ipoddfu_send(pid, dfubuf, dfusize, errstr, sizeof(errstr))) {
288 printf("[INFO] DFU image sent successfully (%d bytes)\n", dfusize);
289 exit(0);
290 }
291 }
292
293error:
294 printf("%s\n", errstr);
295 exit(1);
296}