|  |  |  | /* Modified for the LUFA HID Bootloader by Dean Camera
 | 
					
						
							|  |  |  |  *           http://www.lufa-lib.org
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   THIS MODIFIED VERSION IS UNSUPPORTED BY PJRC. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Teensy Loader, Command Line Interface
 | 
					
						
							|  |  |  |  * Program and Reboot Teensy Board with HalfKay Bootloader | 
					
						
							|  |  |  |  * http://www.pjrc.com/teensy/loader_cli.html
 | 
					
						
							|  |  |  |  * Copyright 2008-2010, PJRC.COM, LLC | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You may redistribute this program and/or modify it under the terms | 
					
						
							|  |  |  |  * of the GNU General Public License as published by the Free Software | 
					
						
							|  |  |  |  * Foundation, version 3 of the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see http://www.gnu.org/licenses/
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Want to incorporate this code into a proprietary application??
 | 
					
						
							|  |  |  |  * Just email paul@pjrc.com to ask.  Usually it's not a problem, | 
					
						
							|  |  |  |  * but you do need to ask to use this code in any way other than | 
					
						
							|  |  |  |  * those permitted by the GNU General Public License, version 3  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* For non-root permissions on ubuntu or similar udev-based linux
 | 
					
						
							|  |  |  |  * http://www.pjrc.com/teensy/49-teensy.rules
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <stdint.h>
 | 
					
						
							|  |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void usage(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	fprintf(stderr, "Usage: hid_bootloader_cli -mmcu=<MCU> [-w] [-h] [-n] [-v] <file.hex>\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "\t-w : Wait for device to appear\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "\t-r : Use hard reboot if device not online\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "\t-n : No reboot after programming\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "\t-v : Verbose output\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "\n<MCU> = atmegaXXuY or at90usbXXXY"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fprintf(stderr, "\nFor support and more information, please visit:\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "http://www.lufa-lib.org\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fprintf(stderr, "\nBased on the TeensyHID command line programmer software:\n"); | 
					
						
							|  |  |  | 	fprintf(stderr, "http://www.pjrc.com/teensy/loader_cli.html\n"); | 
					
						
							|  |  |  | 	exit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // USB Access Functions
 | 
					
						
							|  |  |  | int teensy_open(void); | 
					
						
							|  |  |  | int teensy_write(void *buf, int len, double timeout); | 
					
						
							|  |  |  | void teensy_close(void); | 
					
						
							|  |  |  | int hard_reboot(void); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Intel Hex File Functions
 | 
					
						
							|  |  |  | int read_intel_hex(const char *filename); | 
					
						
							|  |  |  | int ihex_bytes_within_range(int begin, int end); | 
					
						
							|  |  |  | void ihex_get_data(int addr, int len, unsigned char *bytes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Misc stuff
 | 
					
						
							|  |  |  | int printf_verbose(const char *format, ...); | 
					
						
							|  |  |  | void delay(double seconds); | 
					
						
							|  |  |  | void die(const char *str, ...); | 
					
						
							|  |  |  | void parse_options(int argc, char **argv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // options (from user via command line args)
 | 
					
						
							|  |  |  | int wait_for_device_to_appear = 0; | 
					
						
							|  |  |  | int hard_reboot_device = 0; | 
					
						
							|  |  |  | int reboot_after_programming = 1; | 
					
						
							|  |  |  | int verbose = 0; | 
					
						
							|  |  |  | int code_size = 0, block_size = 0; | 
					
						
							|  |  |  | const char *filename=NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*                       Main Program                           */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char **argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned char buf[260]; | 
					
						
							|  |  |  | 	int num, addr, r, first_block=1, waited=0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// parse command line arguments
 | 
					
						
							|  |  |  | 	parse_options(argc, argv); | 
					
						
							|  |  |  | 	if (!filename) { | 
					
						
							|  |  |  | 		fprintf(stderr, "Filename must be specified\n\n"); | 
					
						
							|  |  |  | 		usage(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!code_size) { | 
					
						
							|  |  |  | 		fprintf(stderr, "MCU type must be specified\n\n"); | 
					
						
							|  |  |  | 		usage(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printf_verbose("Teensy Loader, Command Line, Version 2.0\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// read the intel hex file
 | 
					
						
							|  |  |  | 	// this is done first so any error is reported before using USB
 | 
					
						
							|  |  |  | 	num = read_intel_hex(filename); | 
					
						
							|  |  |  | 	if (num < 0) die("error reading intel hex file \"%s\"", filename); | 
					
						
							|  |  |  | 	printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n", | 
					
						
							|  |  |  | 		filename, num, (double)num / (double)code_size * 100.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// open the USB device
 | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							|  |  |  | 		if (teensy_open()) break; | 
					
						
							|  |  |  | 		if (hard_reboot_device) { | 
					
						
							|  |  |  | 			if (!hard_reboot()) die("Unable to find rebootor\n"); | 
					
						
							|  |  |  | 			printf_verbose("Hard Reboot performed\n"); | 
					
						
							|  |  |  | 			hard_reboot_device = 0; // only hard reboot once
 | 
					
						
							|  |  |  | 			wait_for_device_to_appear = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!wait_for_device_to_appear) die("Unable to open device\n"); | 
					
						
							|  |  |  | 		if (!waited) { | 
					
						
							|  |  |  | 			printf_verbose("Waiting for Teensy device...\n"); | 
					
						
							|  |  |  | 			printf_verbose(" (hint: press the reset button)\n"); | 
					
						
							|  |  |  | 			waited = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		delay(0.25); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printf_verbose("Found HalfKay Bootloader\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if we waited for the device, read the hex file again
 | 
					
						
							|  |  |  | 	// perhaps it changed while we were waiting?
 | 
					
						
							|  |  |  | 	if (waited) { | 
					
						
							|  |  |  | 		num = read_intel_hex(filename); | 
					
						
							|  |  |  | 		if (num < 0) die("error reading intel hex file \"%s\"", filename); | 
					
						
							|  |  |  | 		printf_verbose("Read \"%s\": %d bytes, %.1f%% usage\n", | 
					
						
							|  |  |  | 		 	filename, num, (double)num / (double)code_size * 100.0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// program the data
 | 
					
						
							|  |  |  | 	printf_verbose("Programming"); | 
					
						
							|  |  |  | 	fflush(stdout); | 
					
						
							|  |  |  | 	for (addr = 0; addr < code_size; addr += block_size) { | 
					
						
							|  |  |  | 		if (addr > 0 && !ihex_bytes_within_range(addr, addr + block_size - 1)) { | 
					
						
							|  |  |  | 			// don't waste time on blocks that are unused,
 | 
					
						
							|  |  |  | 			// but always do the first one to erase the chip
 | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printf_verbose("."); | 
					
						
							|  |  |  | 		if (code_size < 0x10000) { | 
					
						
							|  |  |  | 			buf[0] = addr & 255; | 
					
						
							|  |  |  | 			buf[1] = (addr >> 8) & 255; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			buf[0] = (addr >> 8) & 255; | 
					
						
							|  |  |  | 			buf[1] = (addr >> 16) & 255; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ihex_get_data(addr, block_size, buf + 2); | 
					
						
							|  |  |  | 		r = teensy_write(buf, block_size + 2, first_block ? 3.0 : 0.25); | 
					
						
							|  |  |  | 		if (!r) die("error writing to Teensy\n"); | 
					
						
							|  |  |  | 		first_block = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printf_verbose("\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// reboot to the user's new code
 | 
					
						
							|  |  |  | 	if (reboot_after_programming) { | 
					
						
							|  |  |  | 		printf_verbose("Booting\n"); | 
					
						
							|  |  |  | 		buf[0] = 0xFF; | 
					
						
							|  |  |  | 		buf[1] = 0xFF; | 
					
						
							|  |  |  | 		memset(buf + 2, 0, sizeof(buf) - 2); | 
					
						
							|  |  |  | 		teensy_write(buf, block_size + 2, 0.25); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	teensy_close(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*             USB Access - libusb (Linux & FreeBSD)            */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(USE_LIBUSB)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // http://libusb.sourceforge.net/doc/index.html
 | 
					
						
							|  |  |  | #include <usb.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | usb_dev_handle * open_usb_device(int vid, int pid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct usb_bus *bus; | 
					
						
							|  |  |  | 	struct usb_device *dev; | 
					
						
							|  |  |  | 	usb_dev_handle *h; | 
					
						
							|  |  |  | 	char buf[128]; | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usb_init(); | 
					
						
							|  |  |  | 	usb_find_busses(); | 
					
						
							|  |  |  | 	usb_find_devices(); | 
					
						
							|  |  |  | 	//printf_verbose("\nSearching for USB device:\n");
 | 
					
						
							|  |  |  | 	for (bus = usb_get_busses(); bus; bus = bus->next) { | 
					
						
							|  |  |  | 		for (dev = bus->devices; dev; dev = dev->next) { | 
					
						
							|  |  |  | 			//printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n",
 | 
					
						
							|  |  |  | 			//	bus->dirname, dev->filename,
 | 
					
						
							|  |  |  | 			//	dev->descriptor.idVendor,
 | 
					
						
							|  |  |  | 			//	dev->descriptor.idProduct
 | 
					
						
							|  |  |  | 			//);
 | 
					
						
							|  |  |  | 			if (dev->descriptor.idVendor != vid) continue; | 
					
						
							|  |  |  | 			if (dev->descriptor.idProduct != pid) continue; | 
					
						
							|  |  |  | 			h = usb_open(dev); | 
					
						
							|  |  |  | 			if (!h) { | 
					
						
							|  |  |  | 				printf_verbose("Found device but unable to open"); | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			#ifdef LIBUSB_HAS_GET_DRIVER_NP
 | 
					
						
							|  |  |  | 			r = usb_get_driver_np(h, 0, buf, sizeof(buf)); | 
					
						
							|  |  |  | 			if (r >= 0) { | 
					
						
							|  |  |  | 				r = usb_detach_kernel_driver_np(h, 0); | 
					
						
							|  |  |  | 				if (r < 0) { | 
					
						
							|  |  |  | 					usb_close(h); | 
					
						
							|  |  |  | 					printf_verbose("Device is in use by \"%s\" driver", buf); | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			#endif
 | 
					
						
							|  |  |  | 			// Mac OS-X - removing this call to usb_claim_interface() might allow
 | 
					
						
							|  |  |  | 			// this to work, even though it is a clear misuse of the libusb API.
 | 
					
						
							|  |  |  | 			// normally Apple's IOKit should be used on Mac OS-X
 | 
					
						
							|  |  |  | 			r = usb_claim_interface(h, 0); | 
					
						
							|  |  |  | 			if (r < 0) { | 
					
						
							|  |  |  | 				usb_close(h); | 
					
						
							|  |  |  | 				printf_verbose("Unable to claim interface, check USB permissions"); | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return h; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static usb_dev_handle *libusb_teensy_handle = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_open(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	teensy_close(); | 
					
						
							|  |  |  | 	libusb_teensy_handle = open_usb_device(0x16C0, 0x0478); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!libusb_teensy_handle) | 
					
						
							|  |  |  | 		libusb_teensy_handle = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!libusb_teensy_handle) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_write(void *buf, int len, double timeout) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!libusb_teensy_handle) return 0; | 
					
						
							|  |  |  | 	r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0, (char *)buf, | 
					
						
							|  |  |  | 		len, (int)(timeout * 1000.0)); | 
					
						
							|  |  |  | 	if (r < 0) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void teensy_close(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!libusb_teensy_handle) return; | 
					
						
							|  |  |  | 	usb_release_interface(libusb_teensy_handle, 0); | 
					
						
							|  |  |  | 	usb_close(libusb_teensy_handle); | 
					
						
							|  |  |  | 	libusb_teensy_handle = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int hard_reboot(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	usb_dev_handle *rebootor; | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rebootor = open_usb_device(0x16C0, 0x0477); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rebootor) | 
					
						
							|  |  |  | 		rebootor = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rebootor) return 0; | 
					
						
							|  |  |  | 	r = usb_control_msg(rebootor, 0x21, 9, 0x0200, 0, "reboot", 6, 100); | 
					
						
							|  |  |  | 	usb_release_interface(rebootor, 0); | 
					
						
							|  |  |  | 	usb_close(rebootor); | 
					
						
							|  |  |  | 	if (r < 0) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*               USB Access - Microsoft WIN32                   */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(USE_WIN32)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // http://msdn.microsoft.com/en-us/library/ms790932.aspx
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #include <setupapi.h>
 | 
					
						
							|  |  |  | #include <ddk/hidsdi.h>
 | 
					
						
							|  |  |  | #include <ddk/hidclass.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HANDLE open_usb_device(int vid, int pid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	GUID guid; | 
					
						
							|  |  |  | 	HDEVINFO info; | 
					
						
							|  |  |  | 	DWORD index, required_size; | 
					
						
							|  |  |  | 	SP_DEVICE_INTERFACE_DATA iface; | 
					
						
							|  |  |  | 	SP_DEVICE_INTERFACE_DETAIL_DATA *details; | 
					
						
							|  |  |  | 	HIDD_ATTRIBUTES attrib; | 
					
						
							|  |  |  | 	HANDLE h; | 
					
						
							|  |  |  | 	BOOL ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	HidD_GetHidGuid(&guid); | 
					
						
							|  |  |  | 	info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | 
					
						
							|  |  |  | 	if (info == INVALID_HANDLE_VALUE) return NULL; | 
					
						
							|  |  |  | 	for (index=0; 1 ;index++) { | 
					
						
							|  |  |  | 		iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | 
					
						
							|  |  |  | 		ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface); | 
					
						
							|  |  |  | 		if (!ret) { | 
					
						
							|  |  |  | 			SetupDiDestroyDeviceInfoList(info); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL); | 
					
						
							|  |  |  | 		details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size); | 
					
						
							|  |  |  | 		if (details == NULL) continue; | 
					
						
							|  |  |  | 		memset(details, 0, required_size); | 
					
						
							|  |  |  | 		details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); | 
					
						
							|  |  |  | 		ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details, | 
					
						
							|  |  |  | 			required_size, NULL, NULL); | 
					
						
							|  |  |  | 		if (!ret) { | 
					
						
							|  |  |  | 			free(details); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE, | 
					
						
							|  |  |  | 			FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, | 
					
						
							|  |  |  | 			FILE_FLAG_OVERLAPPED, NULL); | 
					
						
							|  |  |  | 		free(details); | 
					
						
							|  |  |  | 		if (h == INVALID_HANDLE_VALUE) continue; | 
					
						
							|  |  |  | 		attrib.Size = sizeof(HIDD_ATTRIBUTES); | 
					
						
							|  |  |  | 		ret = HidD_GetAttributes(h, &attrib); | 
					
						
							|  |  |  | 		if (!ret) { | 
					
						
							|  |  |  | 			CloseHandle(h); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (attrib.VendorID != vid || attrib.ProductID != pid) { | 
					
						
							|  |  |  | 			CloseHandle(h); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		SetupDiDestroyDeviceInfoList(info); | 
					
						
							|  |  |  | 		return h; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int write_usb_device(HANDLE h, void *buf, int len, int timeout) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static HANDLE event = NULL; | 
					
						
							|  |  |  | 	unsigned char tmpbuf[1040]; | 
					
						
							|  |  |  | 	OVERLAPPED ov; | 
					
						
							|  |  |  | 	DWORD n, r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len > sizeof(tmpbuf) - 1) return 0; | 
					
						
							|  |  |  | 	if (event == NULL) { | 
					
						
							|  |  |  | 		event = CreateEvent(NULL, TRUE, TRUE, NULL); | 
					
						
							|  |  |  | 		if (!event) return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ResetEvent(&event); | 
					
						
							|  |  |  | 	memset(&ov, 0, sizeof(ov)); | 
					
						
							|  |  |  | 	ov.hEvent = event; | 
					
						
							|  |  |  | 	tmpbuf[0] = 0; | 
					
						
							|  |  |  | 	memcpy(tmpbuf + 1, buf, len); | 
					
						
							|  |  |  | 	if (!WriteFile(h, tmpbuf, len + 1, NULL, &ov)) { | 
					
						
							|  |  |  | 		if (GetLastError() != ERROR_IO_PENDING) return 0; | 
					
						
							|  |  |  | 		r = WaitForSingleObject(event, timeout); | 
					
						
							|  |  |  | 		if (r == WAIT_TIMEOUT) { | 
					
						
							|  |  |  | 			CancelIo(h); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (r != WAIT_OBJECT_0) return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!GetOverlappedResult(h, &ov, &n, FALSE)) return 0; | 
					
						
							|  |  |  | 	if (n <= 0) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void print_win32_err(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |         char buf[256]; | 
					
						
							|  |  |  |         DWORD err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         err = GetLastError(); | 
					
						
							|  |  |  |         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, | 
					
						
							|  |  |  |                 0, buf, sizeof(buf), NULL); | 
					
						
							|  |  |  |         printf("err %ld: %s\n", err, buf); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static HANDLE win32_teensy_handle = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_open(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	teensy_close(); | 
					
						
							|  |  |  | 	win32_teensy_handle = open_usb_device(0x16C0, 0x0478); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!win32_teensy_handle) | 
					
						
							|  |  |  | 		win32_teensy_handle = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!win32_teensy_handle) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_write(void *buf, int len, double timeout) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 	if (!win32_teensy_handle) return 0; | 
					
						
							|  |  |  | 	r = write_usb_device(win32_teensy_handle, buf, len, (int)(timeout * 1000.0)); | 
					
						
							|  |  |  | 	return r; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void teensy_close(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!win32_teensy_handle) return; | 
					
						
							|  |  |  | 	CloseHandle(win32_teensy_handle); | 
					
						
							|  |  |  | 	win32_teensy_handle = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int hard_reboot(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	HANDLE rebootor; | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rebootor = open_usb_device(0x16C0, 0x0477); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rebootor) | 
					
						
							|  |  |  | 		rebootor = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rebootor) return 0; | 
					
						
							|  |  |  | 	r = write_usb_device(rebootor, "reboot", 6, 100); | 
					
						
							|  |  |  | 	CloseHandle(rebootor); | 
					
						
							|  |  |  | 	return r; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*             USB Access - Apple's IOKit, Mac OS-X             */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(USE_APPLE_IOKIT)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // http://developer.apple.com/technotes/tn2007/tn2187.html
 | 
					
						
							|  |  |  | #include <IOKit/IOKitLib.h>
 | 
					
						
							|  |  |  | #include <IOKit/hid/IOHIDLib.h>
 | 
					
						
							|  |  |  | #include <IOKit/hid/IOHIDDevice.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct usb_list_struct { | 
					
						
							|  |  |  | 	IOHIDDeviceRef ref; | 
					
						
							|  |  |  | 	int pid; | 
					
						
							|  |  |  | 	int vid; | 
					
						
							|  |  |  | 	struct usb_list_struct *next; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct usb_list_struct *usb_list=NULL; | 
					
						
							|  |  |  | static IOHIDManagerRef hid_manager=NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CFTypeRef type; | 
					
						
							|  |  |  | 	struct usb_list_struct *n, *p; | 
					
						
							|  |  |  | 	int32_t pid, vid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!dev) return; | 
					
						
							|  |  |  | 	type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey)); | 
					
						
							|  |  |  | 	if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return; | 
					
						
							|  |  |  | 	if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &vid)) return; | 
					
						
							|  |  |  | 	type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey)); | 
					
						
							|  |  |  | 	if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return; | 
					
						
							|  |  |  | 	if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &pid)) return; | 
					
						
							|  |  |  | 	n = (struct usb_list_struct *)malloc(sizeof(struct usb_list_struct)); | 
					
						
							|  |  |  | 	if (!n) return; | 
					
						
							|  |  |  | 	//printf("attach callback: vid=%04X, pid=%04X\n", vid, pid);
 | 
					
						
							|  |  |  | 	n->ref = dev; | 
					
						
							|  |  |  | 	n->vid = vid; | 
					
						
							|  |  |  | 	n->pid = pid; | 
					
						
							|  |  |  | 	n->next = NULL; | 
					
						
							|  |  |  | 	if (usb_list == NULL) { | 
					
						
							|  |  |  | 		usb_list = n; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		for (p = usb_list; p->next; p = p->next) ; | 
					
						
							|  |  |  | 		p->next = n; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct usb_list_struct *p, *tmp, *prev=NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p = usb_list; | 
					
						
							|  |  |  | 	while (p) { | 
					
						
							|  |  |  | 		if (p->ref == dev) { | 
					
						
							|  |  |  | 			if (prev) { | 
					
						
							|  |  |  | 				prev->next = p->next; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				usb_list = p->next; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			tmp = p; | 
					
						
							|  |  |  | 			p = p->next; | 
					
						
							|  |  |  | 			free(tmp); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			prev = p; | 
					
						
							|  |  |  | 			p = p->next; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void init_hid_manager(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	CFMutableDictionaryRef dict; | 
					
						
							|  |  |  | 	IOReturn ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (hid_manager) return; | 
					
						
							|  |  |  | 	hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); | 
					
						
							|  |  |  | 	if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) { | 
					
						
							|  |  |  | 		if (hid_manager) CFRelease(hid_manager); | 
					
						
							|  |  |  | 		printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, | 
					
						
							|  |  |  | 		&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | 
					
						
							|  |  |  | 	if (!dict) return; | 
					
						
							|  |  |  | 	IOHIDManagerSetDeviceMatching(hid_manager, dict); | 
					
						
							|  |  |  | 	CFRelease(dict); | 
					
						
							|  |  |  | 	IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | 
					
						
							|  |  |  | 	IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL); | 
					
						
							|  |  |  | 	IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL); | 
					
						
							|  |  |  | 	ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); | 
					
						
							|  |  |  | 	if (ret != kIOReturnSuccess) { | 
					
						
							|  |  |  | 		IOHIDManagerUnscheduleFromRunLoop(hid_manager, | 
					
						
							|  |  |  | 			CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | 
					
						
							|  |  |  | 		CFRelease(hid_manager); | 
					
						
							|  |  |  | 		printf_verbose("Error opening HID Manager"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void do_run_loop(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IOHIDDeviceRef open_usb_device(int vid, int pid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct usb_list_struct *p; | 
					
						
							|  |  |  | 	IOReturn ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_hid_manager(); | 
					
						
							|  |  |  | 	do_run_loop(); | 
					
						
							|  |  |  | 	for (p = usb_list; p; p = p->next) { | 
					
						
							|  |  |  | 		if (p->vid == vid && p->pid == pid) { | 
					
						
							|  |  |  | 			ret = IOHIDDeviceOpen(p->ref, kIOHIDOptionsTypeNone); | 
					
						
							|  |  |  | 			if (ret == kIOReturnSuccess) return p->ref; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void close_usb_device(IOHIDDeviceRef dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct usb_list_struct *p; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do_run_loop(); | 
					
						
							|  |  |  | 	for (p = usb_list; p; p = p->next) { | 
					
						
							|  |  |  | 		if (p->ref == dev) { | 
					
						
							|  |  |  | 			IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static IOHIDDeviceRef iokit_teensy_reference = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_open(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	teensy_close(); | 
					
						
							|  |  |  | 	iokit_teensy_reference = open_usb_device(0x16C0, 0x0478); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!iokit_teensy_reference) | 
					
						
							|  |  |  | 		iokit_teensy_reference = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!iokit_teensy_reference) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_write(void *buf, int len, double timeout) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IOReturn ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// timeouts do not work on OS-X
 | 
					
						
							|  |  |  | 	// IOHIDDeviceSetReportWithCallback is not implemented
 | 
					
						
							|  |  |  | 	// even though Apple documents it with a code example!
 | 
					
						
							|  |  |  | 	// submitted to Apple on 22-sep-2009, problem ID 7245050
 | 
					
						
							|  |  |  | 	if (!iokit_teensy_reference) return 0; | 
					
						
							|  |  |  | 	ret = IOHIDDeviceSetReport(iokit_teensy_reference, | 
					
						
							|  |  |  | 		kIOHIDReportTypeOutput, 0, buf, len); | 
					
						
							|  |  |  | 	if (ret == kIOReturnSuccess) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void teensy_close(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!iokit_teensy_reference) return; | 
					
						
							|  |  |  | 	close_usb_device(iokit_teensy_reference); | 
					
						
							|  |  |  | 	iokit_teensy_reference = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int hard_reboot(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IOHIDDeviceRef rebootor; | 
					
						
							|  |  |  | 	IOReturn ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rebootor = open_usb_device(0x16C0, 0x0477); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rebootor) | 
					
						
							|  |  |  | 		rebootor = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rebootor) return 0; | 
					
						
							|  |  |  | 	ret = IOHIDDeviceSetReport(rebootor, | 
					
						
							|  |  |  | 		kIOHIDReportTypeOutput, 0, (uint8_t *)("reboot"), 6); | 
					
						
							|  |  |  | 	close_usb_device(rebootor); | 
					
						
							|  |  |  | 	if (ret == kIOReturnSuccess) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*              USB Access - BSD's UHID driver                  */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(USE_UHID)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Thanks to Todd T Fries for help getting this working on OpenBSD
 | 
					
						
							|  |  |  | // and to Chris Kuethe for the initial patch to use UHID.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <dirent.h>
 | 
					
						
							|  |  |  | #include <dev/usb/usb.h>
 | 
					
						
							|  |  |  | #ifndef USB_GET_DEVICEINFO
 | 
					
						
							|  |  |  | #include <dev/usb/usb_ioctl.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int open_usb_device(int vid, int pid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int r, fd; | 
					
						
							|  |  |  | 	DIR *dir; | 
					
						
							|  |  |  | 	struct dirent *d; | 
					
						
							|  |  |  | 	struct usb_device_info info; | 
					
						
							|  |  |  | 	char buf[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dir = opendir("/dev"); | 
					
						
							|  |  |  | 	if (!dir) return -1; | 
					
						
							|  |  |  | 	while ((d = readdir(dir)) != NULL) { | 
					
						
							|  |  |  | 		if (strncmp(d->d_name, "uhid", 4) != 0) continue; | 
					
						
							|  |  |  | 		snprintf(buf, sizeof(buf), "/dev/%s", d->d_name); | 
					
						
							|  |  |  | 		fd = open(buf, O_RDWR); | 
					
						
							|  |  |  | 		if (fd < 0) continue; | 
					
						
							|  |  |  | 		r = ioctl(fd, USB_GET_DEVICEINFO, &info); | 
					
						
							|  |  |  | 		if (r < 0) { | 
					
						
							|  |  |  | 			// NetBSD: added in 2004
 | 
					
						
							|  |  |  | 			// OpenBSD: added November 23, 2009
 | 
					
						
							|  |  |  | 			// FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works!
 | 
					
						
							|  |  |  | 			die("Error: your uhid driver does not support" | 
					
						
							|  |  |  | 			  " USB_GET_DEVICEINFO, please upgrade!\n"); | 
					
						
							|  |  |  | 			close(fd); | 
					
						
							|  |  |  | 			closedir(dir); | 
					
						
							|  |  |  | 			exit(1); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		//printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo);
 | 
					
						
							|  |  |  | 		if (info.udi_vendorNo == vid && info.udi_productNo == pid) { | 
					
						
							|  |  |  | 			closedir(dir); | 
					
						
							|  |  |  | 			return fd; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		close(fd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	closedir(dir); | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int uhid_teensy_fd = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_open(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	teensy_close(); | 
					
						
							|  |  |  | 	uhid_teensy_fd = open_usb_device(0x16C0, 0x0478); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (uhid_teensy_fd < 0) | 
					
						
							|  |  |  | 		uhid_teensy_fd = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (uhid_teensy_fd < 0) return 0; | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int teensy_write(void *buf, int len, double timeout) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: imeplement timeout... how??
 | 
					
						
							|  |  |  | 	r = write(uhid_teensy_fd, buf, len); | 
					
						
							|  |  |  | 	if (r == len) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void teensy_close(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (uhid_teensy_fd >= 0) { | 
					
						
							|  |  |  | 		close(uhid_teensy_fd); | 
					
						
							|  |  |  | 		uhid_teensy_fd = -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int hard_reboot(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int r, rebootor_fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rebootor_fd = open_usb_device(0x16C0, 0x0477); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (rebootor_fd < 0) | 
					
						
							|  |  |  | 		rebootor_fd = open_usb_device(0x03eb, 0x2067); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (rebootor_fd < 0) return 0; | 
					
						
							|  |  |  | 	r = write(rebootor_fd, "reboot", 6); | 
					
						
							|  |  |  | 	delay(0.1); | 
					
						
							|  |  |  | 	close(rebootor_fd); | 
					
						
							|  |  |  | 	if (r == 6) return 1; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*                     Read Intel Hex File                      */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // the maximum flash image size we can support
 | 
					
						
							|  |  |  | // chips with larger memory may be used, but only this
 | 
					
						
							|  |  |  | // much intel-hex data can be loaded into memory!
 | 
					
						
							|  |  |  | #define MAX_MEMORY_SIZE 0x10000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned char firmware_image[MAX_MEMORY_SIZE]; | 
					
						
							|  |  |  | static unsigned char firmware_mask[MAX_MEMORY_SIZE]; | 
					
						
							|  |  |  | static int end_record_seen=0; | 
					
						
							|  |  |  | static int byte_count; | 
					
						
							|  |  |  | static unsigned int extended_addr = 0; | 
					
						
							|  |  |  | static int parse_hex_line(char *line); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int read_intel_hex(const char *filename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	FILE *fp; | 
					
						
							|  |  |  | 	int i, lineno=0; | 
					
						
							|  |  |  | 	char buf[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	byte_count = 0; | 
					
						
							|  |  |  | 	end_record_seen = 0; | 
					
						
							|  |  |  | 	for (i=0; i<MAX_MEMORY_SIZE; i++) { | 
					
						
							|  |  |  | 		firmware_image[i] = 0xFF; | 
					
						
							|  |  |  | 		firmware_mask[i] = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	extended_addr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fp = fopen(filename, "r"); | 
					
						
							|  |  |  | 	if (fp == NULL) { | 
					
						
							|  |  |  | 		//printf("Unable to read file %s\n", filename);
 | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	while (!feof(fp)) { | 
					
						
							|  |  |  | 		*buf = '\0'; | 
					
						
							|  |  |  | 		if (!fgets(buf, sizeof(buf), fp)) break; | 
					
						
							|  |  |  | 		lineno++; | 
					
						
							|  |  |  | 		if (*buf) { | 
					
						
							|  |  |  | 			if (parse_hex_line(buf) == 0) { | 
					
						
							|  |  |  | 				//printf("Warning, parse error line %d\n", lineno);
 | 
					
						
							|  |  |  | 				return -2; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (end_record_seen) break; | 
					
						
							|  |  |  | 		if (feof(stdin)) break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fclose(fp); | 
					
						
							|  |  |  | 	return byte_count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* parses a line of intel hex code, stores the data in bytes[] */ | 
					
						
							|  |  |  | /* and the beginning address in addr, and returns a 1 if the */ | 
					
						
							|  |  |  | /* line was valid, or a 0 if an error occured.  The variable */ | 
					
						
							|  |  |  | /* num gets the number of bytes that were stored into bytes[] */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | parse_hex_line(char *line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int addr, code, num; | 
					
						
							|  |  |  |         int sum, len, cksum, i; | 
					
						
							|  |  |  |         char *ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         num = 0; | 
					
						
							|  |  |  |         if (line[0] != ':') return 0; | 
					
						
							|  |  |  |         if (strlen(line) < 11) return 0; | 
					
						
							|  |  |  |         ptr = line+1; | 
					
						
							|  |  |  |         if (!sscanf(ptr, "%02x", &len)) return 0; | 
					
						
							|  |  |  |         ptr += 2; | 
					
						
							|  |  |  |         if ((int)strlen(line) < (11 + (len * 2)) ) return 0; | 
					
						
							|  |  |  |         if (!sscanf(ptr, "%04x", &addr)) return 0; | 
					
						
							|  |  |  |         ptr += 4; | 
					
						
							|  |  |  |           /* printf("Line: length=%d Addr=%d\n", len, addr); */ | 
					
						
							|  |  |  |         if (!sscanf(ptr, "%02x", &code)) return 0; | 
					
						
							|  |  |  | 	if (addr + extended_addr + len >= MAX_MEMORY_SIZE) return 0; | 
					
						
							|  |  |  |         ptr += 2; | 
					
						
							|  |  |  |         sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255); | 
					
						
							|  |  |  | 	if (code != 0) { | 
					
						
							|  |  |  | 		if (code == 1) { | 
					
						
							|  |  |  | 			end_record_seen = 1; | 
					
						
							|  |  |  | 			return 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (code == 2 && len == 2) { | 
					
						
							|  |  |  | 			if (!sscanf(ptr, "%04x", &i)) return 1; | 
					
						
							|  |  |  | 			ptr += 4; | 
					
						
							|  |  |  | 			sum += ((i >> 8) & 255) + (i & 255); | 
					
						
							|  |  |  |         		if (!sscanf(ptr, "%02x", &cksum)) return 1; | 
					
						
							|  |  |  | 			if (((sum & 255) + (cksum & 255)) & 255) return 1; | 
					
						
							|  |  |  | 			extended_addr = i << 4; | 
					
						
							|  |  |  | 			//printf("ext addr = %05X\n", extended_addr);
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (code == 4 && len == 2) { | 
					
						
							|  |  |  | 			if (!sscanf(ptr, "%04x", &i)) return 1; | 
					
						
							|  |  |  | 			ptr += 4; | 
					
						
							|  |  |  | 			sum += ((i >> 8) & 255) + (i & 255); | 
					
						
							|  |  |  |         		if (!sscanf(ptr, "%02x", &cksum)) return 1; | 
					
						
							|  |  |  | 			if (((sum & 255) + (cksum & 255)) & 255) return 1; | 
					
						
							|  |  |  | 			extended_addr = i << 16; | 
					
						
							|  |  |  | 			//printf("ext addr = %08X\n", extended_addr);
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 1;	// non-data line
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	byte_count += len; | 
					
						
							|  |  |  |         while (num != len) { | 
					
						
							|  |  |  |                 if (sscanf(ptr, "%02x", &i) != 1) return 0; | 
					
						
							|  |  |  | 		i &= 255; | 
					
						
							|  |  |  | 		firmware_image[addr + extended_addr + num] = i; | 
					
						
							|  |  |  | 		firmware_mask[addr + extended_addr + num] = 1; | 
					
						
							|  |  |  |                 ptr += 2; | 
					
						
							|  |  |  |                 sum += i; | 
					
						
							|  |  |  |                 (num)++; | 
					
						
							|  |  |  |                 if (num >= 256) return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!sscanf(ptr, "%02x", &cksum)) return 0; | 
					
						
							|  |  |  |         if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */ | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ihex_bytes_within_range(int begin, int end) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (begin < 0 || begin >= MAX_MEMORY_SIZE || | 
					
						
							|  |  |  | 	   end < 0 || end >= MAX_MEMORY_SIZE) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (i=begin; i<=end; i++) { | 
					
						
							|  |  |  | 		if (firmware_mask[i]) return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ihex_get_data(int addr, int len, unsigned char *bytes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (addr < 0 || len < 0 || addr + len >= MAX_MEMORY_SIZE) { | 
					
						
							|  |  |  | 		for (i=0; i<len; i++) { | 
					
						
							|  |  |  | 			bytes[i] = 255; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for (i=0; i<len; i++) { | 
					
						
							|  |  |  | 		if (firmware_mask[addr]) { | 
					
						
							|  |  |  | 			bytes[i] = firmware_image[addr]; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			bytes[i] = 255; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		addr++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /*                       Misc Functions                         */ | 
					
						
							|  |  |  | /*                                                              */ | 
					
						
							|  |  |  | /****************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int printf_verbose(const char *format, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	va_list ap; | 
					
						
							|  |  |  | 	int r; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_start(ap, format); | 
					
						
							|  |  |  | 	if (verbose) { | 
					
						
							|  |  |  | 		r = vprintf(format, ap); | 
					
						
							|  |  |  | 		fflush(stdout); | 
					
						
							|  |  |  | 		return r; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void delay(double seconds) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	#ifdef WIN32
 | 
					
						
							|  |  |  | 	Sleep(seconds * 1000.0); | 
					
						
							|  |  |  | 	#else
 | 
					
						
							|  |  |  | 	usleep(seconds * 1000000.0); | 
					
						
							|  |  |  | 	#endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void die(const char *str, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	va_list  ap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	va_start(ap, str); | 
					
						
							|  |  |  | 	vfprintf(stderr, str, ap); | 
					
						
							|  |  |  | 	fprintf(stderr, "\n"); | 
					
						
							|  |  |  | 	exit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(WIN32)
 | 
					
						
							|  |  |  | #define strcasecmp stricmp
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void parse_options(int argc, char **argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	const char *arg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i=1; i<argc; i++) { | 
					
						
							|  |  |  | 		arg = argv[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (*arg == '-') { | 
					
						
							|  |  |  | 			if (strcmp(arg, "-w") == 0) { | 
					
						
							|  |  |  | 				wait_for_device_to_appear = 1; | 
					
						
							|  |  |  | 			} else if (strcmp(arg, "-r") == 0) { | 
					
						
							|  |  |  | 				hard_reboot_device = 1; | 
					
						
							|  |  |  | 			} else if (strcmp(arg, "-n") == 0) { | 
					
						
							|  |  |  | 				reboot_after_programming = 0; | 
					
						
							|  |  |  | 			} else if (strcmp(arg, "-v") == 0) { | 
					
						
							|  |  |  | 				verbose = 1; | 
					
						
							|  |  |  | 			} else if (strncmp(arg, "-mmcu=", 6) == 0) { | 
					
						
							|  |  |  | 				arg += 6; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				uint8_t valid_prefix = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (strncmp(arg, "at90usb", 7) == 0) { | 
					
						
							|  |  |  | 					valid_prefix = 1; | 
					
						
							|  |  |  | 					arg += 7; | 
					
						
							|  |  |  | 				} else if (strncmp(arg, "atmega", 6) == 0) { | 
					
						
							|  |  |  | 					valid_prefix = 1; | 
					
						
							|  |  |  | 					arg += 6; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					die("Unknown MCU type\n"); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (strncmp(arg, "128", 3) == 0) { | 
					
						
							|  |  |  | 					code_size  = 128 * 1024; | 
					
						
							|  |  |  | 					block_size = 256; | 
					
						
							|  |  |  | 				} else if (strncmp(arg, "64", 2) == 0) { | 
					
						
							|  |  |  | 					code_size  = 64 * 1024; | 
					
						
							|  |  |  | 					block_size = 256; | 
					
						
							|  |  |  | 				} else if (strncmp(arg, "32", 2) == 0) { | 
					
						
							|  |  |  | 					code_size  = 32 * 1024; | 
					
						
							|  |  |  | 					block_size = 128; | 
					
						
							|  |  |  | 				} else if (strncmp(arg, "16", 2) == 0) { | 
					
						
							|  |  |  | 					code_size  = 16 * 1024; | 
					
						
							|  |  |  | 					block_size = 128; | 
					
						
							|  |  |  | 				} else if (strncmp(arg, "8", 1) == 0) { | 
					
						
							|  |  |  | 					code_size  = 8 * 1024; | 
					
						
							|  |  |  | 					block_size = 128; | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					die("Unknown MCU type\n"); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			filename = argv[i]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |