4fd6ccf1f197b4bb84596ab265eed6d1d4175ba1
[pub/USBasp.git] / Bootloaders / HID / HostLoaderApp / hid_bootloader_cli.c
1 /* Modified for the LUFA HID Bootloader by Dean Camera
2 * http://www.lufa-lib.org
3 *
4 * THIS MODIFIED VERSION IS UNSUPPORTED BY PJRC.
5 */
6
7 /* Teensy Loader, Command Line Interface
8 * Program and Reboot Teensy Board with HalfKay Bootloader
9 * http://www.pjrc.com/teensy/loader_cli.html
10 * Copyright 2008-2010, PJRC.COM, LLC
11 *
12 *
13 * You may redistribute this program and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software
15 * Foundation, version 3 of the License.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see http://www.gnu.org/licenses/
24 */
25
26 /* Want to incorporate this code into a proprietary application??
27 * Just email paul@pjrc.com to ask. Usually it's not a problem,
28 * but you do need to ask to use this code in any way other than
29 * those permitted by the GNU General Public License, version 3 */
30
31 /* For non-root permissions on ubuntu or similar udev-based linux
32 * http://www.pjrc.com/teensy/49-teensy.rules
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 void usage(void)
43 {
44 fprintf(stderr, "Usage: hid_bootloader_cli -mmcu=<MCU> [-w] [-h] [-n] [-v] <file.hex>\n");
45 fprintf(stderr, "\t-w : Wait for device to appear\n");
46 fprintf(stderr, "\t-r : Use hard reboot if device not online\n");
47 fprintf(stderr, "\t-n : No reboot after programming\n");
48 fprintf(stderr, "\t-v : Verbose output\n");
49 fprintf(stderr, "\n<MCU> = atmegaXXuY or at90usbXXXY");
50
51 fprintf(stderr, "\nFor support and more information, please visit:\n");
52 fprintf(stderr, "http://www.lufa-lib.org\n");
53
54 fprintf(stderr, "\nBased on the TeensyHID command line programmer software:\n");
55 fprintf(stderr, "http://www.pjrc.com/teensy/loader_cli.html\n");
56 exit(1);
57 }
58
59 // USB Access Functions
60 int teensy_open(void);
61 int teensy_write(void *buf, int len, double timeout);
62 void teensy_close(void);
63 int hard_reboot(void);
64
65 // Intel Hex File Functions
66 int read_intel_hex(const char *filename);
67 int ihex_bytes_within_range(int begin, int end);
68 void ihex_get_data(int addr, int len, unsigned char *bytes);
69
70 // Misc stuff
71 int printf_verbose(const char *format, ...);
72 void delay(double seconds);
73 void die(const char *str, ...);
74 void parse_options(int argc, char **argv);
75
76 // options (from user via command line args)
77 int wait_for_device_to_appear = 0;
78 int hard_reboot_device = 0;
79 int reboot_after_programming = 1;
80 int verbose = 0;
81 int code_size = 0, block_size = 0;
82 const char *filename=NULL;
83
84
85 /****************************************************************/
86 /* */
87 /* Main Program */
88 /* */
89 /****************************************************************/
90
91 int main(int argc, char **argv)
92 {
93 unsigned char buf[260];
94 int num, addr, r, first_block=1, waited=0;
95
96 // parse command line arguments
97 parse_options(argc, argv);
98 if (!filename) {
99 fprintf(stderr, "Filename must be specified\n\n");
100 usage();
101 }
102 if (!code_size) {
103 fprintf(stderr, "MCU type must be specified\n\n");
104 usage();
105 }
106 printf_verbose("Teensy Loader, Command Line, Version 2.0\n");
107
108 // read the intel hex file
109 // this is done first so any error is reported before using USB
110 num = read_intel_hex(filename);
111 if (num < 0) die("error reading intel hex file \"%s\"", filename);
112 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
113 filename, num, (double)num / (double)code_size * 100.0);
114
115 // open the USB device
116 while (1) {
117 if (teensy_open()) break;
118 if (hard_reboot_device) {
119 if (!hard_reboot()) die("Unable to find rebootor\n");
120 printf_verbose("Hard Reboot performed\n");
121 hard_reboot_device = 0; // only hard reboot once
122 wait_for_device_to_appear = 1;
123 }
124 if (!wait_for_device_to_appear) die("Unable to open device\n");
125 if (!waited) {
126 printf_verbose("Waiting for Teensy device...\n");
127 printf_verbose(" (hint: press the reset button)\n");
128 waited = 1;
129 }
130 delay(0.25);
131 }
132 printf_verbose("Found HalfKay Bootloader\n");
133
134 // if we waited for the device, read the hex file again
135 // perhaps it changed while we were waiting?
136 if (waited) {
137 num = read_intel_hex(filename);
138 if (num < 0) die("error reading intel hex file \"%s\"", filename);
139 printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n",
140 filename, num, (double)num / (double)code_size * 100.0);
141 }
142
143 // program the data
144 printf_verbose("Programming");
145 fflush(stdout);
146 for (addr = 0; addr < code_size; addr += block_size) {
147 if (addr > 0 && !ihex_bytes_within_range(addr, addr + block_size - 1)) {
148 // don't waste time on blocks that are unused,
149 // but always do the first one to erase the chip
150 continue;
151 }
152 printf_verbose(".");
153 if (code_size < 0x10000) {
154 buf[0] = addr & 255;
155 buf[1] = (addr >> 8) & 255;
156 } else {
157 buf[0] = (addr >> 8) & 255;
158 buf[1] = (addr >> 16) & 255;
159 }
160 ihex_get_data(addr, block_size, buf + 2);
161 r = teensy_write(buf, block_size + 2, first_block ? 3.0 : 0.25);
162 if (!r) die("error writing to Teensy\n");
163 first_block = 0;
164 }
165 printf_verbose("\n");
166
167 // reboot to the user's new code
168 if (reboot_after_programming) {
169 printf_verbose("Booting\n");
170 buf[0] = 0xFF;
171 buf[1] = 0xFF;
172 memset(buf + 2, 0, sizeof(buf) - 2);
173 teensy_write(buf, block_size + 2, 0.25);
174 }
175 teensy_close();
176 return 0;
177 }
178
179
180
181
182 /****************************************************************/
183 /* */
184 /* USB Access - libusb (Linux & FreeBSD) */
185 /* */
186 /****************************************************************/
187
188 #if defined(USE_LIBUSB)
189
190 // http://libusb.sourceforge.net/doc/index.html
191 #include <usb.h>
192
193 usb_dev_handle * open_usb_device(int vid, int pid)
194 {
195 struct usb_bus *bus;
196 struct usb_device *dev;
197 usb_dev_handle *h;
198 char buf[128];
199 int r;
200
201 usb_init();
202 usb_find_busses();
203 usb_find_devices();
204 //printf_verbose("\nSearching for USB device:\n");
205 for (bus = usb_get_busses(); bus; bus = bus->next) {
206 for (dev = bus->devices; dev; dev = dev->next) {
207 //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n",
208 // bus->dirname, dev->filename,
209 // dev->descriptor.idVendor,
210 // dev->descriptor.idProduct
211 //);
212 if (dev->descriptor.idVendor != vid) continue;
213 if (dev->descriptor.idProduct != pid) continue;
214 h = usb_open(dev);
215 if (!h) {
216 printf_verbose("Found device but unable to open");
217 continue;
218 }
219 #ifdef LIBUSB_HAS_GET_DRIVER_NP
220 r = usb_get_driver_np(h, 0, buf, sizeof(buf));
221 if (r >= 0) {
222 r = usb_detach_kernel_driver_np(h, 0);
223 if (r < 0) {
224 usb_close(h);
225 printf_verbose("Device is in use by \"%s\" driver", buf);
226 continue;
227 }
228 }
229 #endif
230 // Mac OS-X - removing this call to usb_claim_interface() might allow
231 // this to work, even though it is a clear misuse of the libusb API.
232 // normally Apple's IOKit should be used on Mac OS-X
233 r = usb_claim_interface(h, 0);
234 if (r < 0) {
235 usb_close(h);
236 printf_verbose("Unable to claim interface, check USB permissions");
237 continue;
238 }
239 return h;
240 }
241 }
242 return NULL;
243 }
244
245 static usb_dev_handle *libusb_teensy_handle = NULL;
246
247 int teensy_open(void)
248 {
249 teensy_close();
250 libusb_teensy_handle = open_usb_device(0x16C0, 0x0478);
251
252 if (!libusb_teensy_handle)
253 libusb_teensy_handle = open_usb_device(0x03eb, 0x2067);
254
255 if (!libusb_teensy_handle) return 0;
256 return 1;
257 }
258
259 int teensy_write(void *buf, int len, double timeout)
260 {
261 int r;
262
263 if (!libusb_teensy_handle) return 0;
264 r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0, (char *)buf,
265 len, (int)(timeout * 1000.0));
266 if (r < 0) return 0;
267 return 1;
268 }
269
270 void teensy_close(void)
271 {
272 if (!libusb_teensy_handle) return;
273 usb_release_interface(libusb_teensy_handle, 0);
274 usb_close(libusb_teensy_handle);
275 libusb_teensy_handle = NULL;
276 }
277
278 int hard_reboot(void)
279 {
280 usb_dev_handle *rebootor;
281 int r;
282
283 rebootor = open_usb_device(0x16C0, 0x0477);
284
285 if (!rebootor)
286 rebootor = open_usb_device(0x03eb, 0x2067);
287
288 if (!rebootor) return 0;
289 r = usb_control_msg(rebootor, 0x21, 9, 0x0200, 0, "reboot", 6, 100);
290 usb_release_interface(rebootor, 0);
291 usb_close(rebootor);
292 if (r < 0) return 0;
293 return 1;
294 }
295
296 #endif
297
298
299 /****************************************************************/
300 /* */
301 /* USB Access - Microsoft WIN32 */
302 /* */
303 /****************************************************************/
304
305 #if defined(USE_WIN32)
306
307 // http://msdn.microsoft.com/en-us/library/ms790932.aspx
308 #include <windows.h>
309 #include <setupapi.h>
310 #include <ddk/hidsdi.h>
311 #include <ddk/hidclass.h>
312
313 HANDLE open_usb_device(int vid, int pid)
314 {
315 GUID guid;
316 HDEVINFO info;
317 DWORD index, required_size;
318 SP_DEVICE_INTERFACE_DATA iface;
319 SP_DEVICE_INTERFACE_DETAIL_DATA *details;
320 HIDD_ATTRIBUTES attrib;
321 HANDLE h;
322 BOOL ret;
323
324 HidD_GetHidGuid(&guid);
325 info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
326 if (info == INVALID_HANDLE_VALUE) return NULL;
327 for (index=0; 1 ;index++) {
328 iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
329 ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
330 if (!ret) {
331 SetupDiDestroyDeviceInfoList(info);
332 break;
333 }
334 SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL);
335 details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size);
336 if (details == NULL) continue;
337 memset(details, 0, required_size);
338 details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
339 ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
340 required_size, NULL, NULL);
341 if (!ret) {
342 free(details);
343 continue;
344 }
345 h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
346 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
347 FILE_FLAG_OVERLAPPED, NULL);
348 free(details);
349 if (h == INVALID_HANDLE_VALUE) continue;
350 attrib.Size = sizeof(HIDD_ATTRIBUTES);
351 ret = HidD_GetAttributes(h, &attrib);
352 if (!ret) {
353 CloseHandle(h);
354 continue;
355 }
356 if (attrib.VendorID != vid || attrib.ProductID != pid) {
357 CloseHandle(h);
358 continue;
359 }
360 SetupDiDestroyDeviceInfoList(info);
361 return h;
362 }
363 return NULL;
364 }
365
366 int write_usb_device(HANDLE h, void *buf, int len, int timeout)
367 {
368 static HANDLE event = NULL;
369 unsigned char tmpbuf[1040];
370 OVERLAPPED ov;
371 DWORD n, r;
372
373 if (len > sizeof(tmpbuf) - 1) return 0;
374 if (event == NULL) {
375 event = CreateEvent(NULL, TRUE, TRUE, NULL);
376 if (!event) return 0;
377 }
378 ResetEvent(&event);
379 memset(&ov, 0, sizeof(ov));
380 ov.hEvent = event;
381 tmpbuf[0] = 0;
382 memcpy(tmpbuf + 1, buf, len);
383 if (!WriteFile(h, tmpbuf, len + 1, NULL, &ov)) {
384 if (GetLastError() != ERROR_IO_PENDING) return 0;
385 r = WaitForSingleObject(event, timeout);
386 if (r == WAIT_TIMEOUT) {
387 CancelIo(h);
388 return 0;
389 }
390 if (r != WAIT_OBJECT_0) return 0;
391 }
392 if (!GetOverlappedResult(h, &ov, &n, FALSE)) return 0;
393 if (n <= 0) return 0;
394 return 1;
395 }
396
397 void print_win32_err(void)
398 {
399 char buf[256];
400 DWORD err;
401
402 err = GetLastError();
403 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
404 0, buf, sizeof(buf), NULL);
405 printf("err %ld: %s\n", err, buf);
406 }
407
408 static HANDLE win32_teensy_handle = NULL;
409
410 int teensy_open(void)
411 {
412 teensy_close();
413 win32_teensy_handle = open_usb_device(0x16C0, 0x0478);
414
415 if (!win32_teensy_handle)
416 win32_teensy_handle = open_usb_device(0x03eb, 0x2067);
417
418 if (!win32_teensy_handle) return 0;
419 return 1;
420 }
421
422 int teensy_write(void *buf, int len, double timeout)
423 {
424 int r;
425 if (!win32_teensy_handle) return 0;
426 r = write_usb_device(win32_teensy_handle, buf, len, (int)(timeout * 1000.0));
427 return r;
428 }
429
430 void teensy_close(void)
431 {
432 if (!win32_teensy_handle) return;
433 CloseHandle(win32_teensy_handle);
434 win32_teensy_handle = NULL;
435 }
436
437 int hard_reboot(void)
438 {
439 HANDLE rebootor;
440 int r;
441
442 rebootor = open_usb_device(0x16C0, 0x0477);
443
444 if (!rebootor)
445 rebootor = open_usb_device(0x03eb, 0x2067);
446
447 if (!rebootor) return 0;
448 r = write_usb_device(rebootor, "reboot", 6, 100);
449 CloseHandle(rebootor);
450 return r;
451 }
452
453 #endif
454
455
456
457 /****************************************************************/
458 /* */
459 /* USB Access - Apple's IOKit, Mac OS-X */
460 /* */
461 /****************************************************************/
462
463 #if defined(USE_APPLE_IOKIT)
464
465 // http://developer.apple.com/technotes/tn2007/tn2187.html
466 #include <IOKit/IOKitLib.h>
467 #include <IOKit/hid/IOHIDLib.h>
468 #include <IOKit/hid/IOHIDDevice.h>
469
470 struct usb_list_struct {
471 IOHIDDeviceRef ref;
472 int pid;
473 int vid;
474 struct usb_list_struct *next;
475 };
476
477 static struct usb_list_struct *usb_list=NULL;
478 static IOHIDManagerRef hid_manager=NULL;
479
480 void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
481 {
482 CFTypeRef type;
483 struct usb_list_struct *n, *p;
484 int32_t pid, vid;
485
486 if (!dev) return;
487 type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey));
488 if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
489 if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &vid)) return;
490 type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey));
491 if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
492 if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &pid)) return;
493 n = (struct usb_list_struct *)malloc(sizeof(struct usb_list_struct));
494 if (!n) return;
495 //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid);
496 n->ref = dev;
497 n->vid = vid;
498 n->pid = pid;
499 n->next = NULL;
500 if (usb_list == NULL) {
501 usb_list = n;
502 } else {
503 for (p = usb_list; p->next; p = p->next) ;
504 p->next = n;
505 }
506 }
507
508 void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
509 {
510 struct usb_list_struct *p, *tmp, *prev=NULL;
511
512 p = usb_list;
513 while (p) {
514 if (p->ref == dev) {
515 if (prev) {
516 prev->next = p->next;
517 } else {
518 usb_list = p->next;
519 }
520 tmp = p;
521 p = p->next;
522 free(tmp);
523 } else {
524 prev = p;
525 p = p->next;
526 }
527 }
528 }
529
530 void init_hid_manager(void)
531 {
532 CFMutableDictionaryRef dict;
533 IOReturn ret;
534
535 if (hid_manager) return;
536 hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
537 if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
538 if (hid_manager) CFRelease(hid_manager);
539 printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n");
540 return;
541 }
542 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
543 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
544 if (!dict) return;
545 IOHIDManagerSetDeviceMatching(hid_manager, dict);
546 CFRelease(dict);
547 IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
548 IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL);
549 IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL);
550 ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
551 if (ret != kIOReturnSuccess) {
552 IOHIDManagerUnscheduleFromRunLoop(hid_manager,
553 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
554 CFRelease(hid_manager);
555 printf_verbose("Error opening HID Manager");
556 }
557 }
558
559 static void do_run_loop(void)
560 {
561 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
562 }
563
564 IOHIDDeviceRef open_usb_device(int vid, int pid)
565 {
566 struct usb_list_struct *p;
567 IOReturn ret;
568
569 init_hid_manager();
570 do_run_loop();
571 for (p = usb_list; p; p = p->next) {
572 if (p->vid == vid && p->pid == pid) {
573 ret = IOHIDDeviceOpen(p->ref, kIOHIDOptionsTypeNone);
574 if (ret == kIOReturnSuccess) return p->ref;
575 }
576 }
577 return NULL;
578 }
579
580 void close_usb_device(IOHIDDeviceRef dev)
581 {
582 struct usb_list_struct *p;
583
584 do_run_loop();
585 for (p = usb_list; p; p = p->next) {
586 if (p->ref == dev) {
587 IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone);
588 return;
589 }
590 }
591 }
592
593 static IOHIDDeviceRef iokit_teensy_reference = NULL;
594
595 int teensy_open(void)
596 {
597 teensy_close();
598 iokit_teensy_reference = open_usb_device(0x16C0, 0x0478);
599
600 if (!iokit_teensy_reference)
601 iokit_teensy_reference = open_usb_device(0x03eb, 0x2067);
602
603 if (!iokit_teensy_reference) return 0;
604 return 1;
605 }
606
607 int teensy_write(void *buf, int len, double timeout)
608 {
609 IOReturn ret;
610
611 // timeouts do not work on OS-X
612 // IOHIDDeviceSetReportWithCallback is not implemented
613 // even though Apple documents it with a code example!
614 // submitted to Apple on 22-sep-2009, problem ID 7245050
615 if (!iokit_teensy_reference) return 0;
616 ret = IOHIDDeviceSetReport(iokit_teensy_reference,
617 kIOHIDReportTypeOutput, 0, buf, len);
618 if (ret == kIOReturnSuccess) return 1;
619 return 0;
620 }
621
622 void teensy_close(void)
623 {
624 if (!iokit_teensy_reference) return;
625 close_usb_device(iokit_teensy_reference);
626 iokit_teensy_reference = NULL;
627 }
628
629 int hard_reboot(void)
630 {
631 IOHIDDeviceRef rebootor;
632 IOReturn ret;
633
634 rebootor = open_usb_device(0x16C0, 0x0477);
635
636 if (!rebootor)
637 rebootor = open_usb_device(0x03eb, 0x2067);
638
639 if (!rebootor) return 0;
640 ret = IOHIDDeviceSetReport(rebootor,
641 kIOHIDReportTypeOutput, 0, (uint8_t *)("reboot"), 6);
642 close_usb_device(rebootor);
643 if (ret == kIOReturnSuccess) return 1;
644 return 0;
645 }
646
647 #endif
648
649
650
651 /****************************************************************/
652 /* */
653 /* USB Access - BSD's UHID driver */
654 /* */
655 /****************************************************************/
656
657 #if defined(USE_UHID)
658
659 // Thanks to Todd T Fries for help getting this working on OpenBSD
660 // and to Chris Kuethe for the initial patch to use UHID.
661
662 #include <sys/ioctl.h>
663 #include <fcntl.h>
664 #include <dirent.h>
665 #include <dev/usb/usb.h>
666 #ifndef USB_GET_DEVICEINFO
667 #include <dev/usb/usb_ioctl.h>
668 #endif
669
670 int open_usb_device(int vid, int pid)
671 {
672 int r, fd;
673 DIR *dir;
674 struct dirent *d;
675 struct usb_device_info info;
676 char buf[256];
677
678 dir = opendir("/dev");
679 if (!dir) return -1;
680 while ((d = readdir(dir)) != NULL) {
681 if (strncmp(d->d_name, "uhid", 4) != 0) continue;
682 snprintf(buf, sizeof(buf), "/dev/%s", d->d_name);
683 fd = open(buf, O_RDWR);
684 if (fd < 0) continue;
685 r = ioctl(fd, USB_GET_DEVICEINFO, &info);
686 if (r < 0) {
687 // NetBSD: added in 2004
688 // OpenBSD: added November 23, 2009
689 // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works!
690 die("Error: your uhid driver does not support"
691 " USB_GET_DEVICEINFO, please upgrade!\n");
692 close(fd);
693 closedir(dir);
694 exit(1);
695 }
696 //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo);
697 if (info.udi_vendorNo == vid && info.udi_productNo == pid) {
698 closedir(dir);
699 return fd;
700 }
701 close(fd);
702 }
703 closedir(dir);
704 return -1;
705 }
706
707 static int uhid_teensy_fd = -1;
708
709 int teensy_open(void)
710 {
711 teensy_close();
712 uhid_teensy_fd = open_usb_device(0x16C0, 0x0478);
713
714 if (uhid_teensy_fd < 0)
715 uhid_teensy_fd = open_usb_device(0x03eb, 0x2067);
716
717 if (uhid_teensy_fd < 0) return 0;
718 return 1;
719 }
720
721 int teensy_write(void *buf, int len, double timeout)
722 {
723 int r;
724
725 // TODO: imeplement timeout... how??
726 r = write(uhid_teensy_fd, buf, len);
727 if (r == len) return 1;
728 return 0;
729 }
730
731 void teensy_close(void)
732 {
733 if (uhid_teensy_fd >= 0) {
734 close(uhid_teensy_fd);
735 uhid_teensy_fd = -1;
736 }
737 }
738
739 int hard_reboot(void)
740 {
741 int r, rebootor_fd;
742
743 rebootor_fd = open_usb_device(0x16C0, 0x0477);
744
745 if (rebootor_fd < 0)
746 rebootor_fd = open_usb_device(0x03eb, 0x2067);
747
748 if (rebootor_fd < 0) return 0;
749 r = write(rebootor_fd, "reboot", 6);
750 delay(0.1);
751 close(rebootor_fd);
752 if (r == 6) return 1;
753 return 0;
754 }
755
756 #endif
757
758
759
760 /****************************************************************/
761 /* */
762 /* Read Intel Hex File */
763 /* */
764 /****************************************************************/
765
766 // the maximum flash image size we can support
767 // chips with larger memory may be used, but only this
768 // much intel-hex data can be loaded into memory!
769 #define MAX_MEMORY_SIZE 0x10000
770
771 static unsigned char firmware_image[MAX_MEMORY_SIZE];
772 static unsigned char firmware_mask[MAX_MEMORY_SIZE];
773 static int end_record_seen=0;
774 static int byte_count;
775 static unsigned int extended_addr = 0;
776 static int parse_hex_line(char *line);
777
778 int read_intel_hex(const char *filename)
779 {
780 FILE *fp;
781 int i, lineno=0;
782 char buf[1024];
783
784 byte_count = 0;
785 end_record_seen = 0;
786 for (i=0; i<MAX_MEMORY_SIZE; i++) {
787 firmware_image[i] = 0xFF;
788 firmware_mask[i] = 0;
789 }
790 extended_addr = 0;
791
792 fp = fopen(filename, "r");
793 if (fp == NULL) {
794 //printf("Unable to read file %s\n", filename);
795 return -1;
796 }
797 while (!feof(fp)) {
798 *buf = '\0';
799 if (!fgets(buf, sizeof(buf), fp)) break;
800 lineno++;
801 if (*buf) {
802 if (parse_hex_line(buf) == 0) {
803 //printf("Warning, parse error line %d\n", lineno);
804 fclose(fp);
805 return -2;
806 }
807 }
808 if (end_record_seen) break;
809 if (feof(stdin)) break;
810 }
811 fclose(fp);
812 return byte_count;
813 }
814
815
816 /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */
817
818 /* parses a line of intel hex code, stores the data in bytes[] */
819 /* and the beginning address in addr, and returns a 1 if the */
820 /* line was valid, or a 0 if an error occured. The variable */
821 /* num gets the number of bytes that were stored into bytes[] */
822
823
824 int
825 parse_hex_line(char *line)
826 {
827 int addr, code, num;
828 int sum, len, cksum, i;
829 char *ptr;
830
831 num = 0;
832 if (line[0] != ':') return 0;
833 if (strlen(line) < 11) return 0;
834 ptr = line+1;
835 if (!sscanf(ptr, "%02x", &len)) return 0;
836 ptr += 2;
837 if ((int)strlen(line) < (11 + (len * 2)) ) return 0;
838 if (!sscanf(ptr, "%04x", &addr)) return 0;
839 ptr += 4;
840 /* printf("Line: length=%d Addr=%d\n", len, addr); */
841 if (!sscanf(ptr, "%02x", &code)) return 0;
842 if (addr + extended_addr + len >= MAX_MEMORY_SIZE) return 0;
843 ptr += 2;
844 sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255);
845 if (code != 0) {
846 if (code == 1) {
847 end_record_seen = 1;
848 return 1;
849 }
850 if (code == 2 && len == 2) {
851 if (!sscanf(ptr, "%04x", &i)) return 1;
852 ptr += 4;
853 sum += ((i >> 8) & 255) + (i & 255);
854 if (!sscanf(ptr, "%02x", &cksum)) return 1;
855 if (((sum & 255) + (cksum & 255)) & 255) return 1;
856 extended_addr = i << 4;
857 //printf("ext addr = %05X\n", extended_addr);
858 }
859 if (code == 4 && len == 2) {
860 if (!sscanf(ptr, "%04x", &i)) return 1;
861 ptr += 4;
862 sum += ((i >> 8) & 255) + (i & 255);
863 if (!sscanf(ptr, "%02x", &cksum)) return 1;
864 if (((sum & 255) + (cksum & 255)) & 255) return 1;
865 extended_addr = i << 16;
866 //printf("ext addr = %08X\n", extended_addr);
867 }
868 return 1; // non-data line
869 }
870 byte_count += len;
871 while (num != len) {
872 if (sscanf(ptr, "%02x", &i) != 1) return 0;
873 i &= 255;
874 firmware_image[addr + extended_addr + num] = i;
875 firmware_mask[addr + extended_addr + num] = 1;
876 ptr += 2;
877 sum += i;
878 (num)++;
879 if (num >= 256) return 0;
880 }
881 if (!sscanf(ptr, "%02x", &cksum)) return 0;
882 if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */
883 return 1;
884 }
885
886 int ihex_bytes_within_range(int begin, int end)
887 {
888 int i;
889
890 if (begin < 0 || begin >= MAX_MEMORY_SIZE ||
891 end < 0 || end >= MAX_MEMORY_SIZE) {
892 return 0;
893 }
894 for (i=begin; i<=end; i++) {
895 if (firmware_mask[i]) return 1;
896 }
897 return 0;
898 }
899
900 void ihex_get_data(int addr, int len, unsigned char *bytes)
901 {
902 int i;
903
904 if (addr < 0 || len < 0 || addr + len >= MAX_MEMORY_SIZE) {
905 for (i=0; i<len; i++) {
906 bytes[i] = 255;
907 }
908 return;
909 }
910 for (i=0; i<len; i++) {
911 if (firmware_mask[addr]) {
912 bytes[i] = firmware_image[addr];
913 } else {
914 bytes[i] = 255;
915 }
916 addr++;
917 }
918 }
919
920 /****************************************************************/
921 /* */
922 /* Misc Functions */
923 /* */
924 /****************************************************************/
925
926 int printf_verbose(const char *format, ...)
927 {
928 va_list ap;
929 int r;
930
931 va_start(ap, format);
932 if (verbose) {
933 r = vprintf(format, ap);
934 fflush(stdout);
935 return r;
936 }
937 return 0;
938 }
939
940 void delay(double seconds)
941 {
942 #ifdef WIN32
943 Sleep(seconds * 1000.0);
944 #else
945 usleep(seconds * 1000000.0);
946 #endif
947 }
948
949 void die(const char *str, ...)
950 {
951 va_list ap;
952
953 va_start(ap, str);
954 vfprintf(stderr, str, ap);
955 fprintf(stderr, "\n");
956 exit(1);
957 }
958
959 #if defined(WIN32)
960 #define strcasecmp stricmp
961 #endif
962
963 void parse_options(int argc, char **argv)
964 {
965 int i;
966 const char *arg;
967
968 for (i=1; i<argc; i++) {
969 arg = argv[i];
970
971 if (*arg == '-') {
972 if (strcmp(arg, "-w") == 0) {
973 wait_for_device_to_appear = 1;
974 } else if (strcmp(arg, "-r") == 0) {
975 hard_reboot_device = 1;
976 } else if (strcmp(arg, "-n") == 0) {
977 reboot_after_programming = 0;
978 } else if (strcmp(arg, "-v") == 0) {
979 verbose = 1;
980 } else if (strncmp(arg, "-mmcu=", 6) == 0) {
981 arg += 6;
982
983 uint8_t valid_prefix = 0;
984
985 if (strncmp(arg, "at90usb", 7) == 0) {
986 valid_prefix = 1;
987 arg += 7;
988 } else if (strncmp(arg, "atmega", 6) == 0) {
989 valid_prefix = 1;
990 arg += 6;
991 } else {
992 die("Unknown MCU type\n");
993 }
994
995 if (strncmp(arg, "128", 3) == 0) {
996 code_size = 128 * 1024;
997 block_size = 256;
998 } else if (strncmp(arg, "64", 2) == 0) {
999 code_size = 64 * 1024;
1000 block_size = 256;
1001 } else if (strncmp(arg, "32", 2) == 0) {
1002 code_size = 32 * 1024;
1003 block_size = 128;
1004 } else if (strncmp(arg, "16", 2) == 0) {
1005 code_size = 16 * 1024;
1006 block_size = 128;
1007 } else if (strncmp(arg, "8", 1) == 0) {
1008 code_size = 8 * 1024;
1009 block_size = 128;
1010 } else {
1011 die("Unknown MCU type\n");
1012 }
1013 }
1014 } else {
1015 filename = argv[i];
1016 }
1017 }
1018 }
1019