Kiibohd Controller
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  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. // http://libusb.sourceforge.net/doc/index.html
  178. #include <usb.h>
  179. usb_dev_handle * open_usb_device(int vid, int pid)
  180. {
  181. struct usb_bus *bus;
  182. struct usb_device *dev;
  183. usb_dev_handle *h;
  184. char buf[128];
  185. int r;
  186. usb_init();
  187. usb_find_busses();
  188. usb_find_devices();
  189. //printf_verbose("\nSearching for USB device:\n");
  190. for (bus = usb_get_busses(); bus; bus = bus->next) {
  191. for (dev = bus->devices; dev; dev = dev->next) {
  192. //printf_verbose("bus \"%s\", device \"%s\" vid=%04X, pid=%04X\n",
  193. // bus->dirname, dev->filename,
  194. // dev->descriptor.idVendor,
  195. // dev->descriptor.idProduct
  196. //);
  197. if (dev->descriptor.idVendor != vid) continue;
  198. if (dev->descriptor.idProduct != pid) continue;
  199. h = usb_open(dev);
  200. if (!h) {
  201. printf_verbose("Found device but unable to open");
  202. continue;
  203. }
  204. #ifdef LIBUSB_HAS_GET_DRIVER_NP
  205. r = usb_get_driver_np(h, 0, buf, sizeof(buf));
  206. if (r >= 0) {
  207. r = usb_detach_kernel_driver_np(h, 0);
  208. if (r < 0) {
  209. usb_close(h);
  210. printf_verbose("Device is in use by \"%s\" driver", buf);
  211. continue;
  212. }
  213. }
  214. #endif
  215. // Mac OS-X - removing this call to usb_claim_interface() might allow
  216. // this to work, even though it is a clear misuse of the libusb API.
  217. // normally Apple's IOKit should be used on Mac OS-X
  218. r = usb_claim_interface(h, 0);
  219. if (r < 0) {
  220. usb_close(h);
  221. printf_verbose("Unable to claim interface, check USB permissions");
  222. continue;
  223. }
  224. return h;
  225. }
  226. }
  227. return NULL;
  228. }
  229. static usb_dev_handle *libusb_teensy_handle = NULL;
  230. int teensy_open(void)
  231. {
  232. teensy_close();
  233. libusb_teensy_handle = open_usb_device(0x16C0, 0x0478);
  234. if (libusb_teensy_handle) return 1;
  235. return 0;
  236. }
  237. int teensy_write(void *buf, int len, double timeout)
  238. {
  239. int r;
  240. if (!libusb_teensy_handle) return 0;
  241. while (timeout > 0) {
  242. r = usb_control_msg(libusb_teensy_handle, 0x21, 9, 0x0200, 0,
  243. (char *)buf, len, (int)(timeout * 1000.0));
  244. if (r >= 0) 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(void)
  252. {
  253. if (!libusb_teensy_handle) return;
  254. usb_release_interface(libusb_teensy_handle, 0);
  255. usb_close(libusb_teensy_handle);
  256. libusb_teensy_handle = NULL;
  257. }
  258. int hard_reboot(void)
  259. {
  260. usb_dev_handle *rebootor;
  261. int r;
  262. rebootor = open_usb_device(0x16C0, 0x0477);
  263. if (!rebootor) return 0;
  264. r = usb_control_msg(rebootor, 0x21, 9, 0x0200, 0, "reboot", 6, 100);
  265. usb_release_interface(rebootor, 0);
  266. usb_close(rebootor);
  267. if (r < 0) return 0;
  268. return 1;
  269. }
  270. #endif
  271. /****************************************************************/
  272. /* */
  273. /* USB Access - Microsoft WIN32 */
  274. /* */
  275. /****************************************************************/
  276. #if defined(USE_WIN32)
  277. // http://msdn.microsoft.com/en-us/library/ms790932.aspx
  278. #include <windows.h>
  279. #include <setupapi.h>
  280. #include <ddk/hidsdi.h>
  281. #include <ddk/hidclass.h>
  282. HANDLE open_usb_device(int vid, int pid)
  283. {
  284. GUID guid;
  285. HDEVINFO info;
  286. DWORD index, required_size;
  287. SP_DEVICE_INTERFACE_DATA iface;
  288. SP_DEVICE_INTERFACE_DETAIL_DATA *details;
  289. HIDD_ATTRIBUTES attrib;
  290. HANDLE h;
  291. BOOL ret;
  292. HidD_GetHidGuid(&guid);
  293. info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  294. if (info == INVALID_HANDLE_VALUE) return NULL;
  295. for (index=0; 1 ;index++) {
  296. iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  297. ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface);
  298. if (!ret) {
  299. SetupDiDestroyDeviceInfoList(info);
  300. break;
  301. }
  302. SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &required_size, NULL);
  303. details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(required_size);
  304. if (details == NULL) continue;
  305. memset(details, 0, required_size);
  306. details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  307. ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details,
  308. required_size, NULL, NULL);
  309. if (!ret) {
  310. free(details);
  311. continue;
  312. }
  313. h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE,
  314. FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  315. FILE_FLAG_OVERLAPPED, NULL);
  316. free(details);
  317. if (h == INVALID_HANDLE_VALUE) continue;
  318. attrib.Size = sizeof(HIDD_ATTRIBUTES);
  319. ret = HidD_GetAttributes(h, &attrib);
  320. if (!ret) {
  321. CloseHandle(h);
  322. continue;
  323. }
  324. if (attrib.VendorID != vid || attrib.ProductID != pid) {
  325. CloseHandle(h);
  326. continue;
  327. }
  328. SetupDiDestroyDeviceInfoList(info);
  329. return h;
  330. }
  331. return NULL;
  332. }
  333. int write_usb_device(HANDLE h, void *buf, int len, int timeout)
  334. {
  335. static HANDLE event = NULL;
  336. unsigned char tmpbuf[1040];
  337. OVERLAPPED ov;
  338. DWORD n, r;
  339. if (len > sizeof(tmpbuf) - 1) return 0;
  340. if (event == NULL) {
  341. event = CreateEvent(NULL, TRUE, TRUE, NULL);
  342. if (!event) return 0;
  343. }
  344. ResetEvent(&event);
  345. memset(&ov, 0, sizeof(ov));
  346. ov.hEvent = event;
  347. tmpbuf[0] = 0;
  348. memcpy(tmpbuf + 1, buf, len);
  349. if (!WriteFile(h, tmpbuf, len + 1, NULL, &ov)) {
  350. if (GetLastError() != ERROR_IO_PENDING) return 0;
  351. r = WaitForSingleObject(event, timeout);
  352. if (r == WAIT_TIMEOUT) {
  353. CancelIo(h);
  354. return 0;
  355. }
  356. if (r != WAIT_OBJECT_0) return 0;
  357. }
  358. if (!GetOverlappedResult(h, &ov, &n, FALSE)) return 0;
  359. if (n <= 0) return 0;
  360. return 1;
  361. }
  362. void print_win32_err(void)
  363. {
  364. char buf[256];
  365. DWORD err;
  366. err = GetLastError();
  367. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
  368. 0, buf, sizeof(buf), NULL);
  369. printf("err %ld: %s\n", err, buf);
  370. }
  371. static HANDLE win32_teensy_handle = NULL;
  372. int teensy_open(void)
  373. {
  374. teensy_close();
  375. win32_teensy_handle = open_usb_device(0x16C0, 0x0478);
  376. if (win32_teensy_handle) return 1;
  377. return 0;
  378. }
  379. int teensy_write(void *buf, int len, double timeout)
  380. {
  381. int r;
  382. if (!win32_teensy_handle) return 0;
  383. r = write_usb_device(win32_teensy_handle, buf, len, (int)(timeout * 1000.0));
  384. //if (!r) print_win32_err();
  385. return r;
  386. }
  387. void teensy_close(void)
  388. {
  389. if (!win32_teensy_handle) return;
  390. CloseHandle(win32_teensy_handle);
  391. win32_teensy_handle = NULL;
  392. }
  393. int hard_reboot(void)
  394. {
  395. HANDLE rebootor;
  396. int r;
  397. rebootor = open_usb_device(0x16C0, 0x0477);
  398. if (!rebootor) return 0;
  399. r = write_usb_device(rebootor, "reboot", 6, 100);
  400. CloseHandle(rebootor);
  401. return r;
  402. }
  403. #endif
  404. /****************************************************************/
  405. /* */
  406. /* USB Access - Apple's IOKit, Mac OS-X */
  407. /* */
  408. /****************************************************************/
  409. #if defined(USE_APPLE_IOKIT)
  410. // http://developer.apple.com/technotes/tn2007/tn2187.html
  411. #include <IOKit/IOKitLib.h>
  412. #include <IOKit/hid/IOHIDLib.h>
  413. #include <IOKit/hid/IOHIDDevice.h>
  414. struct usb_list_struct {
  415. IOHIDDeviceRef ref;
  416. int pid;
  417. int vid;
  418. struct usb_list_struct *next;
  419. };
  420. static struct usb_list_struct *usb_list=NULL;
  421. static IOHIDManagerRef hid_manager=NULL;
  422. void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
  423. {
  424. CFTypeRef type;
  425. struct usb_list_struct *n, *p;
  426. int32_t pid, vid;
  427. if (!dev) return;
  428. type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDVendorIDKey));
  429. if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
  430. if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &vid)) return;
  431. type = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDProductIDKey));
  432. if (!type || CFGetTypeID(type) != CFNumberGetTypeID()) return;
  433. if (!CFNumberGetValue((CFNumberRef)type, kCFNumberSInt32Type, &pid)) return;
  434. n = (struct usb_list_struct *)malloc(sizeof(struct usb_list_struct));
  435. if (!n) return;
  436. //printf("attach callback: vid=%04X, pid=%04X\n", vid, pid);
  437. n->ref = dev;
  438. n->vid = vid;
  439. n->pid = pid;
  440. n->next = NULL;
  441. if (usb_list == NULL) {
  442. usb_list = n;
  443. } else {
  444. for (p = usb_list; p->next; p = p->next) ;
  445. p->next = n;
  446. }
  447. }
  448. void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev)
  449. {
  450. struct usb_list_struct *p, *tmp, *prev=NULL;
  451. p = usb_list;
  452. while (p) {
  453. if (p->ref == dev) {
  454. if (prev) {
  455. prev->next = p->next;
  456. } else {
  457. usb_list = p->next;
  458. }
  459. tmp = p;
  460. p = p->next;
  461. free(tmp);
  462. } else {
  463. prev = p;
  464. p = p->next;
  465. }
  466. }
  467. }
  468. void init_hid_manager(void)
  469. {
  470. CFMutableDictionaryRef dict;
  471. IOReturn ret;
  472. if (hid_manager) return;
  473. hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
  474. if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) {
  475. if (hid_manager) CFRelease(hid_manager);
  476. printf_verbose("no HID Manager - maybe this is a pre-Leopard (10.5) system?\n");
  477. return;
  478. }
  479. dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
  480. &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  481. if (!dict) return;
  482. IOHIDManagerSetDeviceMatching(hid_manager, dict);
  483. CFRelease(dict);
  484. IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  485. IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL);
  486. IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL);
  487. ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
  488. if (ret != kIOReturnSuccess) {
  489. IOHIDManagerUnscheduleFromRunLoop(hid_manager,
  490. CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  491. CFRelease(hid_manager);
  492. printf_verbose("Error opening HID Manager");
  493. }
  494. }
  495. static void do_run_loop(void)
  496. {
  497. while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ;
  498. }
  499. IOHIDDeviceRef open_usb_device(int vid, int pid)
  500. {
  501. struct usb_list_struct *p;
  502. IOReturn ret;
  503. init_hid_manager();
  504. do_run_loop();
  505. for (p = usb_list; p; p = p->next) {
  506. if (p->vid == vid && p->pid == pid) {
  507. ret = IOHIDDeviceOpen(p->ref, kIOHIDOptionsTypeNone);
  508. if (ret == kIOReturnSuccess) return p->ref;
  509. }
  510. }
  511. return NULL;
  512. }
  513. void close_usb_device(IOHIDDeviceRef dev)
  514. {
  515. struct usb_list_struct *p;
  516. do_run_loop();
  517. for (p = usb_list; p; p = p->next) {
  518. if (p->ref == dev) {
  519. IOHIDDeviceClose(dev, kIOHIDOptionsTypeNone);
  520. return;
  521. }
  522. }
  523. }
  524. static IOHIDDeviceRef iokit_teensy_reference = NULL;
  525. int teensy_open(void)
  526. {
  527. teensy_close();
  528. iokit_teensy_reference = open_usb_device(0x16C0, 0x0478);
  529. if (iokit_teensy_reference) return 1;
  530. return 0;
  531. }
  532. int teensy_write(void *buf, int len, double timeout)
  533. {
  534. IOReturn ret;
  535. // timeouts do not work on OS-X
  536. // IOHIDDeviceSetReportWithCallback is not implemented
  537. // even though Apple documents it with a code example!
  538. // submitted to Apple on 22-sep-2009, problem ID 7245050
  539. if (!iokit_teensy_reference) return 0;
  540. ret = IOHIDDeviceSetReport(iokit_teensy_reference,
  541. kIOHIDReportTypeOutput, 0, buf, len);
  542. if (ret == kIOReturnSuccess) return 1;
  543. return 0;
  544. }
  545. void teensy_close(void)
  546. {
  547. if (!iokit_teensy_reference) return;
  548. close_usb_device(iokit_teensy_reference);
  549. iokit_teensy_reference = NULL;
  550. }
  551. int hard_reboot(void)
  552. {
  553. IOHIDDeviceRef rebootor;
  554. IOReturn ret;
  555. rebootor = open_usb_device(0x16C0, 0x0477);
  556. if (!rebootor) return 0;
  557. ret = IOHIDDeviceSetReport(rebootor,
  558. kIOHIDReportTypeOutput, 0, (uint8_t *)("reboot"), 6);
  559. close_usb_device(rebootor);
  560. if (ret == kIOReturnSuccess) return 1;
  561. return 0;
  562. }
  563. #endif
  564. /****************************************************************/
  565. /* */
  566. /* USB Access - BSD's UHID driver */
  567. /* */
  568. /****************************************************************/
  569. #if defined(USE_UHID)
  570. // Thanks to Todd T Fries for help getting this working on OpenBSD
  571. // and to Chris Kuethe for the initial patch to use UHID.
  572. #include <sys/ioctl.h>
  573. #include <fcntl.h>
  574. #include <dirent.h>
  575. #include <dev/usb/usb.h>
  576. #ifndef USB_GET_DEVICEINFO
  577. #include <dev/usb/usb_ioctl.h>
  578. #endif
  579. int open_usb_device(int vid, int pid)
  580. {
  581. int r, fd;
  582. DIR *dir;
  583. struct dirent *d;
  584. struct usb_device_info info;
  585. char buf[256];
  586. dir = opendir("/dev");
  587. if (!dir) return -1;
  588. while ((d = readdir(dir)) != NULL) {
  589. if (strncmp(d->d_name, "uhid", 4) != 0) continue;
  590. snprintf(buf, sizeof(buf), "/dev/%s", d->d_name);
  591. fd = open(buf, O_RDWR);
  592. if (fd < 0) continue;
  593. r = ioctl(fd, USB_GET_DEVICEINFO, &info);
  594. if (r < 0) {
  595. // NetBSD: added in 2004
  596. // OpenBSD: added November 23, 2009
  597. // FreeBSD: missing (FreeBSD 8.0) - USE_LIBUSB works!
  598. die("Error: your uhid driver does not support"
  599. " USB_GET_DEVICEINFO, please upgrade!\n");
  600. close(fd);
  601. closedir(dir);
  602. exit(1);
  603. }
  604. //printf("%s: v=%d, p=%d\n", buf, info.udi_vendorNo, info.udi_productNo);
  605. if (info.udi_vendorNo == vid && info.udi_productNo == pid) {
  606. closedir(dir);
  607. return fd;
  608. }
  609. close(fd);
  610. }
  611. closedir(dir);
  612. return -1;
  613. }
  614. static int uhid_teensy_fd = -1;
  615. int teensy_open(void)
  616. {
  617. teensy_close();
  618. uhid_teensy_fd = open_usb_device(0x16C0, 0x0478);
  619. if (uhid_teensy_fd < 0) return 0;
  620. return 1;
  621. }
  622. int teensy_write(void *buf, int len, double timeout)
  623. {
  624. int r;
  625. // TODO: imeplement timeout... how??
  626. r = write(uhid_teensy_fd, buf, len);
  627. if (r == len) return 1;
  628. return 0;
  629. }
  630. void teensy_close(void)
  631. {
  632. if (uhid_teensy_fd >= 0) {
  633. close(uhid_teensy_fd);
  634. uhid_teensy_fd = -1;
  635. }
  636. }
  637. int hard_reboot(void)
  638. {
  639. int r, rebootor_fd;
  640. rebootor_fd = open_usb_device(0x16C0, 0x0477);
  641. if (rebootor_fd < 0) return 0;
  642. r = write(rebootor_fd, "reboot", 6);
  643. delay(0.1);
  644. close(rebootor_fd);
  645. if (r == 6) return 1;
  646. return 0;
  647. }
  648. #endif
  649. /****************************************************************/
  650. /* */
  651. /* Read Intel Hex File */
  652. /* */
  653. /****************************************************************/
  654. // the maximum flash image size we can support
  655. // chips with larger memory may be used, but only this
  656. // much intel-hex data can be loaded into memory!
  657. #define MAX_MEMORY_SIZE 0x40000
  658. static unsigned char firmware_image[MAX_MEMORY_SIZE];
  659. static unsigned char firmware_mask[MAX_MEMORY_SIZE];
  660. static int end_record_seen=0;
  661. static int byte_count;
  662. static unsigned int extended_addr = 0;
  663. static int parse_hex_line(char *line);
  664. int read_intel_hex(const char *filename)
  665. {
  666. FILE *fp;
  667. int i, lineno=0;
  668. char buf[1024];
  669. byte_count = 0;
  670. end_record_seen = 0;
  671. for (i=0; i<MAX_MEMORY_SIZE; i++) {
  672. firmware_image[i] = 0xFF;
  673. firmware_mask[i] = 0;
  674. }
  675. extended_addr = 0;
  676. fp = fopen(filename, "r");
  677. if (fp == NULL) {
  678. //printf("Unable to read file %s\n", filename);
  679. return -1;
  680. }
  681. while (!feof(fp)) {
  682. *buf = '\0';
  683. if (!fgets(buf, sizeof(buf), fp)) break;
  684. lineno++;
  685. if (*buf) {
  686. if (parse_hex_line(buf) == 0) {
  687. printf("Warning, HEX parse error line %d\n", lineno);
  688. return -2;
  689. }
  690. }
  691. if (end_record_seen) break;
  692. if (feof(stdin)) break;
  693. }
  694. fclose(fp);
  695. return byte_count;
  696. }
  697. /* from ihex.c, at http://www.pjrc.com/tech/8051/pm2_docs/intel-hex.html */
  698. /* parses a line of intel hex code, stores the data in bytes[] */
  699. /* and the beginning address in addr, and returns a 1 if the */
  700. /* line was valid, or a 0 if an error occured. The variable */
  701. /* num gets the number of bytes that were stored into bytes[] */
  702. int
  703. parse_hex_line(char *line)
  704. {
  705. int addr, code, num;
  706. int sum, len, cksum, i;
  707. char *ptr;
  708. num = 0;
  709. if (line[0] != ':') return 0;
  710. if (strlen(line) < 11) return 0;
  711. ptr = line+1;
  712. if (!sscanf(ptr, "%02x", &len)) return 0;
  713. ptr += 2;
  714. if ((int)strlen(line) < (11 + (len * 2)) ) return 0;
  715. if (!sscanf(ptr, "%04x", &addr)) return 0;
  716. ptr += 4;
  717. /* printf("Line: length=%d Addr=%d\n", len, addr); */
  718. if (!sscanf(ptr, "%02x", &code)) return 0;
  719. if (addr + extended_addr + len >= MAX_MEMORY_SIZE) return 0;
  720. ptr += 2;
  721. sum = (len & 255) + ((addr >> 8) & 255) + (addr & 255) + (code & 255);
  722. if (code != 0) {
  723. if (code == 1) {
  724. end_record_seen = 1;
  725. return 1;
  726. }
  727. if (code == 2 && len == 2) {
  728. if (!sscanf(ptr, "%04x", &i)) return 1;
  729. ptr += 4;
  730. sum += ((i >> 8) & 255) + (i & 255);
  731. if (!sscanf(ptr, "%02x", &cksum)) return 1;
  732. if (((sum & 255) + (cksum & 255)) & 255) return 1;
  733. extended_addr = i << 4;
  734. //printf("ext addr = %05X\n", extended_addr);
  735. }
  736. if (code == 4 && len == 2) {
  737. if (!sscanf(ptr, "%04x", &i)) return 1;
  738. ptr += 4;
  739. sum += ((i >> 8) & 255) + (i & 255);
  740. if (!sscanf(ptr, "%02x", &cksum)) return 1;
  741. if (((sum & 255) + (cksum & 255)) & 255) return 1;
  742. extended_addr = i << 16;
  743. //printf("ext addr = %08X\n", extended_addr);
  744. }
  745. return 1; // non-data line
  746. }
  747. byte_count += len;
  748. while (num != len) {
  749. if (sscanf(ptr, "%02x", &i) != 1) return 0;
  750. i &= 255;
  751. firmware_image[addr + extended_addr + num] = i;
  752. firmware_mask[addr + extended_addr + num] = 1;
  753. ptr += 2;
  754. sum += i;
  755. (num)++;
  756. if (num >= 256) return 0;
  757. }
  758. if (!sscanf(ptr, "%02x", &cksum)) return 0;
  759. if (((sum & 255) + (cksum & 255)) & 255) return 0; /* checksum error */
  760. return 1;
  761. }
  762. int ihex_bytes_within_range(int begin, int end)
  763. {
  764. int i;
  765. if (begin < 0 || begin >= MAX_MEMORY_SIZE ||
  766. end < 0 || end >= MAX_MEMORY_SIZE) {
  767. return 0;
  768. }
  769. for (i=begin; i<=end; i++) {
  770. if (firmware_mask[i]) return 1;
  771. }
  772. return 0;
  773. }
  774. void ihex_get_data(int addr, int len, unsigned char *bytes)
  775. {
  776. int i;
  777. if (addr < 0 || len < 0 || addr + len >= MAX_MEMORY_SIZE) {
  778. for (i=0; i<len; i++) {
  779. bytes[i] = 255;
  780. }
  781. return;
  782. }
  783. for (i=0; i<len; i++) {
  784. if (firmware_mask[addr]) {
  785. bytes[i] = firmware_image[addr];
  786. } else {
  787. bytes[i] = 255;
  788. }
  789. addr++;
  790. }
  791. }
  792. int memory_is_blank(int addr, int block_size)
  793. {
  794. if (addr < 0 || addr > MAX_MEMORY_SIZE) return 1;
  795. while (block_size && addr < MAX_MEMORY_SIZE) {
  796. if (firmware_mask[addr] && firmware_image[addr] != 255) return 0;
  797. addr++;
  798. block_size--;
  799. }
  800. return 1;
  801. }
  802. /****************************************************************/
  803. /* */
  804. /* Misc Functions */
  805. /* */
  806. /****************************************************************/
  807. int printf_verbose(const char *format, ...)
  808. {
  809. va_list ap;
  810. int r;
  811. va_start(ap, format);
  812. if (verbose) {
  813. r = vprintf(format, ap);
  814. fflush(stdout);
  815. return r;
  816. }
  817. return 0;
  818. }
  819. void delay(double seconds)
  820. {
  821. #ifdef WIN32
  822. Sleep(seconds * 1000.0);
  823. #else
  824. usleep(seconds * 1000000.0);
  825. #endif
  826. }
  827. void die(const char *str, ...)
  828. {
  829. va_list ap;
  830. va_start(ap, str);
  831. vfprintf(stderr, str, ap);
  832. fprintf(stderr, "\n");
  833. exit(1);
  834. }
  835. #if defined(WIN32)
  836. #define strcasecmp stricmp
  837. #endif
  838. void parse_options(int argc, char **argv)
  839. {
  840. int i;
  841. const char *arg;
  842. for (i=1; i<argc; i++) {
  843. arg = argv[i];
  844. //printf("arg: %s\n", arg);
  845. if (*arg == '-') {
  846. if (strcmp(arg, "-w") == 0) {
  847. wait_for_device_to_appear = 1;
  848. } else if (strcmp(arg, "-r") == 0) {
  849. hard_reboot_device = 1;
  850. } else if (strcmp(arg, "-n") == 0) {
  851. reboot_after_programming = 0;
  852. } else if (strcmp(arg, "-v") == 0) {
  853. verbose = 1;
  854. } else if (strncmp(arg, "-mmcu=", 6) == 0) {
  855. if (strcasecmp(arg+6, "at90usb162") == 0) {
  856. code_size = 15872;
  857. block_size = 128;
  858. } else if (strcasecmp(arg+6, "atmega32u4") == 0) {
  859. code_size = 32256;
  860. block_size = 128;
  861. } else if (strcasecmp(arg+6, "at90usb646") == 0) {
  862. code_size = 64512;
  863. block_size = 256;
  864. } else if (strcasecmp(arg+6, "at90usb1286") == 0) {
  865. code_size = 130048;
  866. block_size = 256;
  867. #if defined(USE_LIBUSB)
  868. } else if (strcasecmp(arg+6, "mk20dx128") == 0) {
  869. code_size = 131072;
  870. block_size = 1024;
  871. } else if (strcasecmp(arg+6, "mk20dx256") == 0) {
  872. code_size = 262144;
  873. block_size = 1024;
  874. #endif
  875. } else {
  876. die("Unknown MCU type\n");
  877. }
  878. }
  879. } else {
  880. filename = argv[i];
  881. }
  882. }
  883. }