summaryrefslogtreecommitdiff
path: root/utils/e200tool/e200load.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2014-04-07 22:25:06 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2014-04-07 22:25:06 +0200
commit399acc038750943c1a0ee7178a18714334871472 (patch)
tree343079cb893fe9b27d66455d0459536764b0865a /utils/e200tool/e200load.c
parent68370b6eea8b5bed54e82a07086ad7c81cc966dd (diff)
downloadrockbox-399acc038750943c1a0ee7178a18714334871472.tar.gz
rockbox-399acc038750943c1a0ee7178a18714334871472.zip
Add new tool to upload code on e200/c200/view in manufacturer mode
This is actually the trivial part of e200tool from MrH: it simply writes the code on the bulk endpoint. Code was mostly copied from imxtools/sbloader. Change-Id: I6c208840d23553aaf3bd8b9374e6b0337e54f3b0
Diffstat (limited to 'utils/e200tool/e200load.c')
-rw-r--r--utils/e200tool/e200load.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/utils/e200tool/e200load.c b/utils/e200tool/e200load.c
new file mode 100644
index 0000000000..8e5005b1f8
--- /dev/null
+++ b/utils/e200tool/e200load.c
@@ -0,0 +1,310 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 Amaury Pouly
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#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <libusb.h>
25#include <stdint.h>
26#include <stdbool.h>
27#include <getopt.h>
28
29bool g_debug = false;
30
31struct dev_info_t
32{
33 uint16_t vendor_id;
34 uint16_t product_id;
35 unsigned xfer_size;
36};
37
38struct dev_info_t g_dev_info[] =
39{
40 {0x0781, 0x0720, 64}, /* Sandisk E200/C200/View */
41 {0x0b70, 0x0003, 64}, /* Portal Player */
42};
43
44#ifndef MIN
45#define MIN(a,b) ((a) < (b) ? (a) : (b))
46#endif
47
48#ifndef MAX
49#define MAX(a,b) ((a) > (b) ? (a) : (b))
50#endif
51
52static void put32le(uint8_t *buf, uint32_t i)
53{
54 *buf++ = i & 0xff;
55 *buf++ = (i >> 8) & 0xff;
56 *buf++ = (i >> 16) & 0xff;
57 *buf++ = (i >> 24) & 0xff;
58}
59
60static int send_recovery(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size)
61{
62 // there should be no kernel driver attached but in doubt...
63 libusb_detach_kernel_driver(dev, 0);
64 libusb_claim_interface(dev, 0);
65
66 uint8_t size_buffer[4];
67 put32le(size_buffer, size);
68 int xfered;
69 int ret = libusb_bulk_transfer(dev, 1, size_buffer, sizeof(size_buffer), &xfered, 1000);
70 if(ret < 0 || xfered != sizeof(size_buffer))
71 {
72 printf("transfer error at init step: %d", ret);
73 return 1;
74 }
75
76 int sent = 0;
77 while(sent < size)
78 {
79 int xfered;
80 int len = MIN(size - sent, xfer_size);
81 int ret = libusb_bulk_transfer(dev, 1, data + sent, len, &xfered, 1000);
82 if(ret < 0 || xfered != len)
83 {
84 printf("transfer error at send offset %d: %d\n", sent, ret);
85 return 1;
86 }
87 sent += xfered;
88 }
89 return 0;
90}
91
92static void usage(void)
93{
94 printf("sbloader [options] file\n");
95 printf("options:\n");
96 printf(" -h/-?/--help Display this help\n");
97 printf(" -d/--debug Enable debug output\n");
98 printf(" -x <size> Force transfer size\n");
99 printf(" -u <vid>:<pid> Force USB PID and VID\n");
100 printf(" -b <bus>:<dev> Force USB bus and device\n");
101 printf("The following devices are known to this tool:\n");
102 for(unsigned i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++)
103 {
104 printf(" %04x:%04x (%d bytes/xfer)\n", g_dev_info[i].vendor_id,
105 g_dev_info[i].product_id, g_dev_info[i].xfer_size);
106 }
107 printf("You can select a particular device by USB PID and VID.\n");
108 printf("In case this is ambiguous, use bus and device number.\n");
109 printf("Protocol is infered if possible and unspecified.\n");
110 printf("Transfer size is infered if possible.\n");
111 exit(1);
112}
113
114static bool dev_match(libusb_device *dev, struct dev_info_t *arg_di,
115 int usb_bus, int usb_dev, int *db_idx)
116{
117 // match bus/dev
118 if(usb_bus != -1)
119 return libusb_get_bus_number(dev) == usb_bus && libusb_get_device_address(dev) == usb_dev;
120 // get device descriptor
121 struct libusb_device_descriptor desc;
122 if(libusb_get_device_descriptor(dev, &desc))
123 return false;
124 // match command line vid/pid if specified
125 if(arg_di->vendor_id != 0)
126 return desc.idVendor == arg_di->vendor_id && desc.idProduct == arg_di->product_id;
127 // match known vid/pid
128 for(unsigned i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++)
129 if(desc.idVendor == g_dev_info[i].vendor_id && desc.idProduct == g_dev_info[i].product_id)
130 {
131 if(db_idx)
132 *db_idx = i;
133 return true;
134 }
135 return false;
136}
137
138static void print_match(libusb_device *dev)
139{
140 struct libusb_device_descriptor desc;
141 if(libusb_get_device_descriptor(dev, &desc))
142 printf("????:????");
143 else
144 printf("%04x:%04x", desc.idVendor, desc.idProduct);
145 printf(" @ %d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
146}
147
148int main(int argc, char **argv)
149{
150 if(argc <= 1)
151 usage();
152 struct dev_info_t di = {.vendor_id = 0, .product_id = 0, .xfer_size = 64};
153 int usb_bus = -1;
154 int usb_dev = -1;
155 int force_xfer_size = 0;
156 /* parse command line */
157 while(1)
158 {
159 static struct option long_options[] =
160 {
161 {"help", no_argument, 0, '?'},
162 {"debug", no_argument, 0, 'd'},
163 {0, 0, 0, 0}
164 };
165
166 int c = getopt_long(argc, argv, "?dx:u:b:p:", long_options, NULL);
167 if(c == -1)
168 break;
169 switch(c)
170 {
171 case -1:
172 break;
173 case 'd':
174 g_debug = true;
175 break;
176 case '?':
177 usage();
178 break;
179 case 'x':
180 {
181 char *end;
182 force_xfer_size = strtoul(optarg, &end, 0);
183 if(*end)
184 {
185 printf("Invalid transfer size!\n");
186 exit(2);
187 }
188 break;
189 }
190 case 'u':
191 {
192 char *end;
193 di.vendor_id = strtoul(optarg, &end, 16);
194 if(*end != ':')
195 {
196 printf("Invalid USB PID!\n");
197 exit(3);
198 }
199 di.product_id = strtoul(end + 1, &end, 16);
200 if(*end)
201 {
202 printf("Invalid USB VID!\n");
203 exit(4);
204 }
205 break;
206 }
207 case 'b':
208 {
209 char *end;
210 usb_bus = strtol(optarg, &end, 0);
211 if(*end != ':')
212 {
213 printf("Invalid USB bus!\n");
214 exit(5);
215 }
216 usb_dev = strtol(end, &end, 0);
217 if(*end)
218 {
219 printf("Invalid USB device!\n");
220 exit(6);
221 }
222 break;
223 }
224 default:
225 printf("Internal error: unknown option '%c'\n", c);
226 abort();
227 }
228 }
229
230 if(optind + 1 != argc)
231 usage();
232 const char *filename = argv[optind];
233 /* lookup device */
234 libusb_init(NULL);
235 libusb_set_debug(NULL, 3);
236 libusb_device **list;
237 ssize_t list_size = libusb_get_device_list(NULL, &list);
238 libusb_device_handle *dev = NULL;
239 int db_idx = -1;
240
241 {
242 libusb_device *mdev = NULL;
243 int nr_matches = 0;
244 for(int i = 0; i < list_size; i++)
245 {
246 // match bus/dev if specified
247 if(dev_match(list[i], &di, usb_bus, usb_dev, &db_idx))
248 {
249 mdev = list[i];
250 nr_matches++;
251 }
252 }
253 if(nr_matches == 0)
254 {
255 printf("No device found\n");
256 exit(8);
257 }
258 if(nr_matches > 1)
259 {
260 printf("Several devices match the specified parameters:\n");
261 for(int i = 0; i < list_size; i++)
262 {
263 // match bus/dev if specified
264 if(dev_match(list[i], &di, usb_bus, usb_dev, NULL))
265 {
266 printf(" ");
267 print_match(list[i]);
268 }
269 }
270 }
271 printf("Device: ");
272 print_match(mdev);
273 libusb_open(mdev, &dev);
274 }
275 if(dev == NULL)
276 {
277 printf("Cannot open device\n");
278 return 1;
279 }
280 /* get protocol */
281 int xfer_size = di.xfer_size;
282 if(db_idx >= 0)
283 xfer_size = g_dev_info[db_idx].xfer_size;
284 if(force_xfer_size > 0)
285 xfer_size = force_xfer_size;
286 /* open file */
287 FILE *f = fopen(filename, "r");
288 if(f == NULL)
289 {
290 perror("Cannot open file");
291 return 1;
292 }
293 fseek(f, 0, SEEK_END);
294 size_t size = ftell(f);
295 fseek(f, 0, SEEK_SET);
296
297 printf("Transfer size: %d\n", xfer_size);
298 uint8_t *file_buf = malloc(size);
299 if(fread(file_buf, size, 1, f) != 1)
300 {
301 perror("read error");
302 fclose(f);
303 return 1;
304 }
305 fclose(f);
306 /* send file */
307 return send_recovery(dev, xfer_size, file_buf, size);
308}
309
310