Kiibohd Controller
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

teensy_loader_cli.c 26KB

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