summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-06-13 02:29:36 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-06-13 02:29:36 +0200
commit07e82c163ebf01bc4e96024980a874c06ebb59fb (patch)
tree033450b4d881e7f77cdb727ee2c106fd55b596ec
parent1dae3a82e2e709d0ff37687caba70b6154940636 (diff)
downloadrockbox-07e82c163ebf01bc4e96024980a874c06ebb59fb.tar.gz
rockbox-07e82c163ebf01bc4e96024980a874c06ebb59fb.zip
imxtools: rewrite sbloader to handle both versions + user friendly
The tool can now load sb1 and sb files to devices. Detection has been improved and the tool can infer the packet size for the HID description as well. The command line interface has been vastly improved too, this breaks the old one. Change-Id: I01a0ff8f8a007514aa81c56f114c0f0a86e3303c
-rw-r--r--utils/imxtools/sbtools/sbloader.c382
1 files changed, 346 insertions, 36 deletions
diff --git a/utils/imxtools/sbtools/sbloader.c b/utils/imxtools/sbtools/sbloader.c
index a5bc8c18fb..657ef5d578 100644
--- a/utils/imxtools/sbtools/sbloader.c
+++ b/utils/imxtools/sbtools/sbloader.c
@@ -23,12 +23,20 @@
23#include <string.h> 23#include <string.h>
24#include <libusb.h> 24#include <libusb.h>
25#include <stdint.h> 25#include <stdint.h>
26#include <stdbool.h>
27#include <getopt.h>
28
29bool g_debug = false;
26 30
27#ifndef MIN 31#ifndef MIN
28#define MIN(a,b) ((a) < (b) ? (a) : (b)) 32#define MIN(a,b) ((a) < (b) ? (a) : (b))
29#endif 33#endif
30 34
31void put32le(uint8_t *buf, uint32_t i) 35#ifndef MAX
36#define MAX(a,b) ((a) > (b) ? (a) : (b))
37#endif
38
39static void put32le(uint8_t *buf, uint32_t i)
32{ 40{
33 *buf++ = i & 0xff; 41 *buf++ = i & 0xff;
34 *buf++ = (i >> 8) & 0xff; 42 *buf++ = (i >> 8) & 0xff;
@@ -36,7 +44,7 @@ void put32le(uint8_t *buf, uint32_t i)
36 *buf++ = (i >> 24) & 0xff; 44 *buf++ = (i >> 24) & 0xff;
37} 45}
38 46
39void put32be(uint8_t *buf, uint32_t i) 47static void put32be(uint8_t *buf, uint32_t i)
40{ 48{
41 *buf++ = (i >> 24) & 0xff; 49 *buf++ = (i >> 24) & 0xff;
42 *buf++ = (i >> 16) & 0xff; 50 *buf++ = (i >> 16) & 0xff;
@@ -46,6 +54,7 @@ void put32be(uint8_t *buf, uint32_t i)
46 54
47enum dev_type_t 55enum dev_type_t
48{ 56{
57 PROBE_DEVICE,
49 HID_DEVICE, 58 HID_DEVICE,
50 RECOVERY_DEVICE, 59 RECOVERY_DEVICE,
51}; 60};
@@ -66,13 +75,10 @@ struct dev_info_t g_dev_info[] =
66 {0x066f, 0x3600, 4096, RECOVERY_DEVICE}, /* STMP36xx */ 75 {0x066f, 0x3600, 4096, RECOVERY_DEVICE}, /* STMP36xx */
67}; 76};
68 77
69int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers) 78static int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers)
70{ 79{
71 libusb_detach_kernel_driver(dev, 0); 80 libusb_detach_kernel_driver(dev, 0);
72 libusb_detach_kernel_driver(dev, 4);
73
74 libusb_claim_interface(dev, 0); 81 libusb_claim_interface(dev, 0);
75 libusb_claim_interface(dev, 4);
76 82
77 uint8_t *xfer_buf = malloc(1 + xfer_size); 83 uint8_t *xfer_buf = malloc(1 + xfer_size);
78 uint8_t *p = xfer_buf; 84 uint8_t *p = xfer_buf;
@@ -131,7 +137,7 @@ int send_hid(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size,
131 return ret; 137 return ret;
132} 138}
133 139
134int send_recovery(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers) 140static int send_recovery(libusb_device_handle *dev, int xfer_size, uint8_t *data, int size, int nr_xfers)
135{ 141{
136 (void) nr_xfers; 142 (void) nr_xfers;
137 // there should be no kernel driver attached but in doubt... 143 // there should be no kernel driver attached but in doubt...
@@ -159,52 +165,356 @@ int send_recovery(libusb_device_handle *dev, int xfer_size, uint8_t *data, int s
159 return 0; 165 return 0;
160} 166}
161 167
162int main(int argc, char **argv) 168static void usage(void)
163{ 169{
164 if(argc != 3) 170 printf("sbloader [options] file\n");
171 printf("options:\n");
172 printf(" -h/-?/--help Display this help\n");
173 printf(" -d/--debug Enable debug output\n");
174 printf(" -x <size> Force transfer size\n");
175 printf(" -u <vid>:<pid> Force USB PID and VID\n");
176 printf(" -b <bus>:<dev> Force USB bus and device\n");
177 printf(" -p <protocol> Force protocol ('hid' or 'recovery')\n");
178 printf("The following devices are known to this tool:\n");
179 for(unsigned i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++)
165 { 180 {
166 printf("usage: %s <xfer size> <file>\n", argv[0]); 181 const char *type = "unk";
167 printf("If <xfer size> is set to zero, the preferred one is used.\n"); 182 if(g_dev_info[i].dev_type == HID_DEVICE)
168 return 1; 183 type = "hid";
184 else if(g_dev_info[i].dev_type == RECOVERY_DEVICE)
185 type = "recovery";
186 else if(g_dev_info[i].dev_type == PROBE_DEVICE)
187 type = "probe";
188 printf(" %04x:%04x %s (%d bytes/xfer)\n", g_dev_info[i].vendor_id,
189 g_dev_info[i].product_id, type, g_dev_info[i].xfer_size);
169 } 190 }
191 printf("You can select a particular device by USB PID and VID.\n");
192 printf("In case this is ambiguous, use bus and device number.\n");
193 printf("Protocol is infered if possible and unspecified.\n");
194 printf("Transfer size is infered if possible.\n");
195 exit(1);
196}
197
198static bool dev_match(libusb_device *dev, struct dev_info_t *arg_di,
199 int usb_bus, int usb_dev, int *db_idx)
200{
201 // match bus/dev
202 if(usb_bus != -1)
203 return libusb_get_bus_number(dev) == usb_bus && libusb_get_device_address(dev) == usb_dev;
204 // get device descriptor
205 struct libusb_device_descriptor desc;
206 if(libusb_get_device_descriptor(dev, &desc))
207 return false;
208 // match command line vid/pid if specified
209 if(arg_di->vendor_id != 0)
210 return desc.idVendor == arg_di->vendor_id && desc.idProduct == arg_di->product_id;
211 // match known vid/pid
212 for(unsigned i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++)
213 if(desc.idVendor == g_dev_info[i].vendor_id && desc.idProduct == g_dev_info[i].product_id)
214 {
215 if(db_idx)
216 *db_idx = i;
217 return true;
218 }
219 return false;
220}
221
222static void print_match(libusb_device *dev)
223{
224 struct libusb_device_descriptor desc;
225 if(libusb_get_device_descriptor(dev, &desc))
226 printf("????:????");
227 else
228 printf("%04x:%04x", desc.idVendor, desc.idProduct);
229 printf(" @ %d.%d\n", libusb_get_bus_number(dev), libusb_get_device_address(dev));
230}
231
232static bool is_hid_dev(struct libusb_config_descriptor *desc)
233{
234 if(desc->bNumInterfaces != 1)
235 return false;
236 if(desc->interface[0].num_altsetting != 1)
237 return false;
238 const struct libusb_interface_descriptor *intf = &desc->interface[0].altsetting[0];
239 if(intf->bNumEndpoints != 1)
240 return false;
241 if(intf->bInterfaceClass != LIBUSB_CLASS_HID || intf->bInterfaceSubClass != 0 ||
242 intf->bInterfaceProtocol != 0)
243 return false;
244 return true;
245}
170 246
171 char *end; 247static bool is_recovery_dev(struct libusb_config_descriptor *desc)
172 int xfer_size = strtol(argv[1], &end, 0); 248{
173 if(end != (argv[1] + strlen(argv[1]))) 249 return false;
250}
251
252static enum dev_type_t probe_protocol(libusb_device_handle *dev)
253{
254 struct libusb_config_descriptor *desc;
255 if(libusb_get_config_descriptor(libusb_get_device(dev), 0, &desc))
256 goto Lerr;
257 if(is_hid_dev(desc))
258 return HID_DEVICE;
259 if(is_recovery_dev(desc))
260 return RECOVERY_DEVICE;
261 Lerr:
262 printf("Cannot probe protocol, please specify it on command line.\n");
263 exit(11);
264 return PROBE_DEVICE;
265}
266
267struct hid_item_t
268{
269 int tag;
270 int type;
271 int total_size;
272 int data_offset;
273 int data_size;
274};
275
276static bool hid_parse_short_item(uint8_t *buf, int size, struct hid_item_t *item)
277{
278 if(size == 0)
279 return false;
280 item->tag = buf[0] >> 4;
281 item->data_size = buf[0] & 3;
282 item->type = (buf[0] >> 2) & 3;
283 item->data_offset = 1;
284 item->total_size = 1 + item->data_size;
285 return size >= item->total_size;
286}
287
288static bool hid_parse_item(uint8_t *buf, int size, struct hid_item_t *item)
289{
290 if(!hid_parse_short_item(buf, size, item))
291 return false;
292 /* long item ? */
293 if(item->data_size == 2 && item->type == 3 && item->tag == 15)
174 { 294 {
175 printf("Invalid transfer size !\n"); 295 item->tag = buf[2];
176 return 1; 296 item->data_size = buf[1];
297 item->total_size = 3 + item->data_size;
298 return size >= item->total_size;
177 } 299 }
300 else
301 return true;
302}
303
304static int probe_hid_xfer_size(libusb_device_handle *dev)
305{
306 // FIXME detahc kernel and claim interface here ?
307 /* get HID descriptor */
308 uint8_t buffer[1024];
309 int ret = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_INTERFACE,
310 LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8) | 0, 0, buffer,
311 sizeof(buffer), 1000);
312 if(ret <= 0)
313 goto Lerr;
314 /* this is not a real parse, since the HID descriptor of the device is
315 * is mostly trivial, we assume that all reports are made up of one item
316 * and simply compute the maximum of report size * report count */
317 int xfer_size = 0;
318 int report_size = 0;
319 int report_count = 0;
320 uint8_t *buf = buffer;
321 int size = ret;
322 while(true)
323 {
324 struct hid_item_t item;
325 if(!hid_parse_item(buf, size, &item))
326 break;
327 if(item.type == /*global*/1)
328 {
329 if(item.tag == /*report count*/9)
330 report_count = buf[item.data_offset];
331 if(item.tag == /*report size*/7)
332 report_size = buf[item.data_offset];
333 }
334 else if(item.type == /*main*/0)
335 {
336 if(item.tag == /*output*/9)
337 xfer_size = MAX(xfer_size, report_count * report_size);
338 }
339 buf += item.total_size;
340 size -= item.total_size;
341 }
342 return xfer_size / 8;
178 343
179 libusb_device_handle *dev; 344 Lerr:
180 345 printf("Cannot probe transfer size, please specify it on command line.\n");
346 exit(11);
347 return 0;
348}
349
350static int probe_xfer_size(enum dev_type_t prot, libusb_device_handle *dev)
351{
352 if(prot == HID_DEVICE)
353 return probe_hid_xfer_size(dev);
354 printf("Cannot probe transfer size, please specify it on command line.\n");
355 exit(10);
356 return 0;
357}
358
359int main(int argc, char **argv)
360{
361 if(argc <= 1)
362 usage();
363 struct dev_info_t di = {.vendor_id = 0, .product_id = 0, .xfer_size = 0,
364 .dev_type = PROBE_DEVICE};
365 int usb_bus = -1;
366 int usb_dev = -1;
367 /* parse command line */
368 while(1)
369 {
370 static struct option long_options[] =
371 {
372 {"help", no_argument, 0, '?'},
373 {"debug", no_argument, 0, 'd'},
374 {0, 0, 0, 0}
375 };
376
377 int c = getopt_long(argc, argv, "?dx:u:b:p:", long_options, NULL);
378 if(c == -1)
379 break;
380 switch(c)
381 {
382 case -1:
383 break;
384 case 'd':
385 g_debug = true;
386 break;
387 case '?':
388 usage();
389 break;
390 case 'x':
391 {
392 char *end;
393 di.xfer_size = strtoul(optarg, &end, 0);
394 if(*end)
395 {
396 printf("Invalid transfer size!\n");
397 exit(2);
398 }
399 break;
400 }
401 case 'u':
402 {
403 char *end;
404 di.vendor_id = strtoul(optarg, &end, 16);
405 if(*end != ':')
406 {
407 printf("Invalid USB PID!\n");
408 exit(3);
409 }
410 di.product_id = strtoul(end + 1, &end, 16);
411 if(*end)
412 {
413 printf("Invalid USB VID!\n");
414 exit(4);
415 }
416 break;
417 }
418 case 'b':
419 {
420 char *end;
421 usb_bus = strtol(optarg, &end, 0);
422 if(*end != ':')
423 {
424 printf("Invalid USB bus!\n");
425 exit(5);
426 }
427 usb_dev = strtol(end, &end, 0);
428 if(*end)
429 {
430 printf("Invalid USB device!\n");
431 exit(6);
432 }
433 break;
434 }
435 case 'p':
436 if(strcmp(optarg, "hid") == 0)
437 di.dev_type = HID_DEVICE;
438 else if(strcmp(optarg, "recovery") == 0)
439 di.dev_type = RECOVERY_DEVICE;
440 else
441 {
442 printf("Invalid protocol!\n");
443 exit(7);
444 }
445 break;
446 default:
447 abort();
448 }
449 }
450
451 if(optind + 1 != argc)
452 usage();
453 const char *filename = argv[optind];
454 /* lookup device */
181 libusb_init(NULL); 455 libusb_init(NULL);
182
183 libusb_set_debug(NULL, 3); 456 libusb_set_debug(NULL, 3);
457 libusb_device **list;
458 ssize_t list_size = libusb_get_device_list(NULL, &list);
459 libusb_device_handle *dev = NULL;
460 int db_idx = -1;
184 461
185 unsigned i;
186 for(i = 0; i < sizeof(g_dev_info) / sizeof(g_dev_info[0]); i++)
187 { 462 {
188 dev = libusb_open_device_with_vid_pid(NULL, 463 libusb_device *mdev = NULL;
189 g_dev_info[i].vendor_id, g_dev_info[i].product_id); 464 int nr_matches = 0;
190 if(dev == NULL) 465 for(int i = 0; i < list_size; i++)
191 continue; 466 {
192 if(xfer_size == 0) 467 // match bus/dev if specified
193 xfer_size = g_dev_info[i].xfer_size; 468 if(dev_match(list[i], &di, usb_bus, usb_dev, &db_idx))
194 printf("Found a match for %04x:%04x\n", 469 {
195 g_dev_info[i].vendor_id, g_dev_info[i].product_id); 470 mdev = list[i];
196 break; 471 nr_matches++;
472 }
473 }
474 if(nr_matches == 0)
475 {
476 printf("No device found\n");
477 exit(8);
478 }
479 if(nr_matches > 1)
480 {
481 printf("Several devices match the specified parameters:\n");
482 for(int i = 0; i < list_size; i++)
483 {
484 // match bus/dev if specified
485 if(dev_match(list[i], &di, usb_bus, usb_dev, NULL))
486 {
487 printf(" ");
488 print_match(list[i]);
489 }
490 }
491 }
492 printf("Device: ");
493 print_match(mdev);
494 libusb_open(mdev, &dev);
197 } 495 }
198 if(dev == NULL) 496 if(dev == NULL)
199 { 497 {
200 printf("Cannot open device\n"); 498 printf("Cannot open device\n");
201 return 1; 499 return 1;
202 } 500 }
203 501 /* get protocol */
204 FILE *f = fopen(argv[2], "r"); 502 enum dev_type_t dev_type = PROBE_DEVICE;
503 int xfer_size = di.xfer_size;
504 if(db_idx >= 0)
505 {
506 dev_type = g_dev_info[db_idx].dev_type;
507 xfer_size = g_dev_info[db_idx].xfer_size;
508 }
509 if(dev_type == PROBE_DEVICE)
510 dev_type = probe_protocol(dev);
511 if(xfer_size == 0)
512 xfer_size = probe_xfer_size(dev_type, dev);
513 /* open file */
514 FILE *f = fopen(filename, "r");
205 if(f == NULL) 515 if(f == NULL)
206 { 516 {
207 perror("cannot open file"); 517 perror("Cannot open file");
208 return 1; 518 return 1;
209 } 519 }
210 fseek(f, 0, SEEK_END); 520 fseek(f, 0, SEEK_END);
@@ -222,8 +532,8 @@ int main(int argc, char **argv)
222 return 1; 532 return 1;
223 } 533 }
224 fclose(f); 534 fclose(f);
225 535 /* send file */
226 switch(g_dev_info[i].dev_type) 536 switch(dev_type)
227 { 537 {
228 case HID_DEVICE: 538 case HID_DEVICE:
229 send_hid(dev, xfer_size, file_buf, size, nr_xfers); 539 send_hid(dev, xfer_size, file_buf, size, nr_xfers);