From 12feffb9d0e7f2b79e59da38d7ae9ce85a8a4ba8 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 10 Feb 2023 16:20:55 +0100 Subject: [PATCH 1/9] chore: remove duplicate upload-reset.c source file Signed-off-by: Frederic Pillon --- linux/src/upload-reset/upload-reset.c | 161 ------------------------- macosx/src/upload-reset/upload-reset.c | 161 ------------------------- 2 files changed, 322 deletions(-) delete mode 100644 linux/src/upload-reset/upload-reset.c delete mode 100644 macosx/src/upload-reset/upload-reset.c diff --git a/linux/src/upload-reset/upload-reset.c b/linux/src/upload-reset/upload-reset.c deleted file mode 100644 index 1d03bff51..000000000 --- a/linux/src/upload-reset/upload-reset.c +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright (C) 2015 Roger Clark - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * - * Utility to send the reset sequence on RTS and DTR and chars - * which resets the libmaple and causes the bootloader to be run - * - * - * - * Terminal control code by Heiko Noordhof (see copyright below) - */ - - - -/* Copyright (C) 2003 Heiko Noordhof - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Function prototypes (belong in a seperate header file) */ -int openserial(char *devicename); -void closeserial(void); -int setDTR(unsigned short level); -int setRTS(unsigned short level); - - -/* Two globals for use by this module only */ -static int fd; -static struct termios oldterminfo; - - -void closeserial(void) -{ - tcsetattr(fd, TCSANOW, &oldterminfo); - close(fd); -} - - -int openserial(char *devicename) -{ - struct termios attr; - - if ((fd = open(devicename, O_RDWR)) == -1) return 0; /* Error */ - atexit(closeserial); - - if (tcgetattr(fd, &oldterminfo) == -1) return 0; /* Error */ - attr = oldterminfo; - attr.c_cflag |= CRTSCTS | CLOCAL; - attr.c_oflag = 0; - if (tcflush(fd, TCIOFLUSH) == -1) return 0; /* Error */ - if (tcsetattr(fd, TCSANOW, &attr) == -1) return 0; /* Error */ - - /* Set the lines to a known state, and */ - /* finally return non-zero is successful. */ - return setRTS(0) && setDTR(0); -} - - -/* For the two functions below: - * level=0 to set line to LOW - * level=1 to set line to HIGH - */ - -int setRTS(unsigned short level) -{ - int status; - - if (ioctl(fd, TIOCMGET, &status) == -1) { - perror("setRTS(): TIOCMGET"); - return 0; - } - if (level) status |= TIOCM_RTS; - else status &= ~TIOCM_RTS; - if (ioctl(fd, TIOCMSET, &status) == -1) { - perror("setRTS(): TIOCMSET"); - return 0; - } - return 1; -} - - -int setDTR(unsigned short level) -{ - int status; - - if (ioctl(fd, TIOCMGET, &status) == -1) { - perror("setDTR(): TIOCMGET"); - return 0; - } - if (level) status |= TIOCM_DTR; - else status &= ~TIOCM_DTR; - if (ioctl(fd, TIOCMSET, &status) == -1) { - perror("setDTR: TIOCMSET"); - return 0; - } - return 1; -} - -/* This portion of code was written by Roger Clark - * It was informed by various other pieces of code written by Leaflabs to reset their - * Maple and Maple mini boards - */ - -main(int argc, char *argv[]) -{ - - if (argc<2 || argc >3) - { - printf("Usage upload-reset \n\r"); - return; - } - - if (openserial(argv[1])) - { - // Send magic sequence of DTR and RTS followed by the magic word "1EAF" - setRTS(false); - setDTR(false); - setDTR(true); - - usleep(50000L); - - setDTR(false); - setRTS(true); - setDTR(true); - - usleep(50000L); - - setDTR(false); - - usleep(50000L); - - write(fd,"1EAF",4); - - closeserial(); - if (argc==3) - { - usleep(atol(argv[2])*1000L); - } - } - else - { - printf("Failed to open serial device.\n\r"); - } -} diff --git a/macosx/src/upload-reset/upload-reset.c b/macosx/src/upload-reset/upload-reset.c deleted file mode 100644 index 1d03bff51..000000000 --- a/macosx/src/upload-reset/upload-reset.c +++ /dev/null @@ -1,161 +0,0 @@ -/* Copyright (C) 2015 Roger Clark - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * - * Utility to send the reset sequence on RTS and DTR and chars - * which resets the libmaple and causes the bootloader to be run - * - * - * - * Terminal control code by Heiko Noordhof (see copyright below) - */ - - - -/* Copyright (C) 2003 Heiko Noordhof - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Function prototypes (belong in a seperate header file) */ -int openserial(char *devicename); -void closeserial(void); -int setDTR(unsigned short level); -int setRTS(unsigned short level); - - -/* Two globals for use by this module only */ -static int fd; -static struct termios oldterminfo; - - -void closeserial(void) -{ - tcsetattr(fd, TCSANOW, &oldterminfo); - close(fd); -} - - -int openserial(char *devicename) -{ - struct termios attr; - - if ((fd = open(devicename, O_RDWR)) == -1) return 0; /* Error */ - atexit(closeserial); - - if (tcgetattr(fd, &oldterminfo) == -1) return 0; /* Error */ - attr = oldterminfo; - attr.c_cflag |= CRTSCTS | CLOCAL; - attr.c_oflag = 0; - if (tcflush(fd, TCIOFLUSH) == -1) return 0; /* Error */ - if (tcsetattr(fd, TCSANOW, &attr) == -1) return 0; /* Error */ - - /* Set the lines to a known state, and */ - /* finally return non-zero is successful. */ - return setRTS(0) && setDTR(0); -} - - -/* For the two functions below: - * level=0 to set line to LOW - * level=1 to set line to HIGH - */ - -int setRTS(unsigned short level) -{ - int status; - - if (ioctl(fd, TIOCMGET, &status) == -1) { - perror("setRTS(): TIOCMGET"); - return 0; - } - if (level) status |= TIOCM_RTS; - else status &= ~TIOCM_RTS; - if (ioctl(fd, TIOCMSET, &status) == -1) { - perror("setRTS(): TIOCMSET"); - return 0; - } - return 1; -} - - -int setDTR(unsigned short level) -{ - int status; - - if (ioctl(fd, TIOCMGET, &status) == -1) { - perror("setDTR(): TIOCMGET"); - return 0; - } - if (level) status |= TIOCM_DTR; - else status &= ~TIOCM_DTR; - if (ioctl(fd, TIOCMSET, &status) == -1) { - perror("setDTR: TIOCMSET"); - return 0; - } - return 1; -} - -/* This portion of code was written by Roger Clark - * It was informed by various other pieces of code written by Leaflabs to reset their - * Maple and Maple mini boards - */ - -main(int argc, char *argv[]) -{ - - if (argc<2 || argc >3) - { - printf("Usage upload-reset \n\r"); - return; - } - - if (openserial(argv[1])) - { - // Send magic sequence of DTR and RTS followed by the magic word "1EAF" - setRTS(false); - setDTR(false); - setDTR(true); - - usleep(50000L); - - setDTR(false); - setRTS(true); - setDTR(true); - - usleep(50000L); - - setDTR(false); - - usleep(50000L); - - write(fd,"1EAF",4); - - closeserial(); - if (argc==3) - { - usleep(atol(argv[2])*1000L); - } - } - else - { - printf("Failed to open serial device.\n\r"); - } -} From 52dd8582dbd75ddc9af24d4bc3e9418d38f31486 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 10 Feb 2023 16:21:45 +0100 Subject: [PATCH 2/9] chore: remove deprecated maple_loader source files Signed-off-by: Frederic Pillon --- src/maple_loader/README.md | 5 - src/maple_loader/build.xml | 73 - src/maple_loader/build/built-jar.properties | 4 - .../build/classes/CliTemplate/CliMain.class | Bin 1753 -> 0 bytes .../classes/CliTemplate/DFUUploader.class | Bin 7476 -> 0 bytes .../classes/CliTemplate/ExecCommand.class | Bin 3243 -> 0 bytes .../build/classes/processing/app/Base.class | Bin 639 -> 0 bytes .../classes/processing/app/Preferences.class | Bin 2215 -> 0 bytes .../build/classes/processing/app/Serial.class | Bin 7732 -> 0 bytes .../processing/app/SerialException.class | Bin 735 -> 0 bytes .../app/debug/MessageConsumer.class | Bin 174 -> 0 bytes .../processing/app/debug/MessageSiphon.class | Bin 2325 -> 0 bytes .../app/debug/RunnerException.class | Bin 2509 -> 0 bytes .../processing/app/helpers/ProcessUtils.class | Bin 1399 -> 0 bytes src/maple_loader/dist/README.TXT | 32 - src/maple_loader/dist/lib/jssc.jar | Bin 152418 -> 0 bytes src/maple_loader/dist/maple_loader.jar | Bin 32791 -> 0 bytes src/maple_loader/jars/jssc.jar | Bin 152418 -> 0 bytes src/maple_loader/manifest.mf | 3 - src/maple_loader/nbproject/build-impl.xml | 1413 ----------------- .../nbproject/genfiles.properties | 8 - .../nbproject/private/config.properties | 0 .../nbproject/private/private.properties | 6 - .../nbproject/private/private.xml | 10 - src/maple_loader/nbproject/project.properties | 79 - src/maple_loader/nbproject/project.xml | 15 - src/maple_loader/src/CliTemplate/CliMain.java | 60 - .../src/CliTemplate/DFUUploader.java | 345 ---- .../src/CliTemplate/ExecCommand.java | 119 -- src/maple_loader/src/processing/app/Base.java | 53 - .../src/processing/app/Preferences.java | 157 -- .../src/processing/app/Serial.java | 527 ------ .../src/processing/app/SerialException.java | 39 - .../processing/app/debug/MessageConsumer.java | 42 - .../processing/app/debug/MessageSiphon.java | 104 -- .../processing/app/debug/RunnerException.java | 161 -- .../processing/app/helpers/ProcessUtils.java | 32 - 37 files changed, 3287 deletions(-) delete mode 100644 src/maple_loader/README.md delete mode 100644 src/maple_loader/build.xml delete mode 100644 src/maple_loader/build/built-jar.properties delete mode 100644 src/maple_loader/build/classes/CliTemplate/CliMain.class delete mode 100644 src/maple_loader/build/classes/CliTemplate/DFUUploader.class delete mode 100644 src/maple_loader/build/classes/CliTemplate/ExecCommand.class delete mode 100644 src/maple_loader/build/classes/processing/app/Base.class delete mode 100644 src/maple_loader/build/classes/processing/app/Preferences.class delete mode 100644 src/maple_loader/build/classes/processing/app/Serial.class delete mode 100644 src/maple_loader/build/classes/processing/app/SerialException.class delete mode 100644 src/maple_loader/build/classes/processing/app/debug/MessageConsumer.class delete mode 100644 src/maple_loader/build/classes/processing/app/debug/MessageSiphon.class delete mode 100644 src/maple_loader/build/classes/processing/app/debug/RunnerException.class delete mode 100644 src/maple_loader/build/classes/processing/app/helpers/ProcessUtils.class delete mode 100644 src/maple_loader/dist/README.TXT delete mode 100644 src/maple_loader/dist/lib/jssc.jar delete mode 100644 src/maple_loader/dist/maple_loader.jar delete mode 100644 src/maple_loader/jars/jssc.jar delete mode 100644 src/maple_loader/manifest.mf delete mode 100644 src/maple_loader/nbproject/build-impl.xml delete mode 100644 src/maple_loader/nbproject/genfiles.properties delete mode 100644 src/maple_loader/nbproject/private/config.properties delete mode 100644 src/maple_loader/nbproject/private/private.properties delete mode 100644 src/maple_loader/nbproject/private/private.xml delete mode 100644 src/maple_loader/nbproject/project.properties delete mode 100644 src/maple_loader/nbproject/project.xml delete mode 100644 src/maple_loader/src/CliTemplate/CliMain.java delete mode 100644 src/maple_loader/src/CliTemplate/DFUUploader.java delete mode 100644 src/maple_loader/src/CliTemplate/ExecCommand.java delete mode 100644 src/maple_loader/src/processing/app/Base.java delete mode 100644 src/maple_loader/src/processing/app/Preferences.java delete mode 100644 src/maple_loader/src/processing/app/Serial.java delete mode 100644 src/maple_loader/src/processing/app/SerialException.java delete mode 100644 src/maple_loader/src/processing/app/debug/MessageConsumer.java delete mode 100644 src/maple_loader/src/processing/app/debug/MessageSiphon.java delete mode 100644 src/maple_loader/src/processing/app/debug/RunnerException.java delete mode 100644 src/maple_loader/src/processing/app/helpers/ProcessUtils.java diff --git a/src/maple_loader/README.md b/src/maple_loader/README.md deleted file mode 100644 index c6c937950..000000000 --- a/src/maple_loader/README.md +++ /dev/null @@ -1,5 +0,0 @@ -These files build the maple_loader.jar file used on Windows to reset the Sketch via USB Serial, so that the bootloader will run in dfu upload mode, ready for a new sketch to be uploaded - -The files were written by @bobC (github) and have been slightly modified by me (Roger Clark), so that dfu-util no longer attempts to reset the board after upload. -This change to dfu-util's reset command line argument, was required because dfu-util was showing errors on some Windows systems, because the bootloader had reset its self after upload, -before dfu-util had chance to tell it to reset. \ No newline at end of file diff --git a/src/maple_loader/build.xml b/src/maple_loader/build.xml deleted file mode 100644 index 80bdd6fdb..000000000 --- a/src/maple_loader/build.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - Builds, tests, and runs the project maple_loader. - - - diff --git a/src/maple_loader/build/built-jar.properties b/src/maple_loader/build/built-jar.properties deleted file mode 100644 index 10752d534..000000000 --- a/src/maple_loader/build/built-jar.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Mon, 20 Jul 2015 11:21:26 +1000 - - -C\:\\Users\\rclark\\Desktop\\maple-asp-master\\installer\\maple_loader= diff --git a/src/maple_loader/build/classes/CliTemplate/CliMain.class b/src/maple_loader/build/classes/CliTemplate/CliMain.class deleted file mode 100644 index 37ee63000b20df7528829288b7f0fbeb28eb3b98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1753 zcmZ`(?^7F96g^8e*(Ke!Bot_BEkSJ?Qc5V;R-jfb6dMgcG>{5a@g;erOE=l=X2Z~N zI-?()v44qQZ9mYCj{X7uQR;cgB4LP`%)9&UJMY|k&%L{U{r%gY0A}FDk-}_0<}h#K zP8=WNu8EK0_!ysNj62~BB)v{_}O_60{U^nDSt6rA=x+pvJBnxgu zI3?lRY9BiF;IZA*FjQD@>~&f991+MIpO=N*m?v4CR>N@SQDIl?iJT)EwOldq?M7{0 z1=Gko)OB=!zaqWBcH4J_UnBKkkE}dUI6;1gw$&`>7YQ%hjU`)E zajLr0+VC7#RHd&Wbu912rH#WQ=6<>uh{}^?;k8ROkTtMLX(_0Nc+qY771^P*!g?oF zA{H)T)WDX7NBCMpqAol~Zg=9P_ogOq82HA*x7cPXO-U`CNso0H_|AernPCsT6gqfD ziB{N*&{q|KDBD5PLIqWlAG&3^RonI{{SmYoxSoP)usq+b`J%ok9YH>;)vkUrROWE2 z1fx)i@Km${ciWdu8CZ~@l4rt$J?WR-CIgLhcf3nE3pG4u+m5>OUsEmEN|O=MNK4;$ z{j^)Dw0vJy$I{IU`M8_2<0+8CF&@gCoHaGY7pQPWHk+L4obWud${p#; z27L@k4K-ZtakV#DocMerkTo@*!#%F$RY--p=emv*?bquh)s{kq%`Mr24f>z_x0oWk zLCTs8mRW_UvAgFo<0m=Ux^{yCxgX?0=#uN#1q+Prgb%YlQtp0*JB^+1Ngr)XjWN8< zkD&VXK~wJ&*EDxIT8%cEeGTnp`*@6NtnD1eJAAe}0KAL$xa-GdT%jioXby1(eJ`?+ z=|WbYUd~3RSF*9`IsFy-l92=G$>_B=h$W4rsZ9R>O+0xjarp;jEnTgr6Z)^pp1H0d zXD8G;z>`EW8R7an1~*^h+*~vjP3Z?1diV=2&c$9~Bza!{1F6kODt3Si#W#5C02f~} zu__!6^)Mo=87N_h>m}%{*ksZcy$P0*Vi}_>IX diff --git a/src/maple_loader/build/classes/CliTemplate/DFUUploader.class b/src/maple_loader/build/classes/CliTemplate/DFUUploader.class deleted file mode 100644 index 77087b052fbd03f77b9e1417f2754196beaf1844..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7476 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 diff --git a/src/maple_loader/build/classes/CliTemplate/ExecCommand.class b/src/maple_loader/build/classes/CliTemplate/ExecCommand.class deleted file mode 100644 index ad95f79845d3d1b0c1d2245d06800c06c37e8c08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3243 zcma)8TW}NS75;u{rC%0{F$RGJfhdV%e8DI8>iD5`@f$5 zobR0TowIuL-k)v*cpTT`Xu((=I*^sf#Sz9>9Ca|&Fun>Cm{fx$aYoHgOYE&f9t8WB885cO{+|kW;2R=9EkUaYA6t zxaF3-gRbkihn%vV6KE)zS;x-R9@UxCS+nR_jxEqKP;{NFSt?ofMA|48(>ZgjJdr+9 zwr$frxFEMnAiCSKEw5J~+}d_bK6Ts5zpt3hVZm@qR|ani9V8zv@!I)W%#c?OJOT$+=a;zC}UmqFTH zV?2m#49>}jGqW>Tz-F`Y~^#NtK+Bm8Ih%QT*6BdKiBapPV4xEf|14!9gks$#A`a{ z@XG~EOL@W!{XfN|<5vp$<4XIl@r1y`E52HiR*4sN{06^O&o1luom%}~A^U^!dF!H2 zD^XI%PIT$`gmS;(++*icuIZIs+sviT?L5CEVnbtR%&aGIMaNbAQQ~zS*HBSGI4w|b zPFr3o%ewDLQ42%)KGpnwaR@x>bL>*NV3MQti;1n4$l66m0`9Y3S?L9V^{s99bBPti zYM$^W{kFu44jVbv=n~phecIK=?x>ZlXGk{bIX;gBT9@>f1N} z$}HW*mNCrshI|tYLYF9FnPqJE{mK z6v5<_kuRG=8sTcI_HMSA5xSb;dhj19djx zgIwuVNxpfKJAoeTq6D>sPebyj48*Bh2#;QeHrR2v^LDou?v5lP3GEWLbtWQRJ<(*e zf=G3W&O+awjNXI{;rNA!n4AB{_U$(j6Lz106kD zQoG$933o>m(M04D+LKx$+SMbkLcfL8v|OK*6|8A&;84NZ3K}m&srv7{uV7t!_!`!$ zA<=OI8+x=kZ0?ENLepq6QbF=MHdUc*PDbzC!ULm8t%5BK%T^^+-9G4VqguC2$XRSv z?^4RCl#+d@H{31f=Ks|bo16b95kK-*#ME?Wi}orWyo%<=MqhnX3br`OQNu>~<~ z!&bE7QSLj@&bw{cO->APH$n~^B_ocrNuMSU&XNPqbG}F>yu$2WVpiuUeHr^{VGsLq zFEg+gf5ATd4SjeEAI97GDBeLo-o?l9Zw%lr25}EVLSR_bVN^8Wgh=3&*u*y84MX%` zOk|K1Pa!8xV%+D@n^;ebO|-NJQ8KKHcJ`8!^~AT2wl%CJmk)3iA;wL#yocN}=!=rm zsAZ=w7lFkWN-j#AF{10@>MGfK5Qh*EQAXq=#2X`m>TOK%GvKaT^-~|apcui&=nq*a zBJ^oLv0UaiZxDxR?JYdV=nWIg+nC~)ZJ0LRK?z4_TOvanswS#BMyTT`PmW;CJe`P2 z9FtfjahxMVgyy@5G|gijx0-$0j#Q*>R diff --git a/src/maple_loader/build/classes/processing/app/Base.class b/src/maple_loader/build/classes/processing/app/Base.class deleted file mode 100644 index 4aa0bde02049fbb6c4e035d952edc3f002cba1e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmaKp%TB^T6o&tSLZKAVg7^Ck!G)N(aDg#K6B84>Bp6NH4Q13pXq&cpc^a2)+_+KW z!Uyo7jHgH%(vSU{TL#iY#anNj3gnP^@bs|Q|HhKMoyE2H|Q1LIN$1qrOT-y|$C#{PD zcbvjD_e7B)F1=G}RqY$fA^jOcvg~v7YM(o8fhs+!)VyWT%68K=#jXsB#RI`gjbC#e zacB&x?X6h6Aymxhn8h5Cwpqozjs+|-MB1iwk7gM916!fasl&rcO_+WcD&Kj&XfPx$ zgn#7Pj&S`uhHS3%^Q!E-G+r_P8+DsnY1AJLE^ZIc>Fe~e?9mh|{hDBfK@&rxJwZ`{ zPDW>B`33BWE+Oc&M_X_PNxJLb3Ft$LqB#07KqPp)PT9fA7@=2$4doe;&^=V;0ZRCh ec&BR#29XFt##T^2{g)*ApJcUD!jNgz82kc&eSc^G diff --git a/src/maple_loader/build/classes/processing/app/Preferences.class b/src/maple_loader/build/classes/processing/app/Preferences.class deleted file mode 100644 index 89cf0100455af1f41500150e545c8bbd12583674..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2215 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 L#S!xqDulu}Wzd50 diff --git a/src/maple_loader/build/classes/processing/app/debug/MessageConsumer.class b/src/maple_loader/build/classes/processing/app/debug/MessageConsumer.class deleted file mode 100644 index 37250e7704487822639cf03f4e4a333da994be50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174 zcmX^0Z`VEs1_omWPId-%b_Nbc2KL<4;^M^gR7M6-4WF#UvPAuy#JqI<;F6-uymV{L zFh&Nh;QZ2}36TD<=a zee$u-T}#4J*3vf~eDmkHmbdTB3`x3-T|Q)=efH(-y}z^fnf&_KPd@_~$Jc3`K|#YE z4ezEAM=^~U<~s2b<`r2`3FpOF@DY|1aeE`vQp>rz{0}ik26Y+<5P_3@WA4aH*G_Nr)yS)eXYYsjn$=fJOWF4tYZhC37l!#w}YMI5E!%pT%fP% z+dxal=PHf9X`?)_MwAB1vTAyk>pLES*6{_t)bW){_Z9doX zp*cQw*xW5Rg|$DEB4^Hd92&M1T~J--)m&ee8#S=#_5-Loy058<-UTH+9!Y~sI?QMy zn1HJE?|PQwSw7)TWD82zQS}XvWu(;85YEQY?D>`vXiP_vZ;Q0~d|YUa5UKy|5#2V& zD&;$eAPhYZ*KvUzx$BPrxE*8^HuS-Abd74{xS?(;X{fBvh&yULy=i|kxTlNf7 z;w+!=GZ1(g31n24^DB^1jm|Zu+BsO+^IQ|O%i=s~j=OJ>nhpw19x}OH;50efeMVe!jVSW-ua2gkw zO`dcdm+%Iz;Y~`x9D}Hok8;QOw0WI5DNf}bBYzQNVV2?>S|_O6VZ79L80C_z<4CD^ zfI;%wK6*-f=pC-(g-nK|j=mppG=?XC|CSTX_X(zo5p(&F87o^tr z9?2)rD19-q?V1mm3%@)Ksv5%;9Ag$^m_dKA7Fna(JET`I5v((~5v)b52P@x^V2u+I z;12HvxQ;$d({BZrQKIK8eOE9=eg?Pczk&k!BCY2zk3}rN#66z3f(qph*T;Ae;5fm_32#8&VW5Z_DWZjif-x5zCr=eMcl9{`-9>GD2Q?oaJ}>;w=qVZ)>>5-{ha@ zC)IHMcf={5(&)lhg-58CS>Z0m^@zIs;_yKL*=f}RVTnhAt9^(L80hAo19jc~p+^+7 zg8`@6lwrath(FM+v2>NRYR{Ye%`#rtqAGQjaxxcZ8#Y@_{ZRoV0mQotV5n6@E2k~%3N36at+NEB6-iZpQsd%&@c zA5A4Tuz*j%h6Rru8x|m8Sz^Hl;6tJQ&z#FqWkoT zMK-PSux61%52o=};bEPJ4IUoy@DZt?IbKWPfebnC6t{hn9-@}T2Yu_~Sl zGS`A;(5nc_7S3xI4+ZI)kPtM>f{*(rM}FtPJ8DRlR@G}9dYyph>Z9JP2VFsL?zKCu zDyTtN_S)_8v47OBl|St_n|^2OMb&Tjf>smk3khDIvfC>O3%k1#=<|Tx>kS#<)kHgK zXjWC=*OG0dpELW%Wb8=5OE#92@hTEq^Lvj*RhcgoV`foZtZvN4!3NHxs#B^^M5P>9 z#6Ic;$!!E-EuFg8jjdt}>NO(^_{eLkgxg9tthcQM)l3P5vl+EEYKIxMb2NuOg3i=~ zV?W*`vu(6lFaE{aZ}mG>e_NJeexjyJ+@KC+DaXSt9#$Nhp^QVbbjhJtc(}~N9L@9U zjzjO$ilE#7r(*=ojSoOn4?$!Z7 z;WTsKk=&3Rg9MWTqKiRx`z2eXhyHnb=qBD$(nntT@ZiJ1n(dZyi&;I%$qF{UC!H*ZrjZjn!nbMU#8yrqi8@^Z z7ANbLa`yv3Ot{OtLrS@&0qJgTK!&?GAk)q21C%6d3}|Yc!W&3B(JFM-5bOg~yMk1$ zgJ%Pt9!joCs2OqPBd&bJm5;dciVGAn>4qeHT@mhpkduXk3~Aa0QVb>|>$in8Y$GW< z(s|e;cI4cq+w=y+aADG0O0+EJXju0z(*J;Z*ls316FrtPj(j(ijG#i)trbON%6yG8 z6E^EUU=Cs+W&~nJ&00h|hn*h>F@B!_d6EcHqPNxNG01h)Y!c)dKt8(wXIWW>;Zp|t)R=_w{k$&(nS<|sy#QGvY!8-p}wg9Yy*v>)mJ{n9+<-P@KEO7OK70uz15(}q diff --git a/src/maple_loader/build/classes/processing/app/helpers/ProcessUtils.class b/src/maple_loader/build/classes/processing/app/helpers/ProcessUtils.class deleted file mode 100644 index 27eca62622c61bc21ae557714ca4fa2d4c1eb22b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1399 zcmah}Sy$6Q7`@XLQbO2@A}XTd)|Mr1C|W=TH?$PBD#zs|q@zUJBqpiLyT8ImUwqXU z+>ZPJe~HJR;5jZgC15~3=A6vTcjucs_gj+BKRzr2ID)Gxx-g_-7$Yil91Mp;3J#}n zB#omgnlP&1n2Hu04~MZdPNZ?N6$Olk_Jo2-1*Zg>$1U3mCIyn&+)aVhv{R7+9YxEQ zrFv~ade@DGDv?alF^%d?!?Qv=0#m`F^CTYS6zNcsy3f#h~aIPY8?ejDTV~wVGj91iJrnHr%gOLdgON zcR^s=pJY>Yt6GsBIg`?U97foXP^UC~)^LgUtdH=SyBg)_de`w7c_jW%WRiq!<-jl> zlDv^E1^oi*xu>Rd1Iw{}1*d73ow{er^H!MRu6VjeLU|f8=vHt>!xW|!oYim+=QV7_ zHi6EKDP*Pw82{Y?4Hs}xp!c^!L>%QHWS!A)371*^>01}(XG)~Aor>e%qmUrTHOw;8oku}GFUSD$z#b&AmmXn=E66?~`-!w6+5R1hf&=0k Rugelj(J99_&vgQWzW|+SRY?E< diff --git a/src/maple_loader/dist/README.TXT b/src/maple_loader/dist/README.TXT deleted file mode 100644 index 255b89c68..000000000 --- a/src/maple_loader/dist/README.TXT +++ /dev/null @@ -1,32 +0,0 @@ -======================== -BUILD OUTPUT DESCRIPTION -======================== - -When you build an Java application project that has a main class, the IDE -automatically copies all of the JAR -files on the projects classpath to your projects dist/lib folder. The IDE -also adds each of the JAR files to the Class-Path element in the application -JAR files manifest file (MANIFEST.MF). - -To run the project from the command line, go to the dist folder and -type the following: - -java -jar "maple_loader.jar" - -To distribute this project, zip up the dist folder (including the lib folder) -and distribute the ZIP file. - -Notes: - -* If two JAR files on the project classpath have the same name, only the first -JAR file is copied to the lib folder. -* Only JAR files are copied to the lib folder. -If the classpath contains other types of files or folders, these files (folders) -are not copied. -* If a library on the projects classpath also has a Class-Path element -specified in the manifest,the content of the Class-Path element has to be on -the projects runtime path. -* To set a main class in a standard Java project, right-click the project node -in the Projects window and choose Properties. Then click Run and enter the -class name in the Main Class field. Alternatively, you can manually type the -class name in the manifest Main-Class element. diff --git a/src/maple_loader/dist/lib/jssc.jar b/src/maple_loader/dist/lib/jssc.jar deleted file mode 100644 index eb74f154a01c8c16712233cca36b65120ea47986..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152418 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 @v>QJza{i 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�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 diff --git a/src/maple_loader/dist/maple_loader.jar b/src/maple_loader/dist/maple_loader.jar deleted file mode 100644 index e1f9965c1ff0fe14384717ea4559c7f59e9a1ca6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32791 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 VEwG5^!#_X%TL6{zhrDw%{eMvMy}$qf diff --git a/src/maple_loader/jars/jssc.jar b/src/maple_loader/jars/jssc.jar deleted file mode 100644 index eb74f154a01c8c16712233cca36b65120ea47986..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152418 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 @v>QJza{i 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�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 diff --git a/src/maple_loader/manifest.mf b/src/maple_loader/manifest.mf deleted file mode 100644 index 328e8e5bc..000000000 --- a/src/maple_loader/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build - diff --git a/src/maple_loader/nbproject/build-impl.xml b/src/maple_loader/nbproject/build-impl.xml deleted file mode 100644 index a66f34964..000000000 --- a/src/maple_loader/nbproject/build-impl.xml +++ /dev/null @@ -1,1413 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set src.dir - Must set test.src.dir - Must set build.dir - Must set dist.dir - Must set build.classes.dir - Must set dist.javadoc.dir - Must set build.test.classes.dir - Must set build.test.results.dir - Must set build.classes.excludes - Must set dist.jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No tests executed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set JVM to use for profiling in profiler.info.jvm - Must set profiler agent JVM arguments in profiler.info.jvmargs.agent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - To run this application from the command line without Ant, try: - - java -jar "${dist.jar.resolved}" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - Must select one file in the IDE or set run.class - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set debug.class - - - - - Must select one file in the IDE or set debug.class - - - - - Must set fix.includes - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - Must select one file in the IDE or set profile.class - This target only works when run from inside the NetBeans IDE. - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - - - Must select some files in the IDE or set test.includes - - - - - Must select one file in the IDE or set run.class - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - Some tests failed; see details above. - - - - - - - - - Must select some files in the IDE or set test.includes - - - - Some tests failed; see details above. - - - - Must select some files in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - Some tests failed; see details above. - - - - - Must select one file in the IDE or set test.class - - - - Must select one file in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - - - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/maple_loader/nbproject/genfiles.properties b/src/maple_loader/nbproject/genfiles.properties deleted file mode 100644 index c13672132..000000000 --- a/src/maple_loader/nbproject/genfiles.properties +++ /dev/null @@ -1,8 +0,0 @@ -build.xml.data.CRC32=2e6a03ba -build.xml.script.CRC32=4676ee6b -build.xml.stylesheet.CRC32=8064a381@1.75.2.48 -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=2e6a03ba -nbproject/build-impl.xml.script.CRC32=392b3f79 -nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/src/maple_loader/nbproject/private/config.properties b/src/maple_loader/nbproject/private/config.properties deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/maple_loader/nbproject/private/private.properties b/src/maple_loader/nbproject/private/private.properties deleted file mode 100644 index e5c9f10c4..000000000 --- a/src/maple_loader/nbproject/private/private.properties +++ /dev/null @@ -1,6 +0,0 @@ -compile.on.save=true -do.depend=false -do.jar=true -javac.debug=true -javadoc.preview=true -user.properties.file=C:\\Users\\rclark\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties diff --git a/src/maple_loader/nbproject/private/private.xml b/src/maple_loader/nbproject/private/private.xml deleted file mode 100644 index a1bbd60c9..000000000 --- a/src/maple_loader/nbproject/private/private.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - file:/C:/Users/rclark/Desktop/maple-asp-master/installer/maple_loader/src/CliTemplate/CliMain.java - file:/C:/Users/rclark/Desktop/maple-asp-master/installer/maple_loader/src/CliTemplate/DFUUploader.java - - - diff --git a/src/maple_loader/nbproject/project.properties b/src/maple_loader/nbproject/project.properties deleted file mode 100644 index 7f48d719f..000000000 --- a/src/maple_loader/nbproject/project.properties +++ /dev/null @@ -1,79 +0,0 @@ -annotation.processing.enabled=true -annotation.processing.enabled.in.editor=false -annotation.processing.processors.list= -annotation.processing.run.all.processors=true -annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output -application.title=maple_loader -application.vendor=bob -build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form -# This directory is removed when the project is cleaned: -build.dir=build -build.generated.dir=${build.dir}/generated -build.generated.sources.dir=${build.dir}/generated-sources -# Only compile against the classpath explicitly listed here: -build.sysclasspath=ignore -build.test.classes.dir=${build.dir}/test/classes -build.test.results.dir=${build.dir}/test/results -# Uncomment to specify the preferred debugger connection transport: -#debug.transport=dt_socket -debug.classpath=\ - ${run.classpath} -debug.test.classpath=\ - ${run.test.classpath} -# Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes= -# This directory is removed when the project is cleaned: -dist.dir=dist -dist.jar=${dist.dir}/maple_loader.jar -dist.javadoc.dir=${dist.dir}/javadoc -endorsed.classpath= -excludes= -file.reference.jssc.jar=dist/lib/jssc.jar -file.reference.jssc.jar-1=jars/jssc.jar -includes=** -jar.compress=false -javac.classpath=\ - ${file.reference.jssc.jar}:\ - ${file.reference.jssc.jar-1} -# Space-separated list of extra javac options -javac.compilerargs= -javac.deprecation=false -javac.processorpath=\ - ${javac.classpath} -javac.source=1.7 -javac.target=1.7 -javac.test.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -javac.test.processorpath=\ - ${javac.test.classpath} -javadoc.additionalparam= -javadoc.author=false -javadoc.encoding=${source.encoding} -javadoc.noindex=false -javadoc.nonavbar=false -javadoc.notree=false -javadoc.private=false -javadoc.splitindex=true -javadoc.use=true -javadoc.version=false -javadoc.windowtitle= -main.class=CliTemplate.CliMain -manifest.file=manifest.mf -meta.inf.dir=${src.dir}/META-INF -mkdist.disabled=false -platform.active=default_platform -run.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -# Space-separated list of JVM arguments used when running the project. -# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. -# To set system properties for unit tests define test-sys-prop.name=value: -run.jvmargs= -run.test.classpath=\ - ${javac.test.classpath}:\ - ${build.test.classes.dir} -source.encoding=UTF-8 -src.dir=src -test.src.dir=test diff --git a/src/maple_loader/nbproject/project.xml b/src/maple_loader/nbproject/project.xml deleted file mode 100644 index 92218a925..000000000 --- a/src/maple_loader/nbproject/project.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - org.netbeans.modules.java.j2seproject - - - maple_loader - - - - - - - - - diff --git a/src/maple_loader/src/CliTemplate/CliMain.java b/src/maple_loader/src/CliTemplate/CliMain.java deleted file mode 100644 index c7dc9f098..000000000 --- a/src/maple_loader/src/CliTemplate/CliMain.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package CliTemplate; - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import processing.app.Preferences; - -//import processing.app.I18n; -import processing.app.helpers.ProcessUtils; - -/** - * - * @author cousinr - */ -public class CliMain { - - - /** - * @param args the command line arguments - */ - public static void main(String[] args) { - - String comPort = args[0]; // - String altIf = args[1]; // - String usbID = args[2]; // "1EAF:0003"; - String binFile = args[3]; // bin file - - System.out.println("maple_loader v0.1"); - - Preferences.set ("serial.port",comPort); - Preferences.set ("serial.parity","N"); - Preferences.setInteger ("serial.databits", 8); - Preferences.setInteger ("serial.debug_rate",9600); - Preferences.setInteger ("serial.stopbits",1); - - Preferences.setInteger ("programDelay",1200); - - Preferences.set ("upload.usbID", usbID); - Preferences.set ("upload.altID", altIf); - Preferences.setBoolean ("upload.auto_reset", true); - Preferences.setBoolean ("upload.verbose", false); - - // - DFUUploader dfuUploader = new DFUUploader(); - try { - //dfuUploader.uploadViaDFU(binFile); - dfuUploader.uploadViaDFU(binFile); - } catch (Exception e) - { - System.err.print (MessageFormat.format("an error occurred! {0}\n", e.getMessage())); - } - } -} diff --git a/src/maple_loader/src/CliTemplate/DFUUploader.java b/src/maple_loader/src/CliTemplate/DFUUploader.java deleted file mode 100644 index 3dee0b4b7..000000000 --- a/src/maple_loader/src/CliTemplate/DFUUploader.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - DFUUploader - uploader implementation using DFU - - Copyright (c) 2010 - Andrew Meyer - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -package CliTemplate; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import processing.app.Preferences; -import processing.app.Serial; -import processing.app.debug.MessageConsumer; -import processing.app.debug.MessageSiphon; -import processing.app.debug.RunnerException; - -/** - * - * @author bob - */ -public class DFUUploader implements MessageConsumer { - - boolean firstErrorFound; - boolean secondErrorFound; - // part of the PdeMessageConsumer interface - boolean notFoundError; - boolean verbose; - RunnerException exception; - - static final String SUPER_BADNESS = - "Compiler error!"; - - public boolean uploadUsingPreferences(String binPath, boolean verbose) - throws RunnerException { - - this.verbose = verbose; - - return uploadViaDFU(binPath); - } - - // works with old and new versions of dfu-util - private boolean found_device (String dfuData, String usbID) - { - return dfuData.contains(("Found DFU: [0x"+usbID.substring(0,4)).toUpperCase()) || - dfuData.contains(("Found DFU: ["+usbID.substring(0,4)).toUpperCase()); - } - - public boolean uploadViaDFU (String binPath) - throws RunnerException { - - this.verbose = Preferences.getBoolean ("upload.verbose"); - - /* todo, check for size overruns! */ - String fileType="bin"; - - if (fileType.equals("bin")) { - String usbID = Preferences.get("upload.usbID"); - if (usbID == null) { - /* fall back on default */ - /* this isnt great because is default Avrdude or dfu-util? */ - usbID = Preferences.get("upload.usbID"); - } - - /* if auto-reset, then emit the reset pulse on dtr/rts */ - if (Preferences.get("upload.auto_reset") != null) { - if (Preferences.get("upload.auto_reset").toLowerCase().equals("true")) { - System.out.println("Resetting to bootloader via DTR pulse"); - emitResetPulse(); - } - } else { - System.out.println("Resetting to bootloader via DTR pulse"); - emitResetPulse(); - } - - String dfuList = new String(); - List commandCheck = new ArrayList(); - commandCheck.add("dfu-util"); - commandCheck.add("-l"); - long startChecking = System.currentTimeMillis(); - System.out.println("Searching for DFU device [" + usbID + "]..."); - do { - try { - Thread.sleep(100); - } catch (InterruptedException e) {} - dfuList = executeCheckCommand(commandCheck); - //System.out.println(dfuList); - } - while ( !found_device (dfuList.toUpperCase(), usbID) && (System.currentTimeMillis() - startChecking < 7000)); - - if ( !found_device (dfuList.toUpperCase(), usbID) ) - { - System.out.println(dfuList); - System.err.println("Couldn't find the DFU device: [" + usbID + "]"); - return false; - } - System.out.println("Found it!"); - - /* todo, add handle to let user choose altIf at upload time! */ - String altIf = Preferences.get("upload.altID"); - - List commandDownloader = new ArrayList(); - commandDownloader.add("dfu-util"); - commandDownloader.add("-a "+altIf); - commandDownloader.add("-R"); - commandDownloader.add("-d "+usbID); - commandDownloader.add("-D"+ binPath); //"./thisbin.bin"); - - return executeUploadCommand(commandDownloader); - } - - System.err.println("Only .bin files are supported at this time"); - return false; - } - - /* we need to ensure both RTS and DTR are low to start, - then pulse DTR on its own. This is the reset signal - maple responds to - */ - private void emitResetPulse() throws RunnerException { - - /* wait a while for the device to reboot */ - int programDelay = Preferences.getInteger("programDelay"); - - try { - Serial serialPort = new Serial(); - - // try to toggle DTR/RTS (old scheme) - serialPort.setRTS(false); - serialPort.setDTR(false); - serialPort.setDTR(true); - try { - Thread.sleep(50); - } catch (InterruptedException e) {} - serialPort.setDTR(false); - - // try magic number - serialPort.setRTS(true); - serialPort.setDTR(true); - try { - Thread.sleep(50); - } catch (InterruptedException e) {} - serialPort.setDTR(false); - try { - Thread.sleep(50); - } catch (InterruptedException e) {} - serialPort.write("1EAF"); - try { - Thread.sleep(50); - } catch (InterruptedException e) {} - serialPort.dispose(); - - } catch(Exception e) { - System.err.println("Reset via USB Serial Failed! Did you select the right serial port?\nAssuming the board is in perpetual bootloader mode and continuing to attempt dfu programming...\n"); - } - } - - protected String executeCheckCommand(Collection commandDownloader) - throws RunnerException - { - firstErrorFound = false; // haven't found any errors yet - secondErrorFound = false; - notFoundError = false; - int result=0; // pre-initialized to quiet a bogus warning from jikes - - String userdir = System.getProperty("user.dir") + File.separator; - String returnStr = new String(); - - try { - String[] commandArray = new String[commandDownloader.size()]; - commandDownloader.toArray(commandArray); - - String armBasePath; - - //armBasePath = new String(Base.getHardwarePath() + "/tools/arm/bin/"); - armBasePath = ""; - - commandArray[0] = armBasePath + commandArray[0]; - - if (verbose || Preferences.getBoolean("upload.verbose")) { - for(int i = 0; i < commandArray.length; i++) { - System.out.print(commandArray[i] + " "); - } - System.out.println(); - } - - Process process = Runtime.getRuntime().exec(commandArray); - BufferedReader stdInput = new BufferedReader(new - InputStreamReader(process.getInputStream())); - BufferedReader stdError = new BufferedReader(new - InputStreamReader(process.getErrorStream())); - - // wait for the process to finish. if interrupted - // before waitFor returns, continue waiting - // - boolean busy = true; - while (busy) { - try { - result = process.waitFor(); - busy = false; - } catch (InterruptedException intExc) { - } - } - - String s; - while ((s = stdInput.readLine()) != null) { - returnStr += s + "\n"; - } - - process.destroy(); - - if(exception!=null) { - exception.hideStackTrace(); - throw exception; - } - if(result!=0) return "Error!"; - } catch (Exception e) { - e.printStackTrace(); - } - //System.out.println("result2 is "+result); - // if the result isn't a known, expected value it means that something - // is fairly wrong, one possibility is that jikes has crashed. - // - if (exception != null) throw exception; - - if ((result != 0) && (result != 1 )) { - exception = new RunnerException(SUPER_BADNESS); - } - - return returnStr; // ? true : false; - - } - - // Need to overload this from Uploader to use the system-wide dfu-util - protected boolean executeUploadCommand(Collection commandDownloader) - throws RunnerException - { - firstErrorFound = false; // haven't found any errors yet - secondErrorFound = false; - notFoundError = false; - int result=0; // pre-initialized to quiet a bogus warning from jikes - - String userdir = System.getProperty("user.dir") + File.separator; - - try { - String[] commandArray = new String[commandDownloader.size()]; - commandDownloader.toArray(commandArray); - - String armBasePath; - - //armBasePath = new String(Base.getHardwarePath() + "/tools/arm/bin/"); - armBasePath = ""; - - commandArray[0] = armBasePath + commandArray[0]; - - if (verbose || Preferences.getBoolean("upload.verbose")) { - for(int i = 0; i < commandArray.length; i++) { - System.out.print(commandArray[i] + " "); - } - System.out.println(); - } - - Process process = Runtime.getRuntime().exec(commandArray); - new MessageSiphon(process.getInputStream(), this); - new MessageSiphon(process.getErrorStream(), this); - - // wait for the process to finish. if interrupted - // before waitFor returns, continue waiting - // - boolean compiling = true; - while (compiling) { - try { - result = process.waitFor(); - compiling = false; - } catch (InterruptedException intExc) { - } - } - if(exception!=null) { - exception.hideStackTrace(); - throw exception; - } - if(result!=0) - return false; - } catch (Exception e) { - e.printStackTrace(); - } - //System.out.println("result2 is "+result); - // if the result isn't a known, expected value it means that something - // is fairly wrong, one possibility is that jikes has crashed. - // - if (exception != null) throw exception; - - if ((result != 0) && (result != 1 )) { - exception = new RunnerException(SUPER_BADNESS); - //editor.error(exception); - //PdeBase.openURL(BUGS_URL); - //throw new PdeException(SUPER_BADNESS); - } - - return (result == 0); // ? true : false; - - } - - // deal with messages from dfu-util... - public void message(String s) { - - if(s.indexOf("dfu-util - (C) ") != -1) { return; } - if(s.indexOf("This program is Free Software and has ABSOLUTELY NO WARRANTY") != -1) { return; } - - if(s.indexOf("No DFU capable USB device found") != -1) { - System.err.print(s); - exception = new RunnerException("Problem uploading via dfu-util: No Maple found"); - return; - } - - if(s.indexOf("Operation not perimitted") != -1) { - System.err.print(s); - exception = new RunnerException("Problem uploading via dfu-util: Insufficient privilages"); - return; - } - - // else just print everything... - System.out.print(s); - } - -} diff --git a/src/maple_loader/src/CliTemplate/ExecCommand.java b/src/maple_loader/src/CliTemplate/ExecCommand.java deleted file mode 100644 index 3d6c106b7..000000000 --- a/src/maple_loader/src/CliTemplate/ExecCommand.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package CliTemplate; - -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; - -import processing.app.debug.MessageConsumer; -import processing.app.debug.MessageSiphon; -import processing.app.debug.RunnerException; -import processing.app.helpers.ProcessUtils; - -/** - * - * @author cousinr - */ -public class ExecCommand implements MessageConsumer { - - private boolean verbose = true; - private boolean firstErrorFound; - private boolean secondErrorFound; - private RunnerException exception; - - /** - * Either succeeds or throws a RunnerException fit for public consumption. - * - * @param command - * @throws RunnerException - */ - public void execAsynchronously(String[] command) throws RunnerException { - - // eliminate any empty array entries - List stringList = new ArrayList<>(); - for (String string : command) { - string = string.trim(); - if (string.length() != 0) - stringList.add(string); - } - command = stringList.toArray(new String[stringList.size()]); - if (command.length == 0) - return; - int result = 0; - - if (verbose) { - for (String c : command) - System.out.print(c + " "); - System.out.println(); - } - - firstErrorFound = false; // haven't found any errors yet - secondErrorFound = false; - - Process process; - try { - process = ProcessUtils.exec(command); - } catch (IOException e) { - RunnerException re = new RunnerException(e.getMessage()); - re.hideStackTrace(); - throw re; - } - - MessageSiphon in = new MessageSiphon(process.getInputStream(), this); - MessageSiphon err = new MessageSiphon(process.getErrorStream(), this); - - // wait for the process to finish. if interrupted - // before waitFor returns, continue waiting - boolean compiling = true; - while (compiling) { - try { - in.join(); - err.join(); - result = process.waitFor(); - //System.out.println("result is " + result); - compiling = false; - } catch (InterruptedException ignored) { } - } - - // an error was queued up by message(), barf this back to compile(), - // which will barf it back to Editor. if you're having trouble - // discerning the imagery, consider how cows regurgitate their food - // to digest it, and the fact that they have five stomaches. - // - //System.out.println("throwing up " + exception); - if (exception != null) - throw exception; - - if (result > 1) { - // a failure in the tool (e.g. unable to locate a sub-executable) - System.err.println(MessageFormat.format("{0} returned {1}", command[0], result)); - } - - if (result != 0) { - RunnerException re = new RunnerException(MessageFormat.format("exit code: {0}", result)); - re.hideStackTrace(); - throw re; - } - } - - /** - * Part of the MessageConsumer interface, this is called - * whenever a piece (usually a line) of error message is spewed - * out from the compiler. The errors are parsed for their contents - * and line number, which is then reported back to Editor. - * @param s - */ - @Override - public void message(String s) { - int i; - - - System.err.print(s); - } - -} diff --git a/src/maple_loader/src/processing/app/Base.java b/src/maple_loader/src/processing/app/Base.java deleted file mode 100644 index c3a174dcb..000000000 --- a/src/maple_loader/src/processing/app/Base.java +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-10 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 - as published by the Free Software Foundation. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app; - - -/** - * The base class for the main processing application. - * Primary role of this class is for platform identification and - * general interaction with the system (launching URLs, loading - * files and images, etc) that comes from that. - */ -public class Base { - - /** - * returns true if running on windows. - */ - static public boolean isWindows() { - //return PApplet.platform == PConstants.WINDOWS; - return System.getProperty("os.name").indexOf("Windows") != -1; - } - - - /** - * true if running on linux. - */ - static public boolean isLinux() { - //return PApplet.platform == PConstants.LINUX; - return System.getProperty("os.name").indexOf("Linux") != -1; - } - - - -} diff --git a/src/maple_loader/src/processing/app/Preferences.java b/src/maple_loader/src/processing/app/Preferences.java deleted file mode 100644 index 6368e38af..000000000 --- a/src/maple_loader/src/processing/app/Preferences.java +++ /dev/null @@ -1,157 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-09 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app; - -import java.io.*; -import java.util.*; - - -/** - * Storage class for user preferences and environment settings. - *

- * This class no longer uses the Properties class, since - * properties files are iso8859-1, which is highly likely to - * be a problem when trying to save sketch folders and locations. - *

- * The GUI portion in here is really ugly, as it uses exact layout. This was - * done in frustration one evening (and pre-Swing), but that's long since past, - * and it should all be moved to a proper swing layout like BoxLayout. - *

- * This is very poorly put together, that the preferences panel and the actual - * preferences i/o is part of the same code. But there hasn't yet been a - * compelling reason to bother with the separation aside from concern about - * being lectured by strangers who feel that it doesn't look like what they - * learned in CS class. - *

- * Would also be possible to change this to use the Java Preferences API. - * Some useful articles - * here and - * here. - * However, haven't implemented this yet for lack of time, but more - * importantly, because it would entail writing to the registry (on Windows), - * or an obscure file location (on Mac OS X) and make it far more difficult to - * find the preferences to tweak them by hand (no! stay out of regedit!) - * or to reset the preferences by simply deleting the preferences.txt file. - */ -public class Preferences { - - // what to call the feller - - static final String PREFS_FILE = "preferences.txt"; - - - // prompt text stuff - - static final String PROMPT_YES = "Yes"; - static final String PROMPT_NO = "No"; - static final String PROMPT_CANCEL = "Cancel"; - static final String PROMPT_OK = "OK"; - static final String PROMPT_BROWSE = "Browse"; - - /** - * Standardized width for buttons. Mac OS X 10.3 wants 70 as its default, - * Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper. - */ - static public int BUTTON_WIDTH = 80; - - /** - * Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29, - * presumably because it now includes the blue border, where it didn't - * in Java 1.3. Windows XP only wants 23 (not sure what default Linux - * would be). Because of the disparity, on Mac OS X, it will be set - * inside a static block. - */ - static public int BUTTON_HEIGHT = 24; - - // value for the size bars, buttons, etc - - static final int GRID_SIZE = 33; - - - // indents and spacing standards. these probably need to be modified - // per platform as well, since macosx is so huge, windows is smaller, - // and linux is all over the map - - static final int GUI_BIG = 13; - static final int GUI_BETWEEN = 10; - static final int GUI_SMALL = 6; - - - - // data model - - static Hashtable table = new Hashtable();; - static File preferencesFile; - - - static protected void init(String commandLinePrefs) { - - - } - - - public Preferences() { - - } - - // ................................................................. - - // ................................................................. - - // ................................................................. - - // ................................................................. - - - - static public String get(String attribute) { - return (String) table.get(attribute); - } - - static public void set(String attribute, String value) { - table.put(attribute, value); - } - - - static public boolean getBoolean(String attribute) { - String value = get(attribute); - return (new Boolean(value)).booleanValue(); - } - - - static public void setBoolean(String attribute, boolean value) { - set(attribute, value ? "true" : "false"); - } - - - static public int getInteger(String attribute) { - return Integer.parseInt(get(attribute)); - } - - - static public void setInteger(String key, int value) { - set(key, String.valueOf(value)); - } - -} diff --git a/src/maple_loader/src/processing/app/Serial.java b/src/maple_loader/src/processing/app/Serial.java deleted file mode 100644 index 04566a738..000000000 --- a/src/maple_loader/src/processing/app/Serial.java +++ /dev/null @@ -1,527 +0,0 @@ -/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - PSerial - class for serial port goodness - Part of the Processing project - http://processing.org - - Copyright (c) 2004 Ben Fry & Casey Reas - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General - Public License along with this library; if not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, - Boston, MA 02111-1307 USA -*/ - -package processing.app; -//import processing.core.*; - - -import java.io.*; -import java.text.MessageFormat; -import java.util.*; -import jssc.SerialPort; -import jssc.SerialPortEvent; -import jssc.SerialPortEventListener; -import jssc.SerialPortException; -import jssc.SerialPortList; -import processing.app.debug.MessageConsumer; - - -public class Serial implements SerialPortEventListener { - - //PApplet parent; - - // properties can be passed in for default values - // otherwise defaults to 9600 N81 - - // these could be made static, which might be a solution - // for the classloading problem.. because if code ran again, - // the static class would have an object that could be closed - - SerialPort port; - - int rate; - int parity; - int databits; - int stopbits; - boolean monitor = false; - - // read buffer and streams - - InputStream input; - OutputStream output; - - byte buffer[] = new byte[32768]; - int bufferIndex; - int bufferLast; - - MessageConsumer consumer; - - public Serial(boolean monitor) throws SerialException { - this(Preferences.get("serial.port"), - Preferences.getInteger("serial.debug_rate"), - Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), - new Float(Preferences.get("serial.stopbits")).floatValue()); - this.monitor = monitor; - } - - public Serial() throws SerialException { - this(Preferences.get("serial.port"), - Preferences.getInteger("serial.debug_rate"), - Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), - new Float(Preferences.get("serial.stopbits")).floatValue()); - } - - public Serial(int irate) throws SerialException { - this(Preferences.get("serial.port"), irate, - Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), - new Float(Preferences.get("serial.stopbits")).floatValue()); - } - - public Serial(String iname, int irate) throws SerialException { - this(iname, irate, Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), - new Float(Preferences.get("serial.stopbits")).floatValue()); - } - - public Serial(String iname) throws SerialException { - this(iname, Preferences.getInteger("serial.debug_rate"), - Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), - new Float(Preferences.get("serial.stopbits")).floatValue()); - } - - public Serial(String iname, int irate, - char iparity, int idatabits, float istopbits) - throws SerialException { - //if (port != null) port.close(); - //this.parent = parent; - //parent.attach(this); - - this.rate = irate; - - parity = SerialPort.PARITY_NONE; - if (iparity == 'E') parity = SerialPort.PARITY_EVEN; - if (iparity == 'O') parity = SerialPort.PARITY_ODD; - - this.databits = idatabits; - - stopbits = SerialPort.STOPBITS_1; - if (istopbits == 1.5f) stopbits = SerialPort.STOPBITS_1_5; - if (istopbits == 2) stopbits = SerialPort.STOPBITS_2; - - try { - port = new SerialPort(iname); - port.openPort(); - port.setParams(rate, databits, stopbits, parity, true, true); - port.addEventListener(this); - } catch (Exception e) { - throw new SerialException(MessageFormat.format("Error opening serial port ''{0}''.", iname), e); - } - - if (port == null) { - throw new SerialException("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?"); - } - } - - - public void setup() { - //parent.registerCall(this, DISPOSE); - } - - public void dispose() throws IOException { - if (port != null) { - try { - if (port.isOpened()) { - port.closePort(); // close the port - } - } catch (SerialPortException e) { - throw new IOException(e); - } finally { - port = null; - } - } - } - - public void addListener(MessageConsumer consumer) { - this.consumer = consumer; - } - - public synchronized void serialEvent(SerialPortEvent serialEvent) { - if (serialEvent.isRXCHAR()) { - try { - byte[] buf = port.readBytes(serialEvent.getEventValue()); - if (buf.length > 0) { - if (bufferLast == buffer.length) { - byte temp[] = new byte[bufferLast << 1]; - System.arraycopy(buffer, 0, temp, 0, bufferLast); - buffer = temp; - } - if (monitor) { - System.out.print(new String(buf)); - } - if (this.consumer != null) { - this.consumer.message(new String(buf)); - } - } - } catch (SerialPortException e) { - errorMessage("serialEvent", e); - } - } - } - - - /** - * Returns the number of bytes that have been read from serial - * and are waiting to be dealt with by the user. - */ - public synchronized int available() { - return (bufferLast - bufferIndex); - } - - - /** - * Ignore all the bytes read so far and empty the buffer. - */ - public synchronized void clear() { - bufferLast = 0; - bufferIndex = 0; - } - - - /** - * Returns a number between 0 and 255 for the next byte that's - * waiting in the buffer. - * Returns -1 if there was no byte (although the user should - * first check available() to see if things are ready to avoid this) - */ - public synchronized int read() { - if (bufferIndex == bufferLast) return -1; - - int outgoing = buffer[bufferIndex++] & 0xff; - if (bufferIndex == bufferLast) { // rewind - bufferIndex = 0; - bufferLast = 0; - } - return outgoing; - } - - - /** - * Returns the next byte in the buffer as a char. - * Returns -1, or 0xffff, if nothing is there. - */ - public synchronized char readChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) read(); - } - - - /** - * Return a byte array of anything that's in the serial buffer. - * Not particularly memory/speed efficient, because it creates - * a byte array on each read, but it's easier to use than - * readBytes(byte b[]) (see below). - */ - public synchronized byte[] readBytes() { - if (bufferIndex == bufferLast) return null; - - int length = bufferLast - bufferIndex; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex = 0; // rewind - bufferLast = 0; - return outgoing; - } - - - /** - * Grab whatever is in the serial buffer, and stuff it into a - * byte buffer passed in by the user. This is more memory/time - * efficient than readBytes() returning a byte[] array. - *

- * Returns an int for how many bytes were read. If more bytes - * are available than can fit into the byte array, only those - * that will fit are read. - */ - public synchronized int readBytes(byte outgoing[]) { - if (bufferIndex == bufferLast) return 0; - - int length = bufferLast - bufferIndex; - if (length > outgoing.length) length = outgoing.length; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return length; - } - - - /** - * Reads from the serial port into a buffer of bytes up to and - * including a particular character. If the character isn't in - * the serial buffer, then 'null' is returned. - */ - public synchronized byte[] readBytesUntil(int interesting) { - if (bufferIndex == bufferLast) return null; - byte what = (byte)interesting; - - int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; - break; - } - } - if (found == -1) return null; - - int length = found - bufferIndex + 1; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex = 0; // rewind - bufferLast = 0; - return outgoing; - } - - - /** - * Reads from the serial port into a buffer of bytes until a - * particular character. If the character isn't in the serial - * buffer, then 'null' is returned. - *

- * If outgoing[] is not big enough, then -1 is returned, - * and an error message is printed on the console. - * If nothing is in the buffer, zero is returned. - * If 'interesting' byte is not in the buffer, then 0 is returned. - */ - public synchronized int readBytesUntil(int interesting, byte outgoing[]) { - if (bufferIndex == bufferLast) return 0; - byte what = (byte)interesting; - - int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; - break; - } - } - if (found == -1) return 0; - - int length = found - bufferIndex + 1; - if (length > outgoing.length) { - System.err.println("readBytesUntil() byte buffer is" + - " too small for the " + length + - " bytes up to and including char " + interesting); - return -1; - } - //byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return length; - } - - - /** - * Return whatever has been read from the serial port so far - * as a String. It assumes that the incoming characters are ASCII. - *

- * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - */ - public synchronized String readString() { - if (bufferIndex == bufferLast) return null; - return new String(readBytes()); - } - - - /** - * Combination of readBytesUntil and readString. See caveats in - * each function. Returns null if it still hasn't found what - * you're looking for. - *

- * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - */ - public synchronized String readStringUntil(int interesting) { - byte b[] = readBytesUntil(interesting); - if (b == null) return null; - return new String(b); - } - - - /** - * This will handle both ints, bytes and chars transparently. - */ - public void write(int what) { // will also cover char - try { - port.writeInt(what & 0xff); - } catch (SerialPortException e) { - errorMessage("write", e); - } - } - - - public void write(byte bytes[]) { - try { - port.writeBytes(bytes); - } catch (SerialPortException e) { - errorMessage("write", e); - } - } - - - /** - * Write a String to the output. Note that this doesn't account - * for Unicode (two bytes per char), nor will it send UTF8 - * characters.. It assumes that you mean to send a byte buffer - * (most often the case for networking and serial i/o) and - * will only use the bottom 8 bits of each char in the string. - * (Meaning that internally it uses String.getBytes) - *

- * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - */ - public void write(String what) { - write(what.getBytes()); - } - - public void setDTR(boolean state) { - try { - port.setDTR(state); - } catch (SerialPortException e) { - errorMessage("setDTR", e); - } - } - - public void setRTS(boolean state) { - try { - port.setRTS(state); - } catch (SerialPortException e) { - errorMessage("setRTS", e); - } - } - - static public List list() { - return Arrays.asList(SerialPortList.getPortNames()); - } - - - /** - * General error reporting, all corraled here just in case - * I think of something slightly more intelligent to do. - */ - static public void errorMessage(String where, Throwable e) { - System.err.println("Error inside Serial." + where + "()"); - e.printStackTrace(); - } -} - - - /* - class SerialMenuListener implements ItemListener { - //public SerialMenuListener() { } - - public void itemStateChanged(ItemEvent e) { - int count = serialMenu.getItemCount(); - for (int i = 0; i < count; i++) { - ((CheckboxMenuItem)serialMenu.getItem(i)).setState(false); - } - CheckboxMenuItem item = (CheckboxMenuItem)e.getSource(); - item.setState(true); - String name = item.getLabel(); - //System.out.println(item.getLabel()); - PdeBase.properties.put("serial.port", name); - //System.out.println("set to " + get("serial.port")); - } - } - */ - - - /* - protected Vector buildPortList() { - // get list of names for serial ports - // have the default port checked (if present) - Vector list = new Vector(); - - //SerialMenuListener listener = new SerialMenuListener(); - boolean problem = false; - - // if this is failing, it may be because - // lib/javax.comm.properties is missing. - // java is weird about how it searches for java.comm.properties - // so it tends to be very fragile. i.e. quotes in the CLASSPATH - // environment variable will hose things. - try { - //System.out.println("building port list"); - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); - //System.out.println(portId); - - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - //if (portId.getName().equals(port)) { - String name = portId.getName(); - //CheckboxMenuItem mi = - //new CheckboxMenuItem(name, name.equals(defaultName)); - - //mi.addItemListener(listener); - //serialMenu.add(mi); - list.addElement(name); - } - } - } catch (UnsatisfiedLinkError e) { - e.printStackTrace(); - problem = true; - - } catch (Exception e) { - System.out.println("exception building serial menu"); - e.printStackTrace(); - } - - //if (serialMenu.getItemCount() == 0) { - //System.out.println("dimming serial menu"); - //serialMenu.setEnabled(false); - //} - - // only warn them if this is the first time - if (problem && PdeBase.firstTime) { - JOptionPane.showMessageDialog(this, //frame, - "Serial port support not installed.\n" + - "Check the readme for instructions\n" + - "if you need to use the serial port. ", - "Serial Port Warning", - JOptionPane.WARNING_MESSAGE); - } - return list; - } - */ - - - diff --git a/src/maple_loader/src/processing/app/SerialException.java b/src/maple_loader/src/processing/app/SerialException.java deleted file mode 100644 index 525c24078..000000000 --- a/src/maple_loader/src/processing/app/SerialException.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Copyright (c) 2007 David A. Mellis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app; - -public class SerialException extends Exception { - public SerialException() { - super(); - } - - public SerialException(String message) { - super(message); - } - - public SerialException(String message, Throwable cause) { - super(message, cause); - } - - public SerialException(Throwable cause) { - super(cause); - } -} diff --git a/src/maple_loader/src/processing/app/debug/MessageConsumer.java b/src/maple_loader/src/processing/app/debug/MessageConsumer.java deleted file mode 100644 index 5e2042943..000000000 --- a/src/maple_loader/src/processing/app/debug/MessageConsumer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-06 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app.debug; - - -/** - * Interface for dealing with parser/compiler output. - *

- * Different instances of MessageStream need to do different things with - * messages. In particular, a stream instance used for parsing output from - * the compiler compiler has to interpret its messages differently than one - * parsing output from the runtime. - *

- * Classes which consume messages and do something with them - * should implement this interface. - */ -public interface MessageConsumer { - - public void message(String s); - -} diff --git a/src/maple_loader/src/processing/app/debug/MessageSiphon.java b/src/maple_loader/src/processing/app/debug/MessageSiphon.java deleted file mode 100644 index 26901c3f4..000000000 --- a/src/maple_loader/src/processing/app/debug/MessageSiphon.java +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-06 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app.debug; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.SocketException; - -/** - * Slurps up messages from compiler. - */ -public class MessageSiphon implements Runnable { - - private final BufferedReader streamReader; - private final MessageConsumer consumer; - - private Thread thread; - private boolean canRun; - - public MessageSiphon(InputStream stream, MessageConsumer consumer) { - this.streamReader = new BufferedReader(new InputStreamReader(stream)); - this.consumer = consumer; - this.canRun = true; - - thread = new Thread(this); - // don't set priority too low, otherwise exceptions won't - // bubble up in time (i.e. compile errors have a weird delay) - //thread.setPriority(Thread.MIN_PRIORITY); - thread.setPriority(Thread.MAX_PRIORITY - 1); - thread.start(); - } - - - public void run() { - try { - // process data until we hit EOF; this will happily block - // (effectively sleeping the thread) until new data comes in. - // when the program is finally done, null will come through. - // - String currentLine; - while (canRun && (currentLine = streamReader.readLine()) != null) { - // \n is added again because readLine() strips it out - //EditorConsole.systemOut.println("messaging in"); - consumer.message(currentLine + "\n"); - //EditorConsole.systemOut.println("messaging out"); - } - //EditorConsole.systemOut.println("messaging thread done"); - } catch (NullPointerException npe) { - // Fairly common exception during shutdown - } catch (SocketException e) { - // socket has been close while we were wainting for data. nothing to see here, move along - } catch (Exception e) { - // On Linux and sometimes on Mac OS X, a "bad file descriptor" - // message comes up when closing an applet that's run externally. - // That message just gets supressed here.. - String mess = e.getMessage(); - if ((mess != null) && - (mess.indexOf("Bad file descriptor") != -1)) { - //if (e.getMessage().indexOf("Bad file descriptor") == -1) { - //System.err.println("MessageSiphon err " + e); - //e.printStackTrace(); - } else { - e.printStackTrace(); - } - } finally { - thread = null; - } - } - - // Wait until the MessageSiphon thread is complete. - public void join() throws java.lang.InterruptedException { - // Grab a temp copy in case another thread nulls the "thread" - // member variable - Thread t = thread; - if (t != null) t.join(); - } - - public void stop() { - this.canRun = false; - } - -} diff --git a/src/maple_loader/src/processing/app/debug/RunnerException.java b/src/maple_loader/src/processing/app/debug/RunnerException.java deleted file mode 100644 index 0a67d1e80..000000000 --- a/src/maple_loader/src/processing/app/debug/RunnerException.java +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-08 Ben Fry and Casey Reas - Copyright (c) 2001-04 Massachusetts Institute of Technology - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package processing.app.debug; - - -/** - * An exception with a line number attached that occurs - * during either compile time or run time. - */ -@SuppressWarnings("serial") -public class RunnerException extends Exception { - protected String message; - protected int codeIndex; - protected int codeLine; - protected int codeColumn; - protected boolean showStackTrace; - - - public RunnerException(String message) { - this(message, true); - } - - public RunnerException(String message, boolean showStackTrace) { - this(message, -1, -1, -1, showStackTrace); - } - - public RunnerException(String message, int file, int line) { - this(message, file, line, -1, true); - } - - - public RunnerException(String message, int file, int line, int column) { - this(message, file, line, column, true); - } - - - public RunnerException(String message, int file, int line, int column, - boolean showStackTrace) { - this.message = message; - this.codeIndex = file; - this.codeLine = line; - this.codeColumn = column; - this.showStackTrace = showStackTrace; - } - - - public RunnerException(Exception e) { - super(e); - this.showStackTrace = true; - } - - /** - * Override getMessage() in Throwable, so that I can set - * the message text outside the constructor. - */ - public String getMessage() { - return message; - } - - - public void setMessage(String message) { - this.message = message; - } - - - public int getCodeIndex() { - return codeIndex; - } - - - public void setCodeIndex(int index) { - codeIndex = index; - } - - - public boolean hasCodeIndex() { - return codeIndex != -1; - } - - - public int getCodeLine() { - return codeLine; - } - - - public void setCodeLine(int line) { - this.codeLine = line; - } - - - public boolean hasCodeLine() { - return codeLine != -1; - } - - - public void setCodeColumn(int column) { - this.codeColumn = column; - } - - - public int getCodeColumn() { - return codeColumn; - } - - - public void showStackTrace() { - showStackTrace = true; - } - - - public void hideStackTrace() { - showStackTrace = false; - } - - - /** - * Nix the java.lang crap out of an exception message - * because it scares the children. - *

- * This function must be static to be used with super() - * in each of the constructors above. - */ - /* - static public final String massage(String msg) { - if (msg.indexOf("java.lang.") == 0) { - //int dot = msg.lastIndexOf('.'); - msg = msg.substring("java.lang.".length()); - } - return msg; - //return (dot == -1) ? msg : msg.substring(dot+1); - } - */ - - - public void printStackTrace() { - if (showStackTrace) { - super.printStackTrace(); - } - } -} diff --git a/src/maple_loader/src/processing/app/helpers/ProcessUtils.java b/src/maple_loader/src/processing/app/helpers/ProcessUtils.java deleted file mode 100644 index c023f5810..000000000 --- a/src/maple_loader/src/processing/app/helpers/ProcessUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -package processing.app.helpers; - -//import processing.app.Base; - -import java.io.IOException; -import java.util.Map; - -import processing.app.Base; - -public class ProcessUtils { - - public static Process exec(String[] command) throws IOException { - // No problems on linux and mac - if (!Base.isWindows()) { - return Runtime.getRuntime().exec(command); - } - - // Brutal hack to workaround windows command line parsing. - // http://stackoverflow.com/questions/5969724/java-runtime-exec-fails-to-escape-characters-properly - // http://msdn.microsoft.com/en-us/library/a1y7w461.aspx - // http://bugs.sun.com/view_bug.do?bug_id=6468220 - // http://bugs.sun.com/view_bug.do?bug_id=6518827 - String[] cmdLine = new String[command.length]; - for (int i = 0; i < command.length; i++) - cmdLine[i] = command[i].replace("\"", "\\\""); - - ProcessBuilder pb = new ProcessBuilder(cmdLine); - Map env = pb.environment(); - env.put("CYGWIN", "nodosfilewarning"); - return pb.start(); - } -} From 9401acf4f251f94a4f8af8be6f7837d68e2d21ae Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Fri, 10 Feb 2023 16:45:11 +0100 Subject: [PATCH 3/9] feat: add *.o files to .gitignore Signed-off-by: Frederic Pillon --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 00e281cbd..8fd574fde 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ __pycache__/ !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -*.code-workspace \ No newline at end of file +*.code-workspace +*.o From e23b29ede635d28775fdc8096591727bee5a3b75 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Mon, 13 Feb 2023 17:29:53 +0100 Subject: [PATCH 4/9] feat: add libserialport sources http://sigrok.org/wiki/Libserialport https://github.com/sigrokproject/libserialport Signed-off-by: Frederic Pillon --- src/libserialport/AUTHORS | 27 + src/libserialport/COPYING | 165 ++ src/libserialport/NEWS | 81 + src/libserialport/README | 92 + src/libserialport/config.h | 111 + src/libserialport/libserialport.h | 1827 ++++++++++++++ src/libserialport/libserialport_internal.h | 311 +++ src/libserialport/serialport.c | 2624 ++++++++++++++++++++ src/libserialport/timing.c | 174 ++ src/libserialport/windows.c | 569 +++++ 10 files changed, 5981 insertions(+) create mode 100644 src/libserialport/AUTHORS create mode 100644 src/libserialport/COPYING create mode 100644 src/libserialport/NEWS create mode 100644 src/libserialport/README create mode 100644 src/libserialport/config.h create mode 100644 src/libserialport/libserialport.h create mode 100644 src/libserialport/libserialport_internal.h create mode 100644 src/libserialport/serialport.c create mode 100644 src/libserialport/timing.c create mode 100644 src/libserialport/windows.c diff --git a/src/libserialport/AUTHORS b/src/libserialport/AUTHORS new file mode 100644 index 000000000..6975761c5 --- /dev/null +++ b/src/libserialport/AUTHORS @@ -0,0 +1,27 @@ +------------------------------------------------------------------------------- +AUTHORS +------------------------------------------------------------------------------- + +Martin Ling conceived the idea for the library, designed the API and wrote much +of the implementation and documentation. + +The initial codebase was adapted from serial code in libsigrok, written by Bert +Vermeulen and Uwe Hermann, who gave permission for it to be relicensed under +the LGPL3+ for inclusion in libserialport. + +The package is maintained by Uwe Hermann, with input from Martin Ling. + +Aurelien Jacobs made several contributions, including the USB metadata API, +improvements to the port enumeration code, and eliminating the previous +dependence on libudev for enumeration on Linux. + +Uffe Jakobsen contributed the FreeBSD support. + +Matthias Heidbrink contributed support for non-standard baudrates on Mac OS X. + +Bug fixes have been contributed by Bert Vermeulen, silverbuddy, Marcus +Comstedt, Antti Nykanen, Michael B. Trausch and Janne Huttunen. + +For a full history of contributions, see the git history. + +Others have helped the project by contributing bug reports and discussion. diff --git a/src/libserialport/COPYING b/src/libserialport/COPYING new file mode 100644 index 000000000..65c5ca88a --- /dev/null +++ b/src/libserialport/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/src/libserialport/NEWS b/src/libserialport/NEWS new file mode 100644 index 000000000..7afa688cb --- /dev/null +++ b/src/libserialport/NEWS @@ -0,0 +1,81 @@ +0.1.1 (2016-01-27) +------------------ + +Note: This release does NOT change the libserialport API or ABI in + backwards-incompatible ways. Programs using libserialport should + continue to work fine without recompiling or relinking. + + * New API calls: + - sp_get_port_description(): Obtain a user friendly port description. + - sp_get_port_transport(): Obtain the underlying transport type. + - sp_get_port_usb_bus_address(): Obtain the USB bus number & device address. + - sp_get_port_usb_vid_pid(): Obtain the USB VID and PID. + - sp_get_port_usb_manufacturer(): Obtain the USB manufacturer string. + - sp_get_port_usb_product(): Obtain the USB product string. + - sp_get_port_usb_serial(): Obtain the USB serial number string. + - sp_get_port_bluetooth_address(): Obtain the Bluetooth MAC address. + - sp_blocking_read_next(): Read bytes from the specified serial port, + returning as soon as any data is available. + * API related additions: + - enum sp_mode: Add SP_MODE_READ_WRITE. + - Add enum sp_transport with the following enum entries: + SP_TRANSPORT_NATIVE, SP_TRANSPORT_USB, SP_TRANSPORT_BLUETOOTH. + * Fix the build on platforms where port enumeration and/or port + metadata is not available or implemented. + * Build system: + - Don't set/override "user variables" such as CFLAGS or LDFLAGS, since + those are meant to be controlled by the "user" (bug #577). + - Modernize and cleanup autotools setup. + * Remove trailing commas in libserialport.h enum definitions to allow + the code to build with the -pedantic compiler option. + * Fix various issues to allow successful builds with -std=c99. + * Fix various (non-fatal) compiler warnings. + * Fix various memory leaks (bug #419, among others). + * Fix a potential overflow of the timeout parameter of poll(). + * Fix ReadFile() ERROR_IO_PENDING in sp_nonblocking_read() (bug #707). + * Fix a glibc >= 2.20 compiler warning for deprecated _BSD_SOURCE (bug #716). + * Rename a 'signals' parameter to 'signal_mask' to avoid a conflict with Qt. + * Fix two potential segfaults in sp_get_port_handle() and sp_get_config_*() + (which only occurred if the user incorrectly passed in a NULL argument). + * sp_list_ports(): Actually set list_ptr NULL as documented. + * Use "Port not open" debug message when a closed port is used (bug #710). + * Linux: + - The libudev requirement has been dropped (/sys is now used directly). + - Fix a build issue in the get_termios_get_ioctl() call (bug #396). + - Fix sp_flush() so that it only flushes the requested buffers. + - Fix a build error if BOTHER is not available (bug #363). + - If present, add the USB "description" for better port identification. + - Handle the case when /sys/class/tty/ entries are not symlinks. + * Windows: + - MinGW-w64 (mingw-w64.sf.net) is now required for building, and MinGW + (mingw.org) is no longer supported (bug #393). + - Fix a build issue due to a missing #include. + - Fix a build issue due to the missing -lsetupapi linker argument. + - Use libtool's -no-undefined option to allow shared (DLL) builds. + - Fix a compile error due to multiply or not defined GUIDs (bug #416). + - Fix a build issue related to the SP_PRIV/SP_API macros (bug #553). + - Fix a bug where an uninitialized pointer was free()'d (bug #512). + - Fix a bug wrt the SetupDiOpenDevRegKey() return code (bug #499). + - Fix a bug wrt restart of RX/error wait operations after read (bug #421). + - Fix a bug wrt WaitCommEvents() and/or fAbortOnError handling (bug #341). + - Fix USB iSerial queries on USB composite devices. + - Strip CR/LF from end of system error messages (bug #585). + - Avoid unnecessary calls to the SetCommTimeouts() function (bug #586). + - Fix a bug in the Windows implementation of sp_blocking_read_next(). + - Fix an ERROR_SEM_TIMEOUT related issue in sp_blocking_write(). + * FreeBSD: + - Implement serial port enumeration for FreeBSD systems. + * Android: + - Fix a portability issue wrt the unavailable 'serial_struct' (bug #376). + - Fix a portability issue wrt a readlinkat() call (bug #377). + * Mac OS X: + - Fix port listing on Mac OS X 10.11 (El Capitan). + * README: Various documentation updates and fixes. + * AUTHORS: Add/update list of contributors. + * Doxygen API docs: Various documentation updates and fixes. + +0.1.0 (2014-05-06) +------------------ + + * Initial release. + diff --git a/src/libserialport/README b/src/libserialport/README new file mode 100644 index 000000000..817dff743 --- /dev/null +++ b/src/libserialport/README @@ -0,0 +1,92 @@ +------------------------------------------------------------------------------- +libserialport: cross-platform library for accessing serial ports +------------------------------------------------------------------------------- + +libserialport is a minimal library written in C that is intended to take care +of the OS-specific details when writing software that uses serial ports. + +By writing your serial code to use libserialport, you enable it to work +transparently on any platform supported by the library. + +The operations that are supported are: + +- Port enumeration (obtaining a list of serial ports on the system). +- Obtaining port metadata (USB device information, Bluetooth address, etc). +- Opening and closing ports. +- Setting port parameters (baud rate, parity, etc). +- Reading, writing and flushing data. +- Obtaining error information. + +libserialport is an open source project released under the LGPL3+ license. + +Status +====== + +The library should build and work on any Windows or Unix-based system. If it +does not, please submit a bug. + +Enumeration is currently implemented on Windows, Mac OS X, FreeBSD and Linux. +On other systems enumeration is not supported, but ports can still be opened +by name and then used. + +If you know how to enumerate available ports on another OS, please submit a bug +with this information, or better still a patch implementing it. + +Dependencies +============ + +No other libraries are required. + +Building +======== + +On Windows, libserialport can be built with Visual Studio 2019 or with +the standalone MSBuild tool, using the solution and project files provided. + +For other environments, the package uses a GNU style build based on autotools. + +Run "./autogen.sh" to generate the build system, "./configure" to setup, then +"make" to build the library and "make install" to install it. + +Windows builds can also be created using the autotools build system, using the +MinGW-w64 toolchain from http://mingw-w64.sourceforge.net/ - either natively +in Windows with the MSYS2 environment, or cross-compiling from another system. + +To build from MSYS2, the following packages must be installed: autoconf, +automake-wrapper, libtool, make, and either mingw-w64-i686-gcc (for 32-bit) +or mingw-w64-x86_64-gcc (for 64-bit). Open either the "MSYS2 MinGW 32-bit" or +"MSYS2 MinGW 64-bit" command window from the Start menu and use this when +configuring and building the package. Using the "MSYS2 MSYS" shell will build +against the Cygwin compatibility layer; this works, but port enumeration and +metadata will not be available, and binaries will depend on Cygwin. The builds +produced by MinGW-w64 are normal Windows DLLs without additional dependencies. + +API +=== + +Doxygen API documentation is included. + +It can also be viewed online at: + + http://sigrok.org/api/libserialport/unstable/ + +Bug reports +=========== + +You can report bugs for libserialport at https://sigrok.org/bugzilla. + +Mailing list +============ + + https://lists.sourceforge.net/lists/listinfo/sigrok-devel + +IRC +=== + +You can find the developers in the #sigrok IRC channel on Libera.Chat. + +Website +======= + +http://sigrok.org/wiki/Libserialport + diff --git a/src/libserialport/config.h b/src/libserialport/config.h new file mode 100644 index 000000000..17391764b --- /dev/null +++ b/src/libserialport/config.h @@ -0,0 +1,111 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* clock_gettime is available. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `BOTHER', and to 0 if you don't. + */ +#define HAVE_DECL_BOTHER 0 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* flock is available. */ +/* #undef HAVE_FLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* realpath is available. */ +/* #undef HAVE_REALPATH */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if the system has the type `struct serial_struct'. */ +/* #undef HAVE_STRUCT_SERIAL_STRUCT */ + +/* Define to 1 if the system has the type `struct termios2'. */ +/* #undef HAVE_STRUCT_TERMIOS2 */ + +/* Define to 1 if `c_ispeed' is a member of `struct termios2'. */ +/* #undef HAVE_STRUCT_TERMIOS2_C_ISPEED */ + +/* Define to 1 if `c_ospeed' is a member of `struct termios2'. */ +/* #undef HAVE_STRUCT_TERMIOS2_C_OSPEED */ + +/* Define to 1 if `c_ispeed' is a member of `struct termios'. */ +/* #undef HAVE_STRUCT_TERMIOS_C_ISPEED */ + +/* Define to 1 if `c_ospeed' is a member of `struct termios'. */ +/* #undef HAVE_STRUCT_TERMIOS_C_OSPEED */ + +/* sys/file.h is available. */ +#define HAVE_SYS_FILE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Enumeration is unsupported. */ +/* #undef NO_ENUMERATION */ + +/* Port metadata is unavailable. */ +/* #undef NO_PORT_METADATA */ + +/* Macro preceding public API functions */ +#define SP_API + +/* . */ +#define SP_LIB_VERSION_AGE 1 + +/* . */ +#define SP_LIB_VERSION_CURRENT 1 + +/* . */ +#define SP_LIB_VERSION_REVISION 0 + +/* . */ +#define SP_LIB_VERSION_STRING "1:0:1" + +/* Macro preceding private functions */ +#define SP_PRIV + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +#if HAVE_STRUCT_TERMIOS_C_ISPEED && HAVE_STRUCT_TERMIOS_C_OSPEED +# define HAVE_TERMIOS_SPEED 1 +#endif +#if HAVE_STRUCT_TERMIOS2_C_ISPEED && HAVE_STRUCT_TERMIOS2_C_OSPEED +# define HAVE_TERMIOS2_SPEED 1 +#endif diff --git a/src/libserialport/libserialport.h b/src/libserialport/libserialport.h new file mode 100644 index 000000000..7467f7438 --- /dev/null +++ b/src/libserialport/libserialport.h @@ -0,0 +1,1827 @@ +/* + * This file is part of the libserialport project. + * + * Copyright (C) 2013, 2015 Martin Ling + * Copyright (C) 2014 Uwe Hermann + * Copyright (C) 2014 Aurelien Jacobs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 Lesser General Public License + * along with this program. If not, see . + */ + +/** + * @mainpage libserialport API + * + * Introduction + * ============ + * + * libserialport is a minimal library written in C that is intended to take + * care of the OS-specific details when writing software that uses serial ports. + * + * By writing your serial code to use libserialport, you enable it to work + * transparently on any platform supported by the library. + * + * libserialport is an open source project released under the LGPL3+ license. + * + * The library is maintained by the [sigrok](http://sigrok.org/) project. See + * the [libserialport homepage](http://sigrok.org/wiki/Libserialport) for the + * latest information. + * + * Source code is maintained in git at + * [git://sigrok.org/libserialport](http://sigrok.org/gitweb/?p=libserialport.git). + * + * Bugs are tracked at http://sigrok.org/bugzilla/. + * + * The library was conceived and designed by Martin Ling, is maintained by + * Uwe Hermann, and has received contributions from several other developers. + * See the git history for full credits. + * + * API information + * =============== + * + * The API has been designed from scratch. It does not exactly resemble the + * serial API of any particular operating system. Instead it aims to provide + * a set of functions that can reliably be implemented across all operating + * systems. These form a sufficient basis for higher level behaviour to + * be implemented in a platform independent manner. + * + * If you are porting code written for a particular OS, you may find you need + * to restructure things somewhat, or do without some specialised features. + * For particular notes on porting existing code, see @ref Porting. + * + * Examples + * -------- + * + * Some simple example programs using libserialport are included in the + * @c examples directory in the source package: + * + * - @ref list_ports.c - Getting a list of ports present on the system. + * - @ref port_info.c - Getting information on a particular serial port. + * - @ref port_config.c - Accessing configuration settings of a port. + * - @ref send_receive.c - Sending and receiving data. + * - @ref await_events.c - Awaiting events on multiple ports. + * - @ref handle_errors.c - Handling errors returned from the library. + * + * These examples are linked with the API documentation. Each function + * in the API reference includes links to where it is used in an example + * program, and each appearance of a function in the examples links + * to that function's entry in the API reference. + * + * Headers + * ------- + * + * To use libserialport functions in your code, you should include the + * libserialport.h header, i.e. + * @code + * #include + * @endcode + * + * Namespace + * --------- + * + * All identifiers defined by the public libserialport headers use the prefix + * @c sp_ (for functions and data types) or @c SP_ (for macros and constants). + * + * Functions + * --------- + * + * The functions provided by the library are documented in detail in + * the following sections: + * + * - @ref Enumeration (obtaining a list of serial ports on the system) + * - @ref Ports (opening, closing and getting information about ports) + * - @ref Configuration (baud rate, parity, etc.) + * - @ref Signals (modem control lines, breaks, etc.) + * - @ref Data (reading and writing data, and buffer management) + * - @ref Waiting (waiting for ports to be ready, integrating with event loops) + * - @ref Errors (getting error and debugging information) + * + * Data structures + * --------------- + * + * The library defines three data structures: + * + * - @ref sp_port, which represents a serial port. + * See @ref Enumeration. + * - @ref sp_port_config, which represents a port configuration. + * See @ref Configuration. + * - @ref sp_event_set, which represents a set of events. + * See @ref Waiting. + * + * All these structures are allocated and freed by library functions. It is + * the caller's responsibility to ensure that the correct calls are made to + * free allocated structures after use. + * + * Return codes and error handling + * ------------------------------- + * + * Most functions have return type @ref sp_return and can return only four + * possible error values: + * + * - @ref SP_ERR_ARG means that a function was called with invalid + * arguments. This implies a bug in the caller. The arguments passed would + * be invalid regardless of the underlying OS or serial device involved. + * + * - @ref SP_ERR_FAIL means that the OS reported a failure. The error code or + * message provided by the OS can be obtained by calling sp_last_error_code() + * or sp_last_error_message(). + * + * - @ref SP_ERR_SUPP indicates that there is no support for the requested + * operation in the current OS, driver or device. No error message is + * available from the OS in this case. There is either no way to request + * the operation in the first place, or libserialport does not know how to + * do so in the current version. + * + * - @ref SP_ERR_MEM indicates that a memory allocation failed. + * + * All of these error values are negative. + * + * Calls that succeed return @ref SP_OK, which is equal to zero. Some functions + * declared @ref sp_return can also return a positive value for a successful + * numeric result, e.g. sp_blocking_read() or sp_blocking_write(). + * + * An error message is only available via sp_last_error_message() in the case + * where @ref SP_ERR_FAIL was returned by the previous function call. The error + * message returned is that provided by the OS, using the current language + * settings. It is an error to call sp_last_error_code() or + * sp_last_error_message() except after a previous function call returned + * @ref SP_ERR_FAIL. The library does not define its own error codes or + * messages to accompany other return codes. + * + * Thread safety + * ------------- + * + * Certain combinations of calls can be made concurrently, as follows. + * + * - Calls using different ports may always be made concurrently, i.e. + * it is safe for separate threads to handle their own ports. + * + * - Calls using the same port may be made concurrently when one call + * is a read operation and one call is a write operation, i.e. it is safe + * to use separate "reader" and "writer" threads for the same port. See + * below for which operations meet these definitions. + * + * Read operations: + * + * - sp_blocking_read() + * - sp_blocking_read_next() + * - sp_nonblocking_read() + * - sp_input_waiting() + * - sp_flush() with @ref SP_BUF_INPUT only. + * - sp_wait() with @ref SP_EVENT_RX_READY only. + * + * Write operations: + * + * - sp_blocking_write() + * - sp_nonblocking_write() + * - sp_output_waiting() + * - sp_drain() + * - sp_flush() with @ref SP_BUF_OUTPUT only. + * - sp_wait() with @ref SP_EVENT_TX_READY only. + * + * If two calls, on the same port, do not fit into one of these categories + * each, then they may not be made concurrently. + * + * Debugging + * --------- + * + * The library can output extensive tracing and debugging information. The + * simplest way to use this is to set the environment variable + * @c LIBSERIALPORT_DEBUG to any value; messages will then be output to the + * standard error stream. + * + * This behaviour is implemented by a default debug message handling + * callback. An alternative callback can be set using sp_set_debug_handler(), + * in order to e.g. redirect the output elsewhere or filter it. + * + * No guarantees are made about the content of the debug output; it is chosen + * to suit the needs of the developers and may change between releases. + * + * @anchor Porting + * Porting + * ------- + * + * The following guidelines may help when porting existing OS-specific code + * to use libserialport. + * + * ### Porting from Unix-like systems ### + * + * There are two main differences to note when porting code written for Unix. + * + * The first is that Unix traditionally provides a wide range of functionality + * for dealing with serial devices at the OS level; this is exposed through the + * termios API and dates to the days when serial terminals were common. If your + * code relies on many of these facilities you will need to adapt it, because + * libserialport provides only a raw binary channel with no special handling. + * + * The second relates to blocking versus non-blocking I/O behaviour. In + * Unix-like systems this is normally specified by setting the @c O_NONBLOCK + * flag on the file descriptor, affecting the semantics of subsequent @c read() + * and @c write() calls. + * + * In libserialport, blocking and nonblocking operations are both available at + * any time. If your existing code ѕets @c O_NONBLOCK, you should use + * sp_nonblocking_read() and sp_nonblocking_write() to get the same behaviour + * as your existing @c read() and @c write() calls. If it does not, you should + * use sp_blocking_read() and sp_blocking_write() instead. You may also find + * sp_blocking_read_next() useful, which reproduces the semantics of a blocking + * read() with @c VTIME=0 and @c VMIN=1 set in termios. + * + * Finally, you should take care if your program uses custom signal handlers. + * The blocking calls provided by libserialport will restart system calls that + * return with @c EINTR, so you will need to make your own arrangements if you + * need to interrupt blocking operations when your signal handlers are called. + * This is not an issue if you only use the default handlers. + * + * ### Porting from Windows ### + * + * The main consideration when porting from Windows is that there is no + * direct equivalent for overlapped I/O operations. + * + * If your program does not use overlapped I/O, you can simply use + * sp_blocking_read() and sp_blocking_write() as direct equivalents for + * @c ReadFile() and @c WriteFile(). You may also find sp_blocking_read_next() + * useful, which reproduces the special semantics of @c ReadFile() with + * @c ReadIntervalTimeout and @c ReadTotalTimeoutMultiplier set to @c MAXDWORD + * and @c ReadTotalTimeoutConstant set to between @c 1 and @c MAXDWORD-1 . + * + * If your program makes use of overlapped I/O to continue work while a serial + * operation is in progress, then you can achieve the same results using + * sp_nonblocking_read() and sp_nonblocking_write(). + * + * Generally, overlapped I/O is combined with either waiting for completion + * once there is no more background work to do (using @c WaitForSingleObject() + * or @c WaitForMultipleObjects()), or periodically checking for completion + * with @c GetOverlappedResult(). If the aim is to start a new operation for + * further data once the previous one has completed, you can instead simply + * call the nonblocking functions again with the next data. If you need to + * wait for completion, use sp_wait() to determine when the port is ready to + * send or receive further data. + */ + +#ifndef LIBSERIALPORT_LIBSERIALPORT_H +#define LIBSERIALPORT_LIBSERIALPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** @cond */ +#ifdef _MSC_VER +/* Microsoft Visual C/C++ compiler in use */ +#ifdef LIBSERIALPORT_MSBUILD +/* Building the library - need to export DLL symbols */ +#define SP_API __declspec(dllexport) +#else +/* Using the library - need to import DLL symbols */ +#define SP_API __declspec(dllimport) +#endif +#else +/* Some other compiler in use */ +#ifndef LIBSERIALPORT_ATBUILD +/* Not building the library itself - don't need any special prefixes. */ +#define SP_API +#endif +#endif +/** @endcond */ + +/** Return values. */ +enum sp_return { + /** Operation completed successfully. */ + SP_OK = 0, + /** Invalid arguments were passed to the function. */ + SP_ERR_ARG = -1, + /** A system error occurred while executing the operation. */ + SP_ERR_FAIL = -2, + /** A memory allocation failed while executing the operation. */ + SP_ERR_MEM = -3, + /** The requested operation is not supported by this system or device. */ + SP_ERR_SUPP = -4 +}; + +/** Port access modes. */ +enum sp_mode { + /** Open port for read access. */ + SP_MODE_READ = 1, + /** Open port for write access. */ + SP_MODE_WRITE = 2, + /** Open port for read and write access. @since 0.1.1 */ + SP_MODE_READ_WRITE = 3 +}; + +/** Port events. */ +enum sp_event { + /** Data received and ready to read. */ + SP_EVENT_RX_READY = 1, + /** Ready to transmit new data. */ + SP_EVENT_TX_READY = 2, + /** Error occurred. */ + SP_EVENT_ERROR = 4 +}; + +/** Buffer selection. */ +enum sp_buffer { + /** Input buffer. */ + SP_BUF_INPUT = 1, + /** Output buffer. */ + SP_BUF_OUTPUT = 2, + /** Both buffers. */ + SP_BUF_BOTH = 3 +}; + +/** Parity settings. */ +enum sp_parity { + /** Special value to indicate setting should be left alone. */ + SP_PARITY_INVALID = -1, + /** No parity. */ + SP_PARITY_NONE = 0, + /** Odd parity. */ + SP_PARITY_ODD = 1, + /** Even parity. */ + SP_PARITY_EVEN = 2, + /** Mark parity. */ + SP_PARITY_MARK = 3, + /** Space parity. */ + SP_PARITY_SPACE = 4 +}; + +/** RTS pin behaviour. */ +enum sp_rts { + /** Special value to indicate setting should be left alone. */ + SP_RTS_INVALID = -1, + /** RTS off. */ + SP_RTS_OFF = 0, + /** RTS on. */ + SP_RTS_ON = 1, + /** RTS used for flow control. */ + SP_RTS_FLOW_CONTROL = 2 +}; + +/** CTS pin behaviour. */ +enum sp_cts { + /** Special value to indicate setting should be left alone. */ + SP_CTS_INVALID = -1, + /** CTS ignored. */ + SP_CTS_IGNORE = 0, + /** CTS used for flow control. */ + SP_CTS_FLOW_CONTROL = 1 +}; + +/** DTR pin behaviour. */ +enum sp_dtr { + /** Special value to indicate setting should be left alone. */ + SP_DTR_INVALID = -1, + /** DTR off. */ + SP_DTR_OFF = 0, + /** DTR on. */ + SP_DTR_ON = 1, + /** DTR used for flow control. */ + SP_DTR_FLOW_CONTROL = 2 +}; + +/** DSR pin behaviour. */ +enum sp_dsr { + /** Special value to indicate setting should be left alone. */ + SP_DSR_INVALID = -1, + /** DSR ignored. */ + SP_DSR_IGNORE = 0, + /** DSR used for flow control. */ + SP_DSR_FLOW_CONTROL = 1 +}; + +/** XON/XOFF flow control behaviour. */ +enum sp_xonxoff { + /** Special value to indicate setting should be left alone. */ + SP_XONXOFF_INVALID = -1, + /** XON/XOFF disabled. */ + SP_XONXOFF_DISABLED = 0, + /** XON/XOFF enabled for input only. */ + SP_XONXOFF_IN = 1, + /** XON/XOFF enabled for output only. */ + SP_XONXOFF_OUT = 2, + /** XON/XOFF enabled for input and output. */ + SP_XONXOFF_INOUT = 3 +}; + +/** Standard flow control combinations. */ +enum sp_flowcontrol { + /** No flow control. */ + SP_FLOWCONTROL_NONE = 0, + /** Software flow control using XON/XOFF characters. */ + SP_FLOWCONTROL_XONXOFF = 1, + /** Hardware flow control using RTS/CTS signals. */ + SP_FLOWCONTROL_RTSCTS = 2, + /** Hardware flow control using DTR/DSR signals. */ + SP_FLOWCONTROL_DTRDSR = 3 +}; + +/** Input signals. */ +enum sp_signal { + /** Clear to send. */ + SP_SIG_CTS = 1, + /** Data set ready. */ + SP_SIG_DSR = 2, + /** Data carrier detect. */ + SP_SIG_DCD = 4, + /** Ring indicator. */ + SP_SIG_RI = 8 +}; + +/** + * Transport types. + * + * @since 0.1.1 + */ +enum sp_transport { + /** Native platform serial port. @since 0.1.1 */ + SP_TRANSPORT_NATIVE, + /** USB serial port adapter. @since 0.1.1 */ + SP_TRANSPORT_USB, + /** Bluetooth serial port adapter. @since 0.1.1 */ + SP_TRANSPORT_BLUETOOTH +}; + +/** + * @struct sp_port + * An opaque structure representing a serial port. + */ +struct sp_port; + +/** + * @struct sp_port_config + * An opaque structure representing the configuration for a serial port. + */ +struct sp_port_config; + +/** + * @struct sp_event_set + * A set of handles to wait on for events. + */ +struct sp_event_set { + /** Array of OS-specific handles. */ + void *handles; + /** Array of bitmasks indicating which events apply for each handle. */ + enum sp_event *masks; + /** Number of handles. */ + unsigned int count; +}; + +/** + * @defgroup Enumeration Port enumeration + * + * Enumerating the serial ports of a system. + * + * See @ref list_ports.c for a working example of port enumeration. + * + * @{ + */ + +/** + * Obtain a pointer to a new sp_port structure representing the named port. + * + * The user should allocate a variable of type "struct sp_port *" and pass a + * pointer to this to receive the result. + * + * The result should be freed after use by calling sp_free_port(). + * + * @param[in] portname The OS-specific name of a serial port. Must not be NULL. + * @param[out] port_ptr If any error is returned, the variable pointed to by + * port_ptr will be set to NULL. Otherwise, it will be set + * to point to the newly allocated port. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr); + +/** + * Free a port structure obtained from sp_get_port_by_name() or sp_copy_port(). + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @since 0.1.0 + */ +SP_API void sp_free_port(struct sp_port *port); + +/** + * List the serial ports available on the system. + * + * The result obtained is an array of pointers to sp_port structures, + * terminated by a NULL. The user should allocate a variable of type + * "struct sp_port **" and pass a pointer to this to receive the result. + * + * The result should be freed after use by calling sp_free_port_list(). + * If a port from the list is to be used after freeing the list, it must be + * copied first using sp_copy_port(). + * + * @param[out] list_ptr If any error is returned, the variable pointed to by + * list_ptr will be set to NULL. Otherwise, it will be set + * to point to the newly allocated array. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr); + +/** + * Make a new copy of an sp_port structure. + * + * The user should allocate a variable of type "struct sp_port *" and pass a + * pointer to this to receive the result. + * + * The copy should be freed after use by calling sp_free_port(). + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] copy_ptr If any error is returned, the variable pointed to by + * copy_ptr will be set to NULL. Otherwise, it will be set + * to point to the newly allocated copy. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr); + +/** + * Free a port list obtained from sp_list_ports(). + * + * This will also free all the sp_port structures referred to from the list; + * any that are to be retained must be copied first using sp_copy_port(). + * + * @param[in] ports Pointer to a list of port structures. Must not be NULL. + * + * @since 0.1.0 + */ +SP_API void sp_free_port_list(struct sp_port **ports); + +/** + * @} + * @defgroup Ports Port handling + * + * Opening, closing and querying ports. + * + * See @ref port_info.c for a working example of getting port information. + * + * @{ + */ + +/** + * Open the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] flags Flags to use when opening the serial port. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags); + +/** + * Close the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_close(struct sp_port *port); + +/** + * Get the name of a port. + * + * The name returned is whatever is normally used to refer to a port on the + * current operating system; e.g. for Windows it will usually be a "COMn" + * device name, and for Unix it will be a device path beginning with "/dev/". + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port name, or NULL if an invalid port is passed. The name + * string is part of the port structure and may not be used after + * the port structure has been freed. + * + * @since 0.1.0 + */ +SP_API char *sp_get_port_name(const struct sp_port *port); + +/** + * Get a description for a port, to present to end user. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port description, or NULL if an invalid port is passed. + * The description string is part of the port structure and may not + * be used after the port structure has been freed. + * + * @since 0.1.1 + */ +SP_API char *sp_get_port_description(const struct sp_port *port); + +/** + * Get the transport type used by a port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port transport type. + * + * @since 0.1.1 + */ +SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port); + +/** + * Get the USB bus number and address on bus of a USB serial adapter port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] usb_bus Pointer to a variable to store the USB bus. + * Can be NULL (in that case it will be ignored). + * @param[out] usb_address Pointer to a variable to store the USB address. + * Can be NULL (in that case it will be ignored). + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.1 + */ +SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, + int *usb_bus, int *usb_address); + +/** + * Get the USB Vendor ID and Product ID of a USB serial adapter port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] usb_vid Pointer to a variable to store the USB VID. + * Can be NULL (in that case it will be ignored). + * @param[out] usb_pid Pointer to a variable to store the USB PID. + * Can be NULL (in that case it will be ignored). + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.1 + */ +SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, int *usb_vid, int *usb_pid); + +/** + * Get the USB manufacturer string of a USB serial adapter port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port manufacturer string, or NULL if an invalid port is passed. + * The manufacturer string is part of the port structure and may not + * be used after the port structure has been freed. + * + * @since 0.1.1 + */ +SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port); + +/** + * Get the USB product string of a USB serial adapter port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port product string, or NULL if an invalid port is passed. + * The product string is part of the port structure and may not be + * used after the port structure has been freed. + * + * @since 0.1.1 + */ +SP_API char *sp_get_port_usb_product(const struct sp_port *port); + +/** + * Get the USB serial number string of a USB serial adapter port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port serial number, or NULL if an invalid port is passed. + * The serial number string is part of the port structure and may + * not be used after the port structure has been freed. + * + * @since 0.1.1 + */ +SP_API char *sp_get_port_usb_serial(const struct sp_port *port); + +/** + * Get the MAC address of a Bluetooth serial adapter port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return The port MAC address, or NULL if an invalid port is passed. + * The MAC address string is part of the port structure and may not + * be used after the port structure has been freed. + * + * @since 0.1.1 + */ +SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port); + +/** + * Get the operating system handle for a port. + * + * The type of the handle depends on the operating system. On Unix based + * systems, the handle is a file descriptor of type "int". On Windows, the + * handle is of type "HANDLE". The user should allocate a variable of the + * appropriate type and pass a pointer to this to receive the result. + * + * To obtain a valid handle, the port must first be opened by calling + * sp_open() using the same port structure. + * + * After the port is closed or the port structure freed, the handle may + * no longer be valid. + * + * @warning This feature is provided so that programs may make use of + * OS-specific functionality where desired. Doing so obviously + * comes at a cost in portability. It also cannot be guaranteed + * that direct usage of the OS handle will not conflict with the + * library's own usage of the port. Be careful. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] result_ptr If any error is returned, the variable pointed to by + * result_ptr will have unknown contents and should not + * be used. Otherwise, it will be set to point to the + * OS handle. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr); + +/** + * @} + * + * @defgroup Configuration Configuration + * + * Setting and querying serial port parameters. + * + * See @ref port_config.c for a working example of port configuration. + * + * You should always configure all settings before using a port. + * There are no default settings applied by libserialport. + * When you open a port it may have default settings from the OS or + * driver, or the settings left over by the last program to use it. + * + * You should always set baud rate, data bits, parity and stop bits. + * + * You should normally also set one of the preset @ref sp_flowcontrol + * flow control modes, which will set up the RTS, CTS, DTR and DSR pin + * behaviours and enable or disable XON/XOFF. If you need an unusual + * configuration not covered by the preset flow control modes, you + * will need to configure these settings individually, and avoid + * calling sp_set_flowcontrol() or sp_set_config_flowcontrol() which + * will overwrite these settings. + * + * A port must be opened before you can change its settings. + * + * There are two ways of accessing port settings: + * + * Configuration structures + * ------------------------ + * + * You can read and write a whole configuration (all settings at once) + * using sp_get_config() and sp_set_config(). This is handy if you want + * to change between some preset combinations, or save and restore an + * existing configuration. It also ensures the changes are made + * together, via an efficient set of calls into the OS - in some cases + * a single system call can be used. + * + * Use accessor functions like sp_get_config_baudrate() and + * sp_set_config_baudrate() to get and set individual settings + * from a configuration. + * + * For each setting in a port configuration, a special value of -1 can + * be used, which will cause that setting to be left alone when the + * configuration is applied by sp_set_config(). + * + * This value is also be used by sp_get_config() for any settings + * which are unconfigured at the OS level, or in a state that is + * not representable within the libserialport API. + * + * Configurations are allocated using sp_new_config() and freed + * with sp_free_config(). You need to manage them yourself. When + * a new configuration is allocated by sp_new_config(), all of + * its settings are initially set to the special -1 value. + * + * Direct functions for changing port settings + * ------------------------------------------- + * + * As a shortcut, you can set individual settings on a port directly + * by calling functions like sp_set_baudrate() and sp_set_parity(). + * This saves you the work of allocating a temporary config, setting it + * up, applying it to a port and then freeing it. + * + * @{ + */ + +/** + * Allocate a port configuration structure. + * + * The user should allocate a variable of type "struct sp_port_config *" and + * pass a pointer to this to receive the result. The variable will be updated + * to point to the new configuration structure. The structure is opaque and + * must be accessed via the functions provided. + * + * All parameters in the structure will be initialised to special values which + * are ignored by sp_set_config(). + * + * The structure should be freed after use by calling sp_free_config(). + * + * @param[out] config_ptr If any error is returned, the variable pointed to by + * config_ptr will be set to NULL. Otherwise, it will + * be set to point to the allocated config structure. + * Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr); + +/** + * Free a port configuration structure. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * + * @since 0.1.0 + */ +SP_API void sp_free_config(struct sp_port_config *config); + +/** + * Get the current configuration of the specified serial port. + * + * The user should allocate a configuration structure using sp_new_config() + * and pass this as the config parameter. The configuration structure will + * be updated with the port configuration. + * + * Any parameters that are configured with settings not recognised or + * supported by libserialport, will be set to special values that are + * ignored by sp_set_config(). + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] config Pointer to a configuration structure that will hold + * the result. Upon errors the contents of the config + * struct will not be changed. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config); + +/** + * Set the configuration for the specified serial port. + * + * For each parameter in the configuration, there is a special value (usually + * -1, but see the documentation for each field). These values will be ignored + * and the corresponding setting left unchanged on the port. + * + * Upon errors, the configuration of the serial port is unknown since + * partial/incomplete config updates may have happened. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config); + +/** + * Set the baud rate for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] baudrate Baud rate in bits per second. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_baudrate(struct sp_port *port, int baudrate); + +/** + * Get the baud rate from a port configuration. + * + * The user should allocate a variable of type int and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] baudrate_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_baudrate(const struct sp_port_config *config, int *baudrate_ptr); + +/** + * Set the baud rate in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] baudrate Baud rate in bits per second, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_baudrate(struct sp_port_config *config, int baudrate); + +/** + * Set the data bits for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] bits Number of data bits. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_bits(struct sp_port *port, int bits); + +/** + * Get the data bits from a port configuration. + * + * The user should allocate a variable of type int and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] bits_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_bits(const struct sp_port_config *config, int *bits_ptr); + +/** + * Set the data bits in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] bits Number of data bits, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_bits(struct sp_port_config *config, int bits); + +/** + * Set the parity setting for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] parity Parity setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_parity(struct sp_port *port, enum sp_parity parity); + +/** + * Get the parity setting from a port configuration. + * + * The user should allocate a variable of type enum sp_parity and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] parity_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_parity(const struct sp_port_config *config, enum sp_parity *parity_ptr); + +/** + * Set the parity setting in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] parity Parity setting, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_parity(struct sp_port_config *config, enum sp_parity parity); + +/** + * Set the stop bits for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] stopbits Number of stop bits. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_stopbits(struct sp_port *port, int stopbits); + +/** + * Get the stop bits from a port configuration. + * + * The user should allocate a variable of type int and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] stopbits_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_stopbits(const struct sp_port_config *config, int *stopbits_ptr); + +/** + * Set the stop bits in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] stopbits Number of stop bits, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_stopbits(struct sp_port_config *config, int stopbits); + +/** + * Set the RTS pin behaviour for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] rts RTS pin mode. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_rts(struct sp_port *port, enum sp_rts rts); + +/** + * Get the RTS pin behaviour from a port configuration. + * + * The user should allocate a variable of type enum sp_rts and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] rts_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_rts(const struct sp_port_config *config, enum sp_rts *rts_ptr); + +/** + * Set the RTS pin behaviour in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] rts RTS pin mode, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_rts(struct sp_port_config *config, enum sp_rts rts); + +/** + * Set the CTS pin behaviour for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] cts CTS pin mode. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_cts(struct sp_port *port, enum sp_cts cts); + +/** + * Get the CTS pin behaviour from a port configuration. + * + * The user should allocate a variable of type enum sp_cts and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] cts_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_cts(const struct sp_port_config *config, enum sp_cts *cts_ptr); + +/** + * Set the CTS pin behaviour in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] cts CTS pin mode, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_cts(struct sp_port_config *config, enum sp_cts cts); + +/** + * Set the DTR pin behaviour for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] dtr DTR pin mode. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_dtr(struct sp_port *port, enum sp_dtr dtr); + +/** + * Get the DTR pin behaviour from a port configuration. + * + * The user should allocate a variable of type enum sp_dtr and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] dtr_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_dtr(const struct sp_port_config *config, enum sp_dtr *dtr_ptr); + +/** + * Set the DTR pin behaviour in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] dtr DTR pin mode, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_dtr(struct sp_port_config *config, enum sp_dtr dtr); + +/** + * Set the DSR pin behaviour for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] dsr DSR pin mode. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_dsr(struct sp_port *port, enum sp_dsr dsr); + +/** + * Get the DSR pin behaviour from a port configuration. + * + * The user should allocate a variable of type enum sp_dsr and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] dsr_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_dsr(const struct sp_port_config *config, enum sp_dsr *dsr_ptr); + +/** + * Set the DSR pin behaviour in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] dsr DSR pin mode, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_dsr(struct sp_port_config *config, enum sp_dsr dsr); + +/** + * Set the XON/XOFF configuration for the specified serial port. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] xon_xoff XON/XOFF mode. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_xon_xoff(struct sp_port *port, enum sp_xonxoff xon_xoff); + +/** + * Get the XON/XOFF configuration from a port configuration. + * + * The user should allocate a variable of type enum sp_xonxoff and + * pass a pointer to this to receive the result. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[out] xon_xoff_ptr Pointer to a variable to store the result. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_config_xon_xoff(const struct sp_port_config *config, enum sp_xonxoff *xon_xoff_ptr); + +/** + * Set the XON/XOFF configuration in a port configuration. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] xon_xoff XON/XOFF mode, or -1 to retain the current setting. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_xon_xoff(struct sp_port_config *config, enum sp_xonxoff xon_xoff); + +/** + * Set the flow control type in a port configuration. + * + * This function is a wrapper that sets the RTS, CTS, DTR, DSR and + * XON/XOFF settings as necessary for the specified flow control + * type. For more fine-grained control of these settings, use their + * individual configuration functions. + * + * @param[in] config Pointer to a configuration structure. Must not be NULL. + * @param[in] flowcontrol Flow control setting to use. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol); + +/** + * Set the flow control type for the specified serial port. + * + * This function is a wrapper that sets the RTS, CTS, DTR, DSR and + * XON/XOFF settings as necessary for the specified flow control + * type. For more fine-grained control of these settings, use their + * individual configuration functions. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] flowcontrol Flow control setting to use. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol); + +/** + * @} + * + * @defgroup Data Data handling + * + * Reading, writing, and flushing data. + * + * See @ref send_receive.c for an example of sending and receiving data. + * + * @{ + */ + +/** + * Read bytes from the specified serial port, blocking until complete. + * + * @warning If your program runs on Unix, defines its own signal handlers, and + * needs to abort blocking reads when these are called, then you + * should not use this function. It repeats system calls that return + * with EINTR. To be able to abort a read from a signal handler, you + * should implement your own blocking read using sp_nonblocking_read() + * together with a blocking method that makes sense for your program. + * E.g. you can obtain the file descriptor for an open port using + * sp_get_port_handle() and use this to call select() or pselect(), + * with appropriate arrangements to return if a signal is received. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] buf Buffer in which to store the bytes read. Must not be NULL. + * @param[in] count Requested number of bytes to read. + * @param[in] timeout_ms Timeout in milliseconds, or zero to wait indefinitely. + * + * @return The number of bytes read on success, or a negative error code. If + * the number of bytes returned is less than that requested, the + * timeout was reached before the requested number of bytes was + * available. If timeout is zero, the function will always return + * either the requested number of bytes or a negative error code. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms); + +/** + * Read bytes from the specified serial port, returning as soon as any data is + * available. + * + * @warning If your program runs on Unix, defines its own signal handlers, and + * needs to abort blocking reads when these are called, then you + * should not use this function. It repeats system calls that return + * with EINTR. To be able to abort a read from a signal handler, you + * should implement your own blocking read using sp_nonblocking_read() + * together with a blocking method that makes sense for your program. + * E.g. you can obtain the file descriptor for an open port using + * sp_get_port_handle() and use this to call select() or pselect(), + * with appropriate arrangements to return if a signal is received. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] buf Buffer in which to store the bytes read. Must not be NULL. + * @param[in] count Maximum number of bytes to read. Must not be zero. + * @param[in] timeout_ms Timeout in milliseconds, or zero to wait indefinitely. + * + * @return The number of bytes read on success, or a negative error code. If + * the result is zero, the timeout was reached before any bytes were + * available. If timeout_ms is zero, the function will always return + * either at least one byte, or a negative error code. + * + * @since 0.1.1 + */ +SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms); + +/** + * Read bytes from the specified serial port, without blocking. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] buf Buffer in which to store the bytes read. Must not be NULL. + * @param[in] count Maximum number of bytes to read. + * + * @return The number of bytes read on success, or a negative error code. The + * number of bytes returned may be any number from zero to the maximum + * that was requested. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count); + +/** + * Write bytes to the specified serial port, blocking until complete. + * + * Note that this function only ensures that the accepted bytes have been + * written to the OS; they may be held in driver or hardware buffers and not + * yet physically transmitted. To check whether all written bytes have actually + * been transmitted, use the sp_output_waiting() function. To wait until all + * written bytes have actually been transmitted, use the sp_drain() function. + * + * @warning If your program runs on Unix, defines its own signal handlers, and + * needs to abort blocking writes when these are called, then you + * should not use this function. It repeats system calls that return + * with EINTR. To be able to abort a write from a signal handler, you + * should implement your own blocking write using sp_nonblocking_write() + * together with a blocking method that makes sense for your program. + * E.g. you can obtain the file descriptor for an open port using + * sp_get_port_handle() and use this to call select() or pselect(), + * with appropriate arrangements to return if a signal is received. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] buf Buffer containing the bytes to write. Must not be NULL. + * @param[in] count Requested number of bytes to write. + * @param[in] timeout_ms Timeout in milliseconds, or zero to wait indefinitely. + * + * @return The number of bytes written on success, or a negative error code. + * If the number of bytes returned is less than that requested, the + * timeout was reached before the requested number of bytes was + * written. If timeout is zero, the function will always return + * either the requested number of bytes or a negative error code. In + * the event of an error there is no way to determine how many bytes + * were sent before the error occurred. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout_ms); + +/** + * Write bytes to the specified serial port, without blocking. + * + * Note that this function only ensures that the accepted bytes have been + * written to the OS; they may be held in driver or hardware buffers and not + * yet physically transmitted. To check whether all written bytes have actually + * been transmitted, use the sp_output_waiting() function. To wait until all + * written bytes have actually been transmitted, use the sp_drain() function. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] buf Buffer containing the bytes to write. Must not be NULL. + * @param[in] count Maximum number of bytes to write. + * + * @return The number of bytes written on success, or a negative error code. + * The number of bytes returned may be any number from zero to the + * maximum that was requested. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count); + +/** + * Gets the number of bytes waiting in the input buffer. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return Number of bytes waiting on success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_input_waiting(struct sp_port *port); + +/** + * Gets the number of bytes waiting in the output buffer. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return Number of bytes waiting on success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_output_waiting(struct sp_port *port); + +/** + * Flush serial port buffers. Data in the selected buffer(s) is discarded. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] buffers Which buffer(s) to flush. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers); + +/** + * Wait for buffered data to be transmitted. + * + * @warning If your program runs on Unix, defines its own signal handlers, and + * needs to abort draining the output buffer when when these are + * called, then you should not use this function. It repeats system + * calls that return with EINTR. To be able to abort a drain from a + * signal handler, you would need to implement your own blocking + * drain by polling the result of sp_output_waiting(). + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_drain(struct sp_port *port); + +/** + * @} + * + * @defgroup Waiting Waiting + * + * Waiting for events and timeout handling. + * + * See @ref await_events.c for an example of awaiting events on multiple ports. + * + * @{ + */ + +/** + * Allocate storage for a set of events. + * + * The user should allocate a variable of type struct sp_event_set *, + * then pass a pointer to this variable to receive the result. + * + * The result should be freed after use by calling sp_free_event_set(). + * + * @param[out] result_ptr If any error is returned, the variable pointed to by + * result_ptr will be set to NULL. Otherwise, it will + * be set to point to the event set. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr); + +/** + * Add events to a struct sp_event_set for a given port. + * + * The port must first be opened by calling sp_open() using the same port + * structure. + * + * After the port is closed or the port structure freed, the results may + * no longer be valid. + * + * @param[in,out] event_set Event set to update. Must not be NULL. + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[in] mask Bitmask of events to be waited for. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set, + const struct sp_port *port, enum sp_event mask); + +/** + * Wait for any of a set of events to occur. + * + * @param[in] event_set Event set to wait on. Must not be NULL. + * @param[in] timeout_ms Timeout in milliseconds, or zero to wait indefinitely. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout_ms); + +/** + * Free a structure allocated by sp_new_event_set(). + * + * @param[in] event_set Event set to free. Must not be NULL. + * + * @since 0.1.0 + */ +SP_API void sp_free_event_set(struct sp_event_set *event_set); + +/** + * @} + * + * @defgroup Signals Signals + * + * Port signalling operations. + * + * @{ + */ + +/** + * Gets the status of the control signals for the specified port. + * + * The user should allocate a variable of type "enum sp_signal" and pass a + * pointer to this variable to receive the result. The result is a bitmask + * in which individual signals can be checked by bitwise OR with values of + * the sp_signal enum. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * @param[out] signal_mask Pointer to a variable to receive the result. + * Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signal_mask); + +/** + * Put the port transmit line into the break state. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_start_break(struct sp_port *port); + +/** + * Take the port transmit line out of the break state. + * + * @param[in] port Pointer to a port structure. Must not be NULL. + * + * @return SP_OK upon success, a negative error code otherwise. + * + * @since 0.1.0 + */ +SP_API enum sp_return sp_end_break(struct sp_port *port); + +/** + * @} + * + * @defgroup Errors Errors + * + * Obtaining error information. + * + * See @ref handle_errors.c for an example of error handling. + * + * @{ + */ + +/** + * Get the error code for a failed operation. + * + * In order to obtain the correct result, this function should be called + * straight after the failure, before executing any other system operations. + * The result is thread-specific, and only valid when called immediately + * after a previous call returning SP_ERR_FAIL. + * + * @return The system's numeric code for the error that caused the last + * operation to fail. + * + * @since 0.1.0 + */ +SP_API int sp_last_error_code(void); + +/** + * Get the error message for a failed operation. + * + * In order to obtain the correct result, this function should be called + * straight after the failure, before executing other system operations. + * The result is thread-specific, and only valid when called immediately + * after a previous call returning SP_ERR_FAIL. + * + * @return The system's message for the error that caused the last + * operation to fail. This string may be allocated by the function, + * and should be freed after use by calling sp_free_error_message(). + * + * @since 0.1.0 + */ +SP_API char *sp_last_error_message(void); + +/** + * Free an error message returned by sp_last_error_message(). + * + * @param[in] message The error message string to free. Must not be NULL. + * + * @since 0.1.0 + */ +SP_API void sp_free_error_message(char *message); + +/** + * Set the handler function for library debugging messages. + * + * Debugging messages are generated by the library during each operation, + * to help in diagnosing problems. The handler will be called for each + * message. The handler can be set to NULL to ignore all debug messages. + * + * The handler function should accept a format string and variable length + * argument list, in the same manner as e.g. printf(). + * + * The default handler is sp_default_debug_handler(). + * + * @param[in] handler The handler function to use. Can be NULL (in that case + * all debug messages will be ignored). + * + * @since 0.1.0 + */ +SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...)); + +/** + * Default handler function for library debugging messages. + * + * This function prints debug messages to the standard error stream if the + * environment variable LIBSERIALPORT_DEBUG is set. Otherwise, they are + * ignored. + * + * @param[in] format The format string to use. Must not be NULL. + * @param[in] ... The variable length argument list to use. + * + * @since 0.1.0 + */ +SP_API void sp_default_debug_handler(const char *format, ...); + +/** @} */ + +/** + * @defgroup Versions Versions + * + * Version number querying functions, definitions, and macros. + * + * This set of API calls returns two different version numbers related + * to libserialport. The "package version" is the release version number of the + * libserialport tarball in the usual "major.minor.micro" format, e.g. "0.1.0". + * + * The "library version" is independent of that; it is the libtool version + * number in the "current:revision:age" format, e.g. "2:0:0". + * See http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning for details. + * + * Both version numbers (and/or individual components of them) can be + * retrieved via the API calls at runtime, and/or they can be checked at + * compile/preprocessor time using the respective macros. + * + * @{ + */ + +/* + * Package version macros (can be used for conditional compilation). + */ + +/** The libserialport package 'major' version number. */ +#define SP_PACKAGE_VERSION_MAJOR 0 + +/** The libserialport package 'minor' version number. */ +#define SP_PACKAGE_VERSION_MINOR 1 + +/** The libserialport package 'micro' version number. */ +#define SP_PACKAGE_VERSION_MICRO 1 + +/** The libserialport package version ("major.minor.micro") as string. */ +#define SP_PACKAGE_VERSION_STRING "0.1.1" + +/* + * Library/libtool version macros (can be used for conditional compilation). + */ + +/** The libserialport libtool 'current' version number. */ +#define SP_LIB_VERSION_CURRENT 1 + +/** The libserialport libtool 'revision' version number. */ +#define SP_LIB_VERSION_REVISION 0 + +/** The libserialport libtool 'age' version number. */ +#define SP_LIB_VERSION_AGE 1 + +/** The libserialport libtool version ("current:revision:age") as string. */ +#define SP_LIB_VERSION_STRING "1:0:1" + +/** + * Get the major libserialport package version number. + * + * @return The major package version number. + * + * @since 0.1.0 + */ +SP_API int sp_get_major_package_version(void); + +/** + * Get the minor libserialport package version number. + * + * @return The minor package version number. + * + * @since 0.1.0 + */ +SP_API int sp_get_minor_package_version(void); + +/** + * Get the micro libserialport package version number. + * + * @return The micro package version number. + * + * @since 0.1.0 + */ +SP_API int sp_get_micro_package_version(void); + +/** + * Get the libserialport package version number as a string. + * + * @return The package version number string. The returned string is + * static and thus should NOT be free'd by the caller. + * + * @since 0.1.0 + */ +SP_API const char *sp_get_package_version_string(void); + +/** + * Get the "current" part of the libserialport library version number. + * + * @return The "current" library version number. + * + * @since 0.1.0 + */ +SP_API int sp_get_current_lib_version(void); + +/** + * Get the "revision" part of the libserialport library version number. + * + * @return The "revision" library version number. + * + * @since 0.1.0 + */ +SP_API int sp_get_revision_lib_version(void); + +/** + * Get the "age" part of the libserialport library version number. + * + * @return The "age" library version number. + * + * @since 0.1.0 + */ +SP_API int sp_get_age_lib_version(void); + +/** + * Get the libserialport library version number as a string. + * + * @return The library version number string. The returned string is + * static and thus should NOT be free'd by the caller. + * + * @since 0.1.0 + */ +SP_API const char *sp_get_lib_version_string(void); + +/** @} */ + +/** + * @example list_ports.c Getting a list of ports present on the system. + * @example port_info.c Getting information on a particular serial port. + * @example port_config.c Accessing configuration settings of a port. + * @example send_receive.c Sending and receiving data. + * @example await_events.c Awaiting events on multiple ports. + * @example handle_errors.c Handling errors returned from the library. +*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libserialport/libserialport_internal.h b/src/libserialport/libserialport_internal.h new file mode 100644 index 000000000..ecf8fe95f --- /dev/null +++ b/src/libserialport/libserialport_internal.h @@ -0,0 +1,311 @@ +/* + * This file is part of the libserialport project. + * + * Copyright (C) 2014 Martin Ling + * Copyright (C) 2014 Aurelien Jacobs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef LIBSERIALPORT_LIBSERIALPORT_INTERNAL_H +#define LIBSERIALPORT_LIBSERIALPORT_INTERNAL_H + +/* These MSVC-specific defines must appear before other headers.*/ +#ifdef _MSC_VER +#define _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_SECURE_NO_WARNINGS +#endif + +/* These feature test macros must appear before other headers.*/ +#if defined(__linux__) || defined(__CYGWIN__) +/* For timeradd, timersub, timercmp, realpath. */ +#define _BSD_SOURCE 1 /* for glibc < 2.19 */ +#define _DEFAULT_SOURCE 1 /* for glibc >= 2.20 */ +/* For clock_gettime and associated types. */ +#define _POSIX_C_SOURCE 199309L +#endif + +#ifdef LIBSERIALPORT_ATBUILD +/* If building with autoconf, include the generated config.h. */ +#include +#endif + +#ifdef LIBSERIALPORT_MSBUILD +/* If building with MS tools, define necessary things that + would otherwise appear in config.h. */ +#define SP_PRIV +#endif + +#include "libserialport.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#include +#include +#undef DEFINE_GUID +#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \ + static const GUID name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } } +#include +#include +/* The largest size that can be passed to WriteFile() safely + * on any architecture. This arises from the expression: + * PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR) + * and this worst-case value is found on x64. */ +#define WRITEFILE_MAX_SIZE 33525760 +#else +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_FILE_H +#include +#endif +#endif +#ifdef __APPLE__ +#include +#include +#include +#include +#include +#include +#endif +#ifdef __linux__ +#include +/* Android only has linux/serial.h from platform 21 onwards. */ +#if !(defined(__ANDROID__) && (__ANDROID_API__ < 21)) +#include +#endif +#include "linux_termios.h" + +/* TCGETX/TCSETX is not available everywhere. */ +#if defined(TCGETX) && defined(TCSETX) && defined(HAVE_STRUCT_TERMIOX) +#define USE_TERMIOX +#endif +#endif + +/* TIOCINQ/TIOCOUTQ is not available everywhere. */ +#if !defined(TIOCINQ) && defined(FIONREAD) +#define TIOCINQ FIONREAD +#endif +#if !defined(TIOCOUTQ) && defined(FIONWRITE) +#define TIOCOUTQ FIONWRITE +#endif + +/* + * O_CLOEXEC is not available everywhere, fallback to not setting the + * flag on those systems. + */ +#ifndef _WIN32 +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif +#endif + +/* Non-standard baudrates are not available everywhere. */ +#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && HAVE_DECL_BOTHER +#define USE_TERMIOS_SPEED +#endif + +struct sp_port { + char *name; + char *description; + enum sp_transport transport; + int usb_bus; + int usb_address; + int usb_vid; + int usb_pid; + char *usb_manufacturer; + char *usb_product; + char *usb_serial; + char *bluetooth_address; +#ifdef _WIN32 + char *usb_path; + HANDLE hdl; + COMMTIMEOUTS timeouts; + OVERLAPPED write_ovl; + OVERLAPPED read_ovl; + OVERLAPPED wait_ovl; + DWORD events; + BYTE *write_buf; + DWORD write_buf_size; + BOOL writing; + BOOL wait_running; +#else + int fd; +#endif +}; + +struct sp_port_config { + int baudrate; + int bits; + enum sp_parity parity; + int stopbits; + enum sp_rts rts; + enum sp_cts cts; + enum sp_dtr dtr; + enum sp_dsr dsr; + enum sp_xonxoff xon_xoff; +}; + +struct port_data { +#ifdef _WIN32 + DCB dcb; +#else + struct termios term; + int controlbits; + int termiox_supported; + int rts_flow; + int cts_flow; + int dtr_flow; + int dsr_flow; +#endif +}; + +#ifdef _WIN32 +typedef HANDLE event_handle; +#else +typedef int event_handle; +#endif + +/* Standard baud rates. */ +#ifdef _WIN32 +#define BAUD_TYPE DWORD +#define BAUD(n) {CBR_##n, n} +#else +#define BAUD_TYPE speed_t +#define BAUD(n) {B##n, n} +#endif + +struct std_baudrate { + BAUD_TYPE index; + int value; +}; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +extern void (*sp_debug_handler)(const char *format, ...); + +/* Debug output macros. */ +#define DEBUG_FMT(fmt, ...) do { \ + if (sp_debug_handler) \ + sp_debug_handler(fmt ".\n", __VA_ARGS__); \ +} while (0) +#define DEBUG(msg) DEBUG_FMT(msg, NULL) +#define DEBUG_ERROR(err, msg) DEBUG_FMT("%s returning " #err ": " msg, __func__) +#define DEBUG_FAIL(msg) do { \ + char *errmsg = sp_last_error_message(); \ + DEBUG_FMT("%s returning SP_ERR_FAIL: " msg ": %s", __func__, errmsg); \ + sp_free_error_message(errmsg); \ +} while (0); +#define RETURN() do { \ + DEBUG_FMT("%s returning", __func__); \ + return; \ +} while (0) +#define RETURN_CODE(x) do { \ + DEBUG_FMT("%s returning " #x, __func__); \ + return x; \ +} while (0) +#define RETURN_CODEVAL(x) do { \ + switch (x) { \ + case SP_OK: RETURN_CODE(SP_OK); \ + case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \ + case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \ + case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \ + case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \ + default: RETURN_CODE(SP_ERR_FAIL); \ + } \ +} while (0) +#define RETURN_OK() RETURN_CODE(SP_OK); +#define RETURN_ERROR(err, msg) do { \ + DEBUG_ERROR(err, msg); \ + return err; \ +} while (0) +#define RETURN_FAIL(msg) do { \ + DEBUG_FAIL(msg); \ + return SP_ERR_FAIL; \ +} while (0) +#define RETURN_INT(x) do { \ + int _x = x; \ + DEBUG_FMT("%s returning %d", __func__, _x); \ + return _x; \ +} while (0) +#define RETURN_STRING(x) do { \ + char *_x = x; \ + DEBUG_FMT("%s returning %s", __func__, _x); \ + return _x; \ +} while (0) +#define RETURN_POINTER(x) do { \ + void *_x = x; \ + DEBUG_FMT("%s returning %p", __func__, _x); \ + return _x; \ +} while (0) +#define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0) +#define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0) +#define TRACE(fmt, ...) DEBUG_FMT("%s(" fmt ") called", __func__, __VA_ARGS__) +#define TRACE_VOID() DEBUG_FMT("%s() called", __func__) + +#define TRY(x) do { int retval = x; if (retval != SP_OK) RETURN_CODEVAL(retval); } while (0) + +SP_PRIV struct sp_port **list_append(struct sp_port **list, const char *portname); + +/* OS-specific Helper functions. */ +SP_PRIV enum sp_return get_port_details(struct sp_port *port); +SP_PRIV enum sp_return list_ports(struct sp_port ***list); + +/* Timing abstraction */ + +struct time { +#ifdef _WIN32 + int64_t ticks; +#else + struct timeval tv; +#endif +}; + +struct timeout { + unsigned int ms, limit_ms; + struct time start, now, end, delta, delta_max; + struct timeval delta_tv; + bool calls_started, overflow; +}; + +SP_PRIV void time_get(struct time *time); +SP_PRIV void time_set_ms(struct time *time, unsigned int ms); +SP_PRIV void time_add(const struct time *a, const struct time *b, struct time *result); +SP_PRIV void time_sub(const struct time *a, const struct time *b, struct time *result); +SP_PRIV bool time_greater(const struct time *a, const struct time *b); +SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv); +SP_PRIV unsigned int time_as_ms(const struct time *time); +SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms); +SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms); +SP_PRIV bool timeout_check(struct timeout *timeout); +SP_PRIV void timeout_update(struct timeout *timeout); +SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout); +SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout); + +#endif diff --git a/src/libserialport/serialport.c b/src/libserialport/serialport.c new file mode 100644 index 000000000..e6097eeda --- /dev/null +++ b/src/libserialport/serialport.c @@ -0,0 +1,2624 @@ +/* + * This file is part of the libserialport project. + * + * Copyright (C) 2010-2012 Bert Vermeulen + * Copyright (C) 2010-2015 Uwe Hermann + * Copyright (C) 2013-2015 Martin Ling + * Copyright (C) 2013 Matthias Heidbrink + * Copyright (C) 2014 Aurelien Jacobs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 Lesser General Public License + * along with this program. If not, see . + */ + +#include "libserialport_internal.h" + +static const struct std_baudrate std_baudrates[] = { +#ifdef _WIN32 + /* + * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to + * have documented CBR_* macros. + */ + BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800), + BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600), + BAUD(115200), BAUD(128000), BAUD(256000), +#else + BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200), + BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800), + BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200), + BAUD(230400), +#if !defined(__APPLE__) && !defined(__OpenBSD__) + BAUD(460800), +#endif +#endif +}; + +#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates) + +void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler; + +static enum sp_return get_config(struct sp_port *port, struct port_data *data, + struct sp_port_config *config); + +static enum sp_return set_config(struct sp_port *port, struct port_data *data, + const struct sp_port_config *config); + +SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) +{ + struct sp_port *port; +#ifndef NO_PORT_METADATA + enum sp_return ret; +#endif + size_t len; + + TRACE("%s, %p", portname, port_ptr); + + if (!port_ptr) + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + + *port_ptr = NULL; + + if (!portname) + RETURN_ERROR(SP_ERR_ARG, "Null port name"); + + DEBUG_FMT("Building structure for port %s", portname); + +#if !defined(_WIN32) && defined(HAVE_REALPATH) + /* + * get_port_details() below tries to be too smart and figure out + * some transport properties from the port name which breaks with + * symlinks. Therefore we canonicalize the portname first. + */ + char pathbuf[PATH_MAX + 1]; + char *res = realpath(portname, pathbuf); + if (!res) + RETURN_ERROR(SP_ERR_ARG, "Could not retrieve realpath behind port name"); + + portname = pathbuf; +#endif + + if (!(port = malloc(sizeof(struct sp_port)))) + RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed"); + + len = strlen(portname) + 1; + + if (!(port->name = malloc(len))) { + free(port); + RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed"); + } + + memcpy(port->name, portname, len); + +#ifdef _WIN32 + port->usb_path = NULL; + port->hdl = INVALID_HANDLE_VALUE; + port->write_buf = NULL; + port->write_buf_size = 0; +#else + port->fd = -1; +#endif + + port->description = NULL; + port->transport = SP_TRANSPORT_NATIVE; + port->usb_bus = -1; + port->usb_address = -1; + port->usb_vid = -1; + port->usb_pid = -1; + port->usb_manufacturer = NULL; + port->usb_product = NULL; + port->usb_serial = NULL; + port->bluetooth_address = NULL; + +#ifndef NO_PORT_METADATA + if ((ret = get_port_details(port)) != SP_OK) { + sp_free_port(port); + return ret; + } +#endif + + *port_ptr = port; + + RETURN_OK(); +} + +SP_API char *sp_get_port_name(const struct sp_port *port) +{ + TRACE("%p", port); + + if (!port) + return NULL; + + RETURN_STRING(port->name); +} + +SP_API char *sp_get_port_description(const struct sp_port *port) +{ + TRACE("%p", port); + + if (!port || !port->description) + return NULL; + + RETURN_STRING(port->description); +} + +SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port) +{ + TRACE("%p", port); + + RETURN_INT(port ? port->transport : SP_TRANSPORT_NATIVE); +} + +SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, + int *usb_bus,int *usb_address) +{ + TRACE("%p", port); + + if (!port) + RETURN_ERROR(SP_ERR_ARG, "Null port"); + if (port->transport != SP_TRANSPORT_USB) + RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport"); + if (port->usb_bus < 0 || port->usb_address < 0) + RETURN_ERROR(SP_ERR_SUPP, "Bus and address values are not available"); + + if (usb_bus) + *usb_bus = port->usb_bus; + if (usb_address) + *usb_address = port->usb_address; + + RETURN_OK(); +} + +SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, + int *usb_vid, int *usb_pid) +{ + TRACE("%p", port); + + if (!port) + RETURN_ERROR(SP_ERR_ARG, "Null port"); + if (port->transport != SP_TRANSPORT_USB) + RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport"); + if (port->usb_vid < 0 || port->usb_pid < 0) + RETURN_ERROR(SP_ERR_SUPP, "VID:PID values are not available"); + + if (usb_vid) + *usb_vid = port->usb_vid; + if (usb_pid) + *usb_pid = port->usb_pid; + + RETURN_OK(); +} + +SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port) +{ + TRACE("%p", port); + + if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer) + return NULL; + + RETURN_STRING(port->usb_manufacturer); +} + +SP_API char *sp_get_port_usb_product(const struct sp_port *port) +{ + TRACE("%p", port); + + if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product) + return NULL; + + RETURN_STRING(port->usb_product); +} + +SP_API char *sp_get_port_usb_serial(const struct sp_port *port) +{ + TRACE("%p", port); + + if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial) + return NULL; + + RETURN_STRING(port->usb_serial); +} + +SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port) +{ + TRACE("%p", port); + + if (!port || port->transport != SP_TRANSPORT_BLUETOOTH + || !port->bluetooth_address) + return NULL; + + RETURN_STRING(port->bluetooth_address); +} + +SP_API enum sp_return sp_get_port_handle(const struct sp_port *port, + void *result_ptr) +{ + TRACE("%p, %p", port, result_ptr); + + if (!port) + RETURN_ERROR(SP_ERR_ARG, "Null port"); + if (!result_ptr) + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + +#ifdef _WIN32 + HANDLE *handle_ptr = result_ptr; + *handle_ptr = port->hdl; +#else + int *fd_ptr = result_ptr; + *fd_ptr = port->fd; +#endif + + RETURN_OK(); +} + +SP_API enum sp_return sp_copy_port(const struct sp_port *port, + struct sp_port **copy_ptr) +{ + TRACE("%p, %p", port, copy_ptr); + + if (!copy_ptr) + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + + *copy_ptr = NULL; + + if (!port) + RETURN_ERROR(SP_ERR_ARG, "Null port"); + + if (!port->name) + RETURN_ERROR(SP_ERR_ARG, "Null port name"); + + DEBUG("Copying port structure"); + + RETURN_INT(sp_get_port_by_name(port->name, copy_ptr)); +} + +SP_API void sp_free_port(struct sp_port *port) +{ + TRACE("%p", port); + + if (!port) { + DEBUG("Null port"); + RETURN(); + } + + DEBUG("Freeing port structure"); + + if (port->name) + free(port->name); + if (port->description) + free(port->description); + if (port->usb_manufacturer) + free(port->usb_manufacturer); + if (port->usb_product) + free(port->usb_product); + if (port->usb_serial) + free(port->usb_serial); + if (port->bluetooth_address) + free(port->bluetooth_address); +#ifdef _WIN32 + if (port->usb_path) + free(port->usb_path); + if (port->write_buf) + free(port->write_buf); +#endif + + free(port); + + RETURN(); +} + +SP_PRIV struct sp_port **list_append(struct sp_port **list, + const char *portname) +{ + void *tmp; + size_t count; + + for (count = 0; list[count]; count++) + ; + if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2)))) + goto fail; + list = tmp; + if (sp_get_port_by_name(portname, &list[count]) != SP_OK) + goto fail; + list[count + 1] = NULL; + return list; + +fail: + sp_free_port_list(list); + return NULL; +} + +SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr) +{ +#ifndef NO_ENUMERATION + struct sp_port **list; + int ret; +#endif + + TRACE("%p", list_ptr); + + if (!list_ptr) + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + + *list_ptr = NULL; + +#ifdef NO_ENUMERATION + RETURN_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform"); +#else + DEBUG("Enumerating ports"); + + if (!(list = malloc(sizeof(struct sp_port *)))) + RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed"); + + list[0] = NULL; + + ret = list_ports(&list); + + if (ret == SP_OK) { + *list_ptr = list; + } else { + sp_free_port_list(list); + *list_ptr = NULL; + } + + RETURN_CODEVAL(ret); +#endif +} + +SP_API void sp_free_port_list(struct sp_port **list) +{ + unsigned int i; + + TRACE("%p", list); + + if (!list) { + DEBUG("Null list"); + RETURN(); + } + + DEBUG("Freeing port list"); + + for (i = 0; list[i]; i++) + sp_free_port(list[i]); + free(list); + + RETURN(); +} + +#define CHECK_PORT() do { \ + if (!port) \ + RETURN_ERROR(SP_ERR_ARG, "Null port"); \ + if (!port->name) \ + RETURN_ERROR(SP_ERR_ARG, "Null port name"); \ +} while (0) +#ifdef _WIN32 +#define CHECK_PORT_HANDLE() do { \ + if (port->hdl == INVALID_HANDLE_VALUE) \ + RETURN_ERROR(SP_ERR_ARG, "Port not open"); \ +} while (0) +#else +#define CHECK_PORT_HANDLE() do { \ + if (port->fd < 0) \ + RETURN_ERROR(SP_ERR_ARG, "Port not open"); \ +} while (0) +#endif +#define CHECK_OPEN_PORT() do { \ + CHECK_PORT(); \ + CHECK_PORT_HANDLE(); \ +} while (0) + +#ifdef WIN32 +/** To be called after port receive buffer is emptied. */ +static enum sp_return restart_wait(struct sp_port *port) +{ + DWORD wait_result; + + if (port->wait_running) { + /* Check status of running wait operation. */ + if (GetOverlappedResult(port->hdl, &port->wait_ovl, + &wait_result, FALSE)) { + DEBUG("Previous wait completed"); + port->wait_running = FALSE; + } else if (GetLastError() == ERROR_IO_INCOMPLETE) { + DEBUG("Previous wait still running"); + RETURN_OK(); + } else { + RETURN_FAIL("GetOverlappedResult() failed"); + } + } + + if (!port->wait_running) { + /* Start new wait operation. */ + if (WaitCommEvent(port->hdl, &port->events, + &port->wait_ovl)) { + DEBUG("New wait returned, events already pending"); + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("New wait running in background"); + port->wait_running = TRUE; + } else { + RETURN_FAIL("WaitCommEvent() failed"); + } + } + + RETURN_OK(); +} +#endif + +SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) +{ + struct port_data data; + struct sp_port_config config; + enum sp_return ret; + + TRACE("%p, 0x%x", port, flags); + + CHECK_PORT(); + + if (flags > SP_MODE_READ_WRITE) + RETURN_ERROR(SP_ERR_ARG, "Invalid flags"); + + DEBUG_FMT("Opening port %s", port->name); + +#ifdef _WIN32 + DWORD desired_access = 0, flags_and_attributes = 0, errors; + char *escaped_port_name; + COMSTAT status; + + /* Prefix port name with '\\.\' to work with ports above COM9. */ + if (!(escaped_port_name = malloc(strlen(port->name) + 5))) + RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed"); + sprintf(escaped_port_name, "\\\\.\\%s", port->name); + + /* Map 'flags' to the OS-specific settings. */ + flags_and_attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED; + if (flags & SP_MODE_READ) + desired_access |= GENERIC_READ; + if (flags & SP_MODE_WRITE) + desired_access |= GENERIC_WRITE; + + port->hdl = CreateFileA(escaped_port_name, desired_access, 0, 0, + OPEN_EXISTING, flags_and_attributes, 0); + + free(escaped_port_name); + + if (port->hdl == INVALID_HANDLE_VALUE) + RETURN_FAIL("Port CreateFile() failed"); + + /* All timeouts initially disabled. */ + port->timeouts.ReadIntervalTimeout = 0; + port->timeouts.ReadTotalTimeoutMultiplier = 0; + port->timeouts.ReadTotalTimeoutConstant = 0; + port->timeouts.WriteTotalTimeoutMultiplier = 0; + port->timeouts.WriteTotalTimeoutConstant = 0; + + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) { + sp_close(port); + RETURN_FAIL("SetCommTimeouts() failed"); + } + + /* Prepare OVERLAPPED structures. */ +#define INIT_OVERLAPPED(ovl) do { \ + memset(&port->ovl, 0, sizeof(port->ovl)); \ + port->ovl.hEvent = INVALID_HANDLE_VALUE; \ + if ((port->ovl.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) \ + == INVALID_HANDLE_VALUE) { \ + sp_close(port); \ + RETURN_FAIL(#ovl "CreateEvent() failed"); \ + } \ +} while (0) + + INIT_OVERLAPPED(read_ovl); + INIT_OVERLAPPED(write_ovl); + INIT_OVERLAPPED(wait_ovl); + + /* Set event mask for RX and error events. */ + if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) { + sp_close(port); + RETURN_FAIL("SetCommMask() failed"); + } + + port->writing = FALSE; + port->wait_running = FALSE; + + ret = restart_wait(port); + + if (ret < 0) { + sp_close(port); + RETURN_CODEVAL(ret); + } +#else + int flags_local = O_NONBLOCK | O_NOCTTY | O_CLOEXEC; + + /* Map 'flags' to the OS-specific settings. */ + if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE) + flags_local |= O_RDWR; + else if (flags & SP_MODE_READ) + flags_local |= O_RDONLY; + else if (flags & SP_MODE_WRITE) + flags_local |= O_WRONLY; + + if ((port->fd = open(port->name, flags_local)) < 0) + RETURN_FAIL("open() failed"); + + /* + * On POSIX in the default case the file descriptor of a serial port + * is not opened exclusively. Therefore the settings of a port are + * overwritten if the serial port is opened a second time. Windows + * opens all serial ports exclusively. + * So the idea is to open the serial ports alike in the exclusive mode. + * + * ioctl(*, TIOCEXCL) defines the file descriptor as exclusive. So all + * further open calls on the serial port will fail. + * + * There is a race condition if two processes open the same serial + * port. None of the processes will notice the exclusive ownership of + * the other process because ioctl() doesn't return an error code if + * the file descriptor is already marked as exclusive. + * This can be solved with flock(). It returns an error if the file + * descriptor is already locked by another process. + */ +#ifdef HAVE_FLOCK + if (flock(port->fd, LOCK_EX | LOCK_NB) < 0) + RETURN_FAIL("flock() failed"); +#endif + +#ifdef TIOCEXCL + /* + * Before Linux 3.8 ioctl(*, TIOCEXCL) was not implemented and could + * lead to EINVAL or ENOTTY. + * These errors aren't fatal and can be ignored. + */ + if (ioctl(port->fd, TIOCEXCL) < 0 && errno != EINVAL && errno != ENOTTY) + RETURN_FAIL("ioctl() failed"); +#endif + +#endif + + ret = get_config(port, &data, &config); + + if (ret < 0) { + sp_close(port); + RETURN_CODEVAL(ret); + } + + /* + * Assume a default baudrate if the OS does not provide one. + * Cannot assign -1 here since Windows holds the baudrate in + * the DCB and does not configure the rate individually. + */ + if (config.baudrate == 0) { + config.baudrate = 9600; + } + + /* Set sane port settings. */ +#ifdef _WIN32 + data.dcb.fBinary = TRUE; + data.dcb.fDsrSensitivity = FALSE; + data.dcb.fErrorChar = FALSE; + data.dcb.fNull = FALSE; + data.dcb.fAbortOnError = FALSE; +#else + /* Turn off all fancy termios tricks, give us a raw channel. */ + data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL); +#ifdef IUCLC + data.term.c_iflag &= ~IUCLC; +#endif + data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET); +#ifdef OLCUC + data.term.c_oflag &= ~OLCUC; +#endif +#ifdef NLDLY + data.term.c_oflag &= ~NLDLY; +#endif +#ifdef CRDLY + data.term.c_oflag &= ~CRDLY; +#endif +#ifdef TABDLY + data.term.c_oflag &= ~TABDLY; +#endif +#ifdef BSDLY + data.term.c_oflag &= ~BSDLY; +#endif +#ifdef VTDLY + data.term.c_oflag &= ~VTDLY; +#endif +#ifdef FFDLY + data.term.c_oflag &= ~FFDLY; +#endif +#ifdef OFILL + data.term.c_oflag &= ~OFILL; +#endif + data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN); + data.term.c_cc[VMIN] = 0; + data.term.c_cc[VTIME] = 0; + + /* Ignore modem status lines; enable receiver; leave control lines alone on close. */ + data.term.c_cflag |= (CLOCAL | CREAD); + data.term.c_cflag &= ~(HUPCL); +#endif + +#ifdef _WIN32 + if (ClearCommError(port->hdl, &errors, &status) == 0) + RETURN_FAIL("ClearCommError() failed"); +#endif + + ret = set_config(port, &data, &config); + + if (ret < 0) { + sp_close(port); + RETURN_CODEVAL(ret); + } + + RETURN_OK(); +} + +SP_API enum sp_return sp_close(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); + + DEBUG_FMT("Closing port %s", port->name); + +#ifdef _WIN32 + /* Returns non-zero upon success, 0 upon failure. */ + if (CloseHandle(port->hdl) == 0) + RETURN_FAIL("Port CloseHandle() failed"); + port->hdl = INVALID_HANDLE_VALUE; + + /* Close event handles for overlapped structures. */ +#define CLOSE_OVERLAPPED(ovl) do { \ + if (port->ovl.hEvent != INVALID_HANDLE_VALUE && \ + CloseHandle(port->ovl.hEvent) == 0) \ + RETURN_FAIL(# ovl "event CloseHandle() failed"); \ +} while (0) + CLOSE_OVERLAPPED(read_ovl); + CLOSE_OVERLAPPED(write_ovl); + CLOSE_OVERLAPPED(wait_ovl); + + if (port->write_buf) { + free(port->write_buf); + port->write_buf = NULL; + } +#else + /* Returns 0 upon success, -1 upon failure. */ + if (close(port->fd) == -1) + RETURN_FAIL("close() failed"); + port->fd = -1; +#endif + + RETURN_OK(); +} + +SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) +{ + TRACE("%p, 0x%x", port, buffers); + + CHECK_OPEN_PORT(); + + if (buffers > SP_BUF_BOTH) + RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection"); + + const char *buffer_names[] = {"no", "input", "output", "both"}; + + DEBUG_FMT("Flushing %s buffers on port %s", + buffer_names[buffers], port->name); + +#ifdef _WIN32 + DWORD flags = 0; + if (buffers & SP_BUF_INPUT) + flags |= PURGE_RXCLEAR; + if (buffers & SP_BUF_OUTPUT) + flags |= PURGE_TXCLEAR; + + /* Returns non-zero upon success, 0 upon failure. */ + if (PurgeComm(port->hdl, flags) == 0) + RETURN_FAIL("PurgeComm() failed"); + + if (buffers & SP_BUF_INPUT) + TRY(restart_wait(port)); +#else + int flags = 0; + if (buffers == SP_BUF_BOTH) + flags = TCIOFLUSH; + else if (buffers == SP_BUF_INPUT) + flags = TCIFLUSH; + else if (buffers == SP_BUF_OUTPUT) + flags = TCOFLUSH; + + /* Returns 0 upon success, -1 upon failure. */ + if (tcflush(port->fd, flags) < 0) + RETURN_FAIL("tcflush() failed"); +#endif + RETURN_OK(); +} + +SP_API enum sp_return sp_drain(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); + + DEBUG_FMT("Draining port %s", port->name); + +#ifdef _WIN32 + /* Returns non-zero upon success, 0 upon failure. */ + if (FlushFileBuffers(port->hdl) == 0) + RETURN_FAIL("FlushFileBuffers() failed"); + RETURN_OK(); +#else + int result; + while (1) { +#if defined(__ANDROID__) && (__ANDROID_API__ < 21) + /* Android only has tcdrain from platform 21 onwards. + * On previous API versions, use the ioctl directly. */ + int arg = 1; + result = ioctl(port->fd, TCSBRK, &arg); +#else + result = tcdrain(port->fd); +#endif + if (result < 0) { + if (errno == EINTR) { + DEBUG("tcdrain() was interrupted"); + continue; + } else { + RETURN_FAIL("tcdrain() failed"); + } + } else { + RETURN_OK(); + } + } +#endif +} + +#ifdef _WIN32 +static enum sp_return await_write_completion(struct sp_port *port) +{ + TRACE("%p", port); + DWORD bytes_written; + BOOL result; + + /* Wait for previous non-blocking write to complete, if any. */ + if (port->writing) { + DEBUG("Waiting for previous write to complete"); + result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE); + port->writing = 0; + if (!result) + RETURN_FAIL("Previous write failed to complete"); + DEBUG("Previous write completed"); + } + + RETURN_OK(); +} +#endif + +SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, + size_t count, unsigned int timeout_ms) +{ + TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms); + + CHECK_OPEN_PORT(); + + if (!buf) + RETURN_ERROR(SP_ERR_ARG, "Null buffer"); + + if (timeout_ms) + DEBUG_FMT("Writing %d bytes to port %s, timeout %d ms", + count, port->name, timeout_ms); + else + DEBUG_FMT("Writing %d bytes to port %s, no timeout", + count, port->name); + + if (count == 0) + RETURN_INT(0); + +#ifdef _WIN32 + DWORD remaining_ms, write_size, bytes_written; + size_t remaining_bytes, total_bytes_written = 0; + const uint8_t *write_ptr = (uint8_t *) buf; + bool result; + struct timeout timeout; + + timeout_start(&timeout, timeout_ms); + + TRY(await_write_completion(port)); + + while (total_bytes_written < count) { + + if (timeout_check(&timeout)) + break; + + remaining_ms = timeout_remaining_ms(&timeout); + + if (port->timeouts.WriteTotalTimeoutConstant != remaining_ms) { + port->timeouts.WriteTotalTimeoutConstant = remaining_ms; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } + + /* Reduce write size if it exceeds the WriteFile limit. */ + remaining_bytes = count - total_bytes_written; + if (remaining_bytes > WRITEFILE_MAX_SIZE) + write_size = WRITEFILE_MAX_SIZE; + else + write_size = (DWORD) remaining_bytes; + + /* Start write. */ + + result = WriteFile(port->hdl, write_ptr, write_size, NULL, &port->write_ovl); + + timeout_update(&timeout); + + if (result) { + DEBUG("Write completed immediately"); + bytes_written = write_size; + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("Waiting for write to complete"); + if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) { + if (GetLastError() == ERROR_SEM_TIMEOUT) { + DEBUG("Write timed out"); + break; + } else { + RETURN_FAIL("GetOverlappedResult() failed"); + } + } + DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, write_size); + } else { + RETURN_FAIL("WriteFile() failed"); + } + + write_ptr += bytes_written; + total_bytes_written += bytes_written; + } + + RETURN_INT((int) total_bytes_written); +#else + size_t bytes_written = 0; + unsigned char *ptr = (unsigned char *) buf; + struct timeout timeout; + fd_set fds; + int result; + + timeout_start(&timeout, timeout_ms); + + FD_ZERO(&fds); + FD_SET(port->fd, &fds); + + /* Loop until we have written the requested number of bytes. */ + while (bytes_written < count) { + + if (timeout_check(&timeout)) + break; + + result = select(port->fd + 1, NULL, &fds, NULL, timeout_timeval(&timeout)); + + timeout_update(&timeout); + + if (result < 0) { + if (errno == EINTR) { + DEBUG("select() call was interrupted, repeating"); + continue; + } else { + RETURN_FAIL("select() failed"); + } + } else if (result == 0) { + /* Timeout has expired. */ + break; + } + + /* Do write. */ + result = write(port->fd, ptr, count - bytes_written); + + if (result < 0) { + if (errno == EAGAIN) + /* This shouldn't happen because we did a select() first, but handle anyway. */ + continue; + else + /* This is an actual failure. */ + RETURN_FAIL("write() failed"); + } + + bytes_written += result; + ptr += result; + } + + if (bytes_written < count) + DEBUG("Write timed out"); + + RETURN_INT(bytes_written); +#endif +} + +SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, + const void *buf, size_t count) +{ + TRACE("%p, %p, %d", port, buf, count); + + CHECK_OPEN_PORT(); + + if (!buf) + RETURN_ERROR(SP_ERR_ARG, "Null buffer"); + + DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name); + + if (count == 0) + RETURN_INT(0); + +#ifdef _WIN32 + size_t buf_bytes; + + /* Check whether previous write is complete. */ + if (port->writing) { + if (HasOverlappedIoCompleted(&port->write_ovl)) { + DEBUG("Previous write completed"); + port->writing = 0; + } else { + DEBUG("Previous write not complete"); + /* Can't take a new write until the previous one finishes. */ + RETURN_INT(0); + } + } + + /* Set timeout. */ + if (port->timeouts.WriteTotalTimeoutConstant != 0) { + port->timeouts.WriteTotalTimeoutConstant = 0; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } + + /* Reduce count if it exceeds the WriteFile limit. */ + if (count > WRITEFILE_MAX_SIZE) + count = WRITEFILE_MAX_SIZE; + + /* Copy data to our write buffer. */ + buf_bytes = min(port->write_buf_size, count); + memcpy(port->write_buf, buf, buf_bytes); + + /* Start asynchronous write. */ + if (WriteFile(port->hdl, port->write_buf, (DWORD) buf_bytes, NULL, &port->write_ovl) == 0) { + if (GetLastError() == ERROR_IO_PENDING) { + if ((port->writing = !HasOverlappedIoCompleted(&port->write_ovl))) + DEBUG("Asynchronous write completed immediately"); + else + DEBUG("Asynchronous write running"); + } else { + /* Actual failure of some kind. */ + RETURN_FAIL("WriteFile() failed"); + } + } + + DEBUG("All bytes written immediately"); + + RETURN_INT((int) buf_bytes); +#else + /* Returns the number of bytes written, or -1 upon failure. */ + ssize_t written = write(port->fd, buf, count); + + if (written < 0) { + if (errno == EAGAIN) + // Buffer is full, no bytes written. + RETURN_INT(0); + else + RETURN_FAIL("write() failed"); + } else { + RETURN_INT(written); + } +#endif +} + +#ifdef _WIN32 +/* Restart wait operation if buffer was emptied. */ +static enum sp_return restart_wait_if_needed(struct sp_port *port, unsigned int bytes_read) +{ + DWORD errors; + COMSTAT comstat; + + if (bytes_read == 0) + RETURN_OK(); + + if (ClearCommError(port->hdl, &errors, &comstat) == 0) + RETURN_FAIL("ClearCommError() failed"); + + if (comstat.cbInQue == 0) + TRY(restart_wait(port)); + + RETURN_OK(); +} +#endif + +SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, + size_t count, unsigned int timeout_ms) +{ + TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms); + + CHECK_OPEN_PORT(); + + if (!buf) + RETURN_ERROR(SP_ERR_ARG, "Null buffer"); + + if (timeout_ms) + DEBUG_FMT("Reading %d bytes from port %s, timeout %d ms", + count, port->name, timeout_ms); + else + DEBUG_FMT("Reading %d bytes from port %s, no timeout", + count, port->name); + + if (count == 0) + RETURN_INT(0); + +#ifdef _WIN32 + DWORD bytes_read; + + /* Set timeout. */ + if (port->timeouts.ReadIntervalTimeout != 0 || + port->timeouts.ReadTotalTimeoutMultiplier != 0 || + port->timeouts.ReadTotalTimeoutConstant != timeout_ms) { + port->timeouts.ReadIntervalTimeout = 0; + port->timeouts.ReadTotalTimeoutMultiplier = 0; + port->timeouts.ReadTotalTimeoutConstant = timeout_ms; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } + + /* Start read. */ + if (ReadFile(port->hdl, buf, (DWORD) count, NULL, &port->read_ovl)) { + DEBUG("Read completed immediately"); + bytes_read = (DWORD) count; + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("Waiting for read to complete"); + if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0) + RETURN_FAIL("GetOverlappedResult() failed"); + DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count); + } else { + RETURN_FAIL("ReadFile() failed"); + } + + TRY(restart_wait_if_needed(port, bytes_read)); + + RETURN_INT((int) bytes_read); + +#else + size_t bytes_read = 0; + unsigned char *ptr = (unsigned char *) buf; + struct timeout timeout; + fd_set fds; + int result; + + timeout_start(&timeout, timeout_ms); + + FD_ZERO(&fds); + FD_SET(port->fd, &fds); + + /* Loop until we have the requested number of bytes. */ + while (bytes_read < count) { + + if (timeout_check(&timeout)) + /* Timeout has expired. */ + break; + + result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout)); + + timeout_update(&timeout); + + if (result < 0) { + if (errno == EINTR) { + DEBUG("select() call was interrupted, repeating"); + continue; + } else { + RETURN_FAIL("select() failed"); + } + } else if (result == 0) { + /* Timeout has expired. */ + break; + } + + /* Do read. */ + result = read(port->fd, ptr, count - bytes_read); + + if (result < 0) { + if (errno == EAGAIN) + /* + * This shouldn't happen because we did a + * select() first, but handle anyway. + */ + continue; + else + /* This is an actual failure. */ + RETURN_FAIL("read() failed"); + } + + bytes_read += result; + ptr += result; + } + + if (bytes_read < count) + DEBUG("Read timed out"); + + RETURN_INT(bytes_read); +#endif +} + +SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, + size_t count, unsigned int timeout_ms) +{ + TRACE("%p, %p, %d, %d", port, buf, count, timeout_ms); + + CHECK_OPEN_PORT(); + + if (!buf) + RETURN_ERROR(SP_ERR_ARG, "Null buffer"); + + if (count == 0) + RETURN_ERROR(SP_ERR_ARG, "Zero count"); + + if (timeout_ms) + DEBUG_FMT("Reading next max %d bytes from port %s, timeout %d ms", + count, port->name, timeout_ms); + else + DEBUG_FMT("Reading next max %d bytes from port %s, no timeout", + count, port->name); + +#ifdef _WIN32 + DWORD bytes_read = 0; + + /* If timeout_ms == 0, set maximum timeout. */ + DWORD timeout_val = (timeout_ms == 0 ? MAXDWORD - 1 : timeout_ms); + + /* Set timeout. */ + if (port->timeouts.ReadIntervalTimeout != MAXDWORD || + port->timeouts.ReadTotalTimeoutMultiplier != MAXDWORD || + port->timeouts.ReadTotalTimeoutConstant != timeout_val) { + port->timeouts.ReadIntervalTimeout = MAXDWORD; + port->timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; + port->timeouts.ReadTotalTimeoutConstant = timeout_val; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } + + /* Loop until we have at least one byte, or timeout is reached. */ + while (bytes_read == 0) { + /* Start read. */ + if (ReadFile(port->hdl, buf, (DWORD) count, &bytes_read, &port->read_ovl)) { + DEBUG("Read completed immediately"); + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("Waiting for read to complete"); + if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0) + RETURN_FAIL("GetOverlappedResult() failed"); + if (bytes_read > 0) { + DEBUG("Read completed"); + } else if (timeout_ms > 0) { + DEBUG("Read timed out"); + break; + } else { + DEBUG("Restarting read"); + } + } else { + RETURN_FAIL("ReadFile() failed"); + } + } + + TRY(restart_wait_if_needed(port, bytes_read)); + + RETURN_INT(bytes_read); + +#else + size_t bytes_read = 0; + struct timeout timeout; + fd_set fds; + int result; + + timeout_start(&timeout, timeout_ms); + + FD_ZERO(&fds); + FD_SET(port->fd, &fds); + + /* Loop until we have at least one byte, or timeout is reached. */ + while (bytes_read == 0) { + + if (timeout_check(&timeout)) + /* Timeout has expired. */ + break; + + result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout)); + + timeout_update(&timeout); + + if (result < 0) { + if (errno == EINTR) { + DEBUG("select() call was interrupted, repeating"); + continue; + } else { + RETURN_FAIL("select() failed"); + } + } else if (result == 0) { + /* Timeout has expired. */ + break; + } + + /* Do read. */ + result = read(port->fd, buf, count); + + if (result < 0) { + if (errno == EAGAIN) + /* This shouldn't happen because we did a select() first, but handle anyway. */ + continue; + else + /* This is an actual failure. */ + RETURN_FAIL("read() failed"); + } + + bytes_read = result; + } + + if (bytes_read == 0) + DEBUG("Read timed out"); + + RETURN_INT(bytes_read); +#endif +} + +SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, + size_t count) +{ + TRACE("%p, %p, %d", port, buf, count); + + CHECK_OPEN_PORT(); + + if (!buf) + RETURN_ERROR(SP_ERR_ARG, "Null buffer"); + + DEBUG_FMT("Reading up to %d bytes from port %s", count, port->name); + +#ifdef _WIN32 + DWORD bytes_read; + + /* Set timeout. */ + if (port->timeouts.ReadIntervalTimeout != MAXDWORD || + port->timeouts.ReadTotalTimeoutMultiplier != 0 || + port->timeouts.ReadTotalTimeoutConstant != 0) { + port->timeouts.ReadIntervalTimeout = MAXDWORD; + port->timeouts.ReadTotalTimeoutMultiplier = 0; + port->timeouts.ReadTotalTimeoutConstant = 0; + if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) + RETURN_FAIL("SetCommTimeouts() failed"); + } + + /* Do read. */ + if (ReadFile(port->hdl, buf, (DWORD) count, NULL, &port->read_ovl) == 0) + if (GetLastError() != ERROR_IO_PENDING) + RETURN_FAIL("ReadFile() failed"); + + /* Get number of bytes read. */ + if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, FALSE) == 0) + RETURN_FAIL("GetOverlappedResult() failed"); + + TRY(restart_wait_if_needed(port, bytes_read)); + + RETURN_INT(bytes_read); +#else + ssize_t bytes_read; + + /* Returns the number of bytes read, or -1 upon failure. */ + if ((bytes_read = read(port->fd, buf, count)) < 0) { + if (errno == EAGAIN) + /* No bytes available. */ + bytes_read = 0; + else + /* This is an actual failure. */ + RETURN_FAIL("read() failed"); + } + RETURN_INT(bytes_read); +#endif +} + +SP_API enum sp_return sp_input_waiting(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); + + DEBUG_FMT("Checking input bytes waiting on port %s", port->name); + +#ifdef _WIN32 + DWORD errors; + COMSTAT comstat; + + if (ClearCommError(port->hdl, &errors, &comstat) == 0) + RETURN_FAIL("ClearCommError() failed"); + RETURN_INT(comstat.cbInQue); +#else + int bytes_waiting; + if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0) + RETURN_FAIL("TIOCINQ ioctl failed"); + RETURN_INT(bytes_waiting); +#endif +} + +SP_API enum sp_return sp_output_waiting(struct sp_port *port) +{ + TRACE("%p", port); + +#ifdef __CYGWIN__ + /* TIOCOUTQ is not defined in Cygwin headers */ + RETURN_ERROR(SP_ERR_SUPP, + "Getting output bytes waiting is not supported on Cygwin"); +#else + CHECK_OPEN_PORT(); + + DEBUG_FMT("Checking output bytes waiting on port %s", port->name); + +#ifdef _WIN32 + DWORD errors; + COMSTAT comstat; + + if (ClearCommError(port->hdl, &errors, &comstat) == 0) + RETURN_FAIL("ClearCommError() failed"); + RETURN_INT(comstat.cbOutQue); +#else + int bytes_waiting; + if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0) + RETURN_FAIL("TIOCOUTQ ioctl failed"); + RETURN_INT(bytes_waiting); +#endif +#endif +} + +SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr) +{ + struct sp_event_set *result; + + TRACE("%p", result_ptr); + + if (!result_ptr) + RETURN_ERROR(SP_ERR_ARG, "Null result"); + + *result_ptr = NULL; + + if (!(result = malloc(sizeof(struct sp_event_set)))) + RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed"); + + memset(result, 0, sizeof(struct sp_event_set)); + + *result_ptr = result; + + RETURN_OK(); +} + +static enum sp_return add_handle(struct sp_event_set *event_set, + event_handle handle, enum sp_event mask) +{ + void *new_handles; + enum sp_event *new_masks; + + TRACE("%p, %d, %d", event_set, handle, mask); + + if (!(new_handles = realloc(event_set->handles, + sizeof(event_handle) * (event_set->count + 1)))) + RETURN_ERROR(SP_ERR_MEM, "Handle array realloc() failed"); + + event_set->handles = new_handles; + + if (!(new_masks = realloc(event_set->masks, + sizeof(enum sp_event) * (event_set->count + 1)))) + RETURN_ERROR(SP_ERR_MEM, "Mask array realloc() failed"); + + event_set->masks = new_masks; + + ((event_handle *) event_set->handles)[event_set->count] = handle; + event_set->masks[event_set->count] = mask; + + event_set->count++; + + RETURN_OK(); +} + +SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set, + const struct sp_port *port, enum sp_event mask) +{ + TRACE("%p, %p, %d", event_set, port, mask); + + if (!event_set) + RETURN_ERROR(SP_ERR_ARG, "Null event set"); + + if (!port) + RETURN_ERROR(SP_ERR_ARG, "Null port"); + + if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR)) + RETURN_ERROR(SP_ERR_ARG, "Invalid event mask"); + + if (!mask) + RETURN_OK(); + +#ifdef _WIN32 + enum sp_event handle_mask; + if ((handle_mask = mask & SP_EVENT_TX_READY)) + TRY(add_handle(event_set, port->write_ovl.hEvent, handle_mask)); + if ((handle_mask = mask & (SP_EVENT_RX_READY | SP_EVENT_ERROR))) + TRY(add_handle(event_set, port->wait_ovl.hEvent, handle_mask)); +#else + TRY(add_handle(event_set, port->fd, mask)); +#endif + + RETURN_OK(); +} + +SP_API void sp_free_event_set(struct sp_event_set *event_set) +{ + TRACE("%p", event_set); + + if (!event_set) { + DEBUG("Null event set"); + RETURN(); + } + + DEBUG("Freeing event set"); + + if (event_set->handles) + free(event_set->handles); + if (event_set->masks) + free(event_set->masks); + + free(event_set); + + RETURN(); +} + +SP_API enum sp_return sp_wait(struct sp_event_set *event_set, + unsigned int timeout_ms) +{ + TRACE("%p, %d", event_set, timeout_ms); + + if (!event_set) + RETURN_ERROR(SP_ERR_ARG, "Null event set"); + +#ifdef _WIN32 + if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE, + timeout_ms ? timeout_ms : INFINITE) == WAIT_FAILED) + RETURN_FAIL("WaitForMultipleObjects() failed"); + + RETURN_OK(); +#else + struct timeout timeout; + int poll_timeout; + int result; + struct pollfd *pollfds; + unsigned int i; + + if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count))) + RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed"); + + for (i = 0; i < event_set->count; i++) { + pollfds[i].fd = ((int *)event_set->handles)[i]; + pollfds[i].events = 0; + pollfds[i].revents = 0; + if (event_set->masks[i] & SP_EVENT_RX_READY) + pollfds[i].events |= POLLIN; + if (event_set->masks[i] & SP_EVENT_TX_READY) + pollfds[i].events |= POLLOUT; + if (event_set->masks[i] & SP_EVENT_ERROR) + pollfds[i].events |= POLLERR; + } + + timeout_start(&timeout, timeout_ms); + timeout_limit(&timeout, INT_MAX); + + /* Loop until an event occurs. */ + while (1) { + + if (timeout_check(&timeout)) { + DEBUG("Wait timed out"); + break; + } + + poll_timeout = (int) timeout_remaining_ms(&timeout); + if (poll_timeout == 0) + poll_timeout = -1; + + result = poll(pollfds, event_set->count, poll_timeout); + + timeout_update(&timeout); + + if (result < 0) { + if (errno == EINTR) { + DEBUG("poll() call was interrupted, repeating"); + continue; + } else { + free(pollfds); + RETURN_FAIL("poll() failed"); + } + } else if (result == 0) { + DEBUG("poll() timed out"); + if (!timeout.overflow) + break; + } else { + DEBUG("poll() completed"); + break; + } + } + + free(pollfds); + RETURN_OK(); +#endif +} + +#ifdef USE_TERMIOS_SPEED +static enum sp_return get_baudrate(int fd, int *baudrate) +{ + void *data; + + TRACE("%d, %p", fd, baudrate); + + DEBUG("Getting baud rate"); + + if (!(data = malloc(get_termios_size()))) + RETURN_ERROR(SP_ERR_MEM, "termios malloc failed"); + + if (ioctl(fd, get_termios_get_ioctl(), data) < 0) { + free(data); + RETURN_FAIL("Getting termios failed"); + } + + *baudrate = get_termios_speed(data); + + free(data); + + RETURN_OK(); +} + +static enum sp_return set_baudrate(int fd, int baudrate) +{ + void *data; + + TRACE("%d, %d", fd, baudrate); + + DEBUG("Getting baud rate"); + + if (!(data = malloc(get_termios_size()))) + RETURN_ERROR(SP_ERR_MEM, "termios malloc failed"); + + if (ioctl(fd, get_termios_get_ioctl(), data) < 0) { + free(data); + RETURN_FAIL("Getting termios failed"); + } + + DEBUG("Setting baud rate"); + + set_termios_speed(data, baudrate); + + if (ioctl(fd, get_termios_set_ioctl(), data) < 0) { + free(data); + RETURN_FAIL("Setting termios failed"); + } + + free(data); + + RETURN_OK(); +} +#endif /* USE_TERMIOS_SPEED */ + +#ifdef USE_TERMIOX +static enum sp_return get_flow(int fd, struct port_data *data) +{ + void *termx; + + TRACE("%d, %p", fd, data); + + DEBUG("Getting advanced flow control"); + + if (!(termx = malloc(get_termiox_size()))) + RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed"); + + if (ioctl(fd, TCGETX, termx) < 0) { + free(termx); + RETURN_FAIL("Getting termiox failed"); + } + + get_termiox_flow(termx, &data->rts_flow, &data->cts_flow, + &data->dtr_flow, &data->dsr_flow); + + free(termx); + + RETURN_OK(); +} + +static enum sp_return set_flow(int fd, struct port_data *data) +{ + void *termx; + + TRACE("%d, %p", fd, data); + + DEBUG("Getting advanced flow control"); + + if (!(termx = malloc(get_termiox_size()))) + RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed"); + + if (ioctl(fd, TCGETX, termx) < 0) { + free(termx); + RETURN_FAIL("Getting termiox failed"); + } + + DEBUG("Setting advanced flow control"); + + set_termiox_flow(termx, data->rts_flow, data->cts_flow, + data->dtr_flow, data->dsr_flow); + + if (ioctl(fd, TCSETX, termx) < 0) { + free(termx); + RETURN_FAIL("Setting termiox failed"); + } + + free(termx); + + RETURN_OK(); +} +#endif /* USE_TERMIOX */ + +static enum sp_return get_config(struct sp_port *port, struct port_data *data, + struct sp_port_config *config) +{ + unsigned int i; + + TRACE("%p, %p, %p", port, data, config); + + DEBUG_FMT("Getting configuration for port %s", port->name); + +#ifdef _WIN32 + if (!GetCommState(port->hdl, &data->dcb)) + RETURN_FAIL("GetCommState() failed"); + + for (i = 0; i < NUM_STD_BAUDRATES; i++) { + if (data->dcb.BaudRate == std_baudrates[i].index) { + config->baudrate = std_baudrates[i].value; + break; + } + } + + if (i == NUM_STD_BAUDRATES) + /* BaudRate field can be either an index or a custom baud rate. */ + config->baudrate = data->dcb.BaudRate; + + config->bits = data->dcb.ByteSize; + + switch (data->dcb.Parity) { + case NOPARITY: + config->parity = SP_PARITY_NONE; + break; + case ODDPARITY: + config->parity = SP_PARITY_ODD; + break; + case EVENPARITY: + config->parity = SP_PARITY_EVEN; + break; + case MARKPARITY: + config->parity = SP_PARITY_MARK; + break; + case SPACEPARITY: + config->parity = SP_PARITY_SPACE; + break; + default: + config->parity = -1; + } + + switch (data->dcb.StopBits) { + case ONESTOPBIT: + config->stopbits = 1; + break; + case TWOSTOPBITS: + config->stopbits = 2; + break; + default: + config->stopbits = -1; + } + + switch (data->dcb.fRtsControl) { + case RTS_CONTROL_DISABLE: + config->rts = SP_RTS_OFF; + break; + case RTS_CONTROL_ENABLE: + config->rts = SP_RTS_ON; + break; + case RTS_CONTROL_HANDSHAKE: + config->rts = SP_RTS_FLOW_CONTROL; + break; + default: + config->rts = -1; + } + + config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE; + + switch (data->dcb.fDtrControl) { + case DTR_CONTROL_DISABLE: + config->dtr = SP_DTR_OFF; + break; + case DTR_CONTROL_ENABLE: + config->dtr = SP_DTR_ON; + break; + case DTR_CONTROL_HANDSHAKE: + config->dtr = SP_DTR_FLOW_CONTROL; + break; + default: + config->dtr = -1; + } + + config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; + + if (data->dcb.fInX) { + if (data->dcb.fOutX) + config->xon_xoff = SP_XONXOFF_INOUT; + else + config->xon_xoff = SP_XONXOFF_IN; + } else { + if (data->dcb.fOutX) + config->xon_xoff = SP_XONXOFF_OUT; + else + config->xon_xoff = SP_XONXOFF_DISABLED; + } + +#else // !_WIN32 + + if (tcgetattr(port->fd, &data->term) < 0) + RETURN_FAIL("tcgetattr() failed"); + + if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0) + RETURN_FAIL("TIOCMGET ioctl failed"); + +#ifdef USE_TERMIOX + int ret = get_flow(port->fd, data); + + if (ret == SP_ERR_FAIL && errno == EINVAL) + data->termiox_supported = 0; + else if (ret < 0) + RETURN_CODEVAL(ret); + else + data->termiox_supported = 1; +#else + data->termiox_supported = 0; +#endif + + for (i = 0; i < NUM_STD_BAUDRATES; i++) { + if (cfgetispeed(&data->term) == std_baudrates[i].index) { + config->baudrate = std_baudrates[i].value; + break; + } + } + + if (i == NUM_STD_BAUDRATES) { +#ifdef __APPLE__ + config->baudrate = (int)data->term.c_ispeed; +#elif defined(USE_TERMIOS_SPEED) + TRY(get_baudrate(port->fd, &config->baudrate)); +#else + config->baudrate = -1; +#endif + } + + switch (data->term.c_cflag & CSIZE) { + case CS8: + config->bits = 8; + break; + case CS7: + config->bits = 7; + break; + case CS6: + config->bits = 6; + break; + case CS5: + config->bits = 5; + break; + default: + config->bits = -1; + } + + if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR)) + config->parity = SP_PARITY_NONE; + else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR)) + config->parity = -1; +#ifdef CMSPAR + else if (data->term.c_cflag & CMSPAR) + config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE; +#endif + else + config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN; + + config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1; + + if (data->term.c_cflag & CRTSCTS) { + config->rts = SP_RTS_FLOW_CONTROL; + config->cts = SP_CTS_FLOW_CONTROL; + } else { + if (data->termiox_supported && data->rts_flow) + config->rts = SP_RTS_FLOW_CONTROL; + else + config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF; + + config->cts = (data->termiox_supported && data->cts_flow) ? + SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE; + } + + if (data->termiox_supported && data->dtr_flow) + config->dtr = SP_DTR_FLOW_CONTROL; + else + config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF; + + config->dsr = (data->termiox_supported && data->dsr_flow) ? + SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE; + + if (data->term.c_iflag & IXOFF) { + if (data->term.c_iflag & IXON) + config->xon_xoff = SP_XONXOFF_INOUT; + else + config->xon_xoff = SP_XONXOFF_IN; + } else { + if (data->term.c_iflag & IXON) + config->xon_xoff = SP_XONXOFF_OUT; + else + config->xon_xoff = SP_XONXOFF_DISABLED; + } +#endif + + RETURN_OK(); +} + +static enum sp_return set_config(struct sp_port *port, struct port_data *data, + const struct sp_port_config *config) +{ + unsigned int i; +#ifdef __APPLE__ + BAUD_TYPE baud_nonstd; + + baud_nonstd = B0; +#endif +#ifdef USE_TERMIOS_SPEED + int baud_nonstd = 0; +#endif + + TRACE("%p, %p, %p", port, data, config); + + DEBUG_FMT("Setting configuration for port %s", port->name); + +#ifdef _WIN32 + BYTE* new_buf; + + TRY(await_write_completion(port)); + + if (config->baudrate >= 0) { + for (i = 0; i < NUM_STD_BAUDRATES; i++) { + if (config->baudrate == std_baudrates[i].value) { + data->dcb.BaudRate = std_baudrates[i].index; + break; + } + } + + if (i == NUM_STD_BAUDRATES) + data->dcb.BaudRate = config->baudrate; + + /* Allocate write buffer for 50ms of data at baud rate. */ + port->write_buf_size = max(config->baudrate / (8 * 20), 1); + new_buf = realloc(port->write_buf, port->write_buf_size); + if (!new_buf) + RETURN_ERROR(SP_ERR_MEM, "Allocating write buffer failed"); + port->write_buf = new_buf; + } + + if (config->bits >= 0) + data->dcb.ByteSize = config->bits; + + if (config->parity >= 0) { + switch (config->parity) { + case SP_PARITY_NONE: + data->dcb.Parity = NOPARITY; + break; + case SP_PARITY_ODD: + data->dcb.Parity = ODDPARITY; + break; + case SP_PARITY_EVEN: + data->dcb.Parity = EVENPARITY; + break; + case SP_PARITY_MARK: + data->dcb.Parity = MARKPARITY; + break; + case SP_PARITY_SPACE: + data->dcb.Parity = SPACEPARITY; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting"); + } + } + + if (config->stopbits >= 0) { + switch (config->stopbits) { + /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */ + case 1: + data->dcb.StopBits = ONESTOPBIT; + break; + case 2: + data->dcb.StopBits = TWOSTOPBITS; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting"); + } + } + + if (config->rts >= 0) { + switch (config->rts) { + case SP_RTS_OFF: + data->dcb.fRtsControl = RTS_CONTROL_DISABLE; + break; + case SP_RTS_ON: + data->dcb.fRtsControl = RTS_CONTROL_ENABLE; + break; + case SP_RTS_FLOW_CONTROL: + data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting"); + } + } + + if (config->cts >= 0) { + switch (config->cts) { + case SP_CTS_IGNORE: + data->dcb.fOutxCtsFlow = FALSE; + break; + case SP_CTS_FLOW_CONTROL: + data->dcb.fOutxCtsFlow = TRUE; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting"); + } + } + + if (config->dtr >= 0) { + switch (config->dtr) { + case SP_DTR_OFF: + data->dcb.fDtrControl = DTR_CONTROL_DISABLE; + break; + case SP_DTR_ON: + data->dcb.fDtrControl = DTR_CONTROL_ENABLE; + break; + case SP_DTR_FLOW_CONTROL: + data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting"); + } + } + + if (config->dsr >= 0) { + switch (config->dsr) { + case SP_DSR_IGNORE: + data->dcb.fOutxDsrFlow = FALSE; + break; + case SP_DSR_FLOW_CONTROL: + data->dcb.fOutxDsrFlow = TRUE; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting"); + } + } + + if (config->xon_xoff >= 0) { + switch (config->xon_xoff) { + case SP_XONXOFF_DISABLED: + data->dcb.fInX = FALSE; + data->dcb.fOutX = FALSE; + break; + case SP_XONXOFF_IN: + data->dcb.fInX = TRUE; + data->dcb.fOutX = FALSE; + break; + case SP_XONXOFF_OUT: + data->dcb.fInX = FALSE; + data->dcb.fOutX = TRUE; + break; + case SP_XONXOFF_INOUT: + data->dcb.fInX = TRUE; + data->dcb.fOutX = TRUE; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting"); + } + } + + if (!SetCommState(port->hdl, &data->dcb)) + RETURN_FAIL("SetCommState() failed"); + +#else /* !_WIN32 */ + + int controlbits; + + if (config->baudrate >= 0) { + for (i = 0; i < NUM_STD_BAUDRATES; i++) { + if (config->baudrate == std_baudrates[i].value) { + if (cfsetospeed(&data->term, std_baudrates[i].index) < 0) + RETURN_FAIL("cfsetospeed() failed"); + + if (cfsetispeed(&data->term, std_baudrates[i].index) < 0) + RETURN_FAIL("cfsetispeed() failed"); + break; + } + } + + /* Non-standard baud rate */ + if (i == NUM_STD_BAUDRATES) { +#ifdef __APPLE__ + /* Set "dummy" baud rate. */ + if (cfsetspeed(&data->term, B9600) < 0) + RETURN_FAIL("cfsetspeed() failed"); + baud_nonstd = config->baudrate; +#elif defined(USE_TERMIOS_SPEED) + baud_nonstd = 1; +#else + RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported"); +#endif + } + } + + if (config->bits >= 0) { + data->term.c_cflag &= ~CSIZE; + switch (config->bits) { + case 8: + data->term.c_cflag |= CS8; + break; + case 7: + data->term.c_cflag |= CS7; + break; + case 6: + data->term.c_cflag |= CS6; + break; + case 5: + data->term.c_cflag |= CS5; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting"); + } + } + + if (config->parity >= 0) { + data->term.c_iflag &= ~IGNPAR; + data->term.c_cflag &= ~(PARENB | PARODD); +#ifdef CMSPAR + data->term.c_cflag &= ~CMSPAR; +#endif + switch (config->parity) { + case SP_PARITY_NONE: + data->term.c_iflag |= IGNPAR; + break; + case SP_PARITY_EVEN: + data->term.c_cflag |= PARENB; + break; + case SP_PARITY_ODD: + data->term.c_cflag |= PARENB | PARODD; + break; +#ifdef CMSPAR + case SP_PARITY_MARK: + data->term.c_cflag |= PARENB | PARODD; + data->term.c_cflag |= CMSPAR; + break; + case SP_PARITY_SPACE: + data->term.c_cflag |= PARENB; + data->term.c_cflag |= CMSPAR; + break; +#else + case SP_PARITY_MARK: + case SP_PARITY_SPACE: + RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported"); +#endif + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting"); + } + } + + if (config->stopbits >= 0) { + data->term.c_cflag &= ~CSTOPB; + switch (config->stopbits) { + case 1: + data->term.c_cflag &= ~CSTOPB; + break; + case 2: + data->term.c_cflag |= CSTOPB; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting"); + } + } + + if (config->rts >= 0 || config->cts >= 0) { + if (data->termiox_supported) { + data->rts_flow = data->cts_flow = 0; + switch (config->rts) { + case SP_RTS_OFF: + case SP_RTS_ON: + controlbits = TIOCM_RTS; + if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0) + RETURN_FAIL("Setting RTS signal level failed"); + break; + case SP_RTS_FLOW_CONTROL: + data->rts_flow = 1; + break; + default: + break; + } + if (config->cts == SP_CTS_FLOW_CONTROL) + data->cts_flow = 1; + + if (data->rts_flow && data->cts_flow) + data->term.c_iflag |= CRTSCTS; + else + data->term.c_iflag &= ~CRTSCTS; + } else { + /* Asymmetric use of RTS/CTS not supported. */ + if (data->term.c_iflag & CRTSCTS) { + /* Flow control can only be disabled for both RTS & CTS together. */ + if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) { + if (config->cts != SP_CTS_IGNORE) + RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together"); + } + if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) { + if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL) + RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together"); + } + } else { + /* Flow control can only be enabled for both RTS & CTS together. */ + if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) || + ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL))) + RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together"); + } + + if (config->rts >= 0) { + if (config->rts == SP_RTS_FLOW_CONTROL) { + data->term.c_iflag |= CRTSCTS; + } else { + controlbits = TIOCM_RTS; + if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, + &controlbits) < 0) + RETURN_FAIL("Setting RTS signal level failed"); + } + } + } + } + + if (config->dtr >= 0 || config->dsr >= 0) { + if (data->termiox_supported) { + data->dtr_flow = data->dsr_flow = 0; + switch (config->dtr) { + case SP_DTR_OFF: + case SP_DTR_ON: + controlbits = TIOCM_DTR; + if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0) + RETURN_FAIL("Setting DTR signal level failed"); + break; + case SP_DTR_FLOW_CONTROL: + data->dtr_flow = 1; + break; + default: + break; + } + if (config->dsr == SP_DSR_FLOW_CONTROL) + data->dsr_flow = 1; + } else { + /* DTR/DSR flow control not supported. */ + if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL) + RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported"); + + if (config->dtr >= 0) { + controlbits = TIOCM_DTR; + if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, + &controlbits) < 0) + RETURN_FAIL("Setting DTR signal level failed"); + } + } + } + + if (config->xon_xoff >= 0) { + data->term.c_iflag &= ~(IXON | IXOFF | IXANY); + switch (config->xon_xoff) { + case SP_XONXOFF_DISABLED: + break; + case SP_XONXOFF_IN: + data->term.c_iflag |= IXOFF; + break; + case SP_XONXOFF_OUT: + data->term.c_iflag |= IXON | IXANY; + break; + case SP_XONXOFF_INOUT: + data->term.c_iflag |= IXON | IXOFF | IXANY; + break; + default: + RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting"); + } + } + + if (tcsetattr(port->fd, TCSANOW, &data->term) < 0) + RETURN_FAIL("tcsetattr() failed"); + +#ifdef __APPLE__ + if (baud_nonstd != B0) { + if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1) + RETURN_FAIL("IOSSIOSPEED ioctl failed"); + /* + * Set baud rates in data->term to correct, but incompatible + * with tcsetattr() value, same as delivered by tcgetattr(). + */ + if (cfsetspeed(&data->term, baud_nonstd) < 0) + RETURN_FAIL("cfsetspeed() failed"); + } +#elif defined(__linux__) +#ifdef USE_TERMIOS_SPEED + if (baud_nonstd) + TRY(set_baudrate(port->fd, config->baudrate)); +#endif +#ifdef USE_TERMIOX + if (data->termiox_supported) + TRY(set_flow(port->fd, data)); +#endif +#endif + +#endif /* !_WIN32 */ + + RETURN_OK(); +} + +SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr) +{ + struct sp_port_config *config; + + TRACE("%p", config_ptr); + + if (!config_ptr) + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + + *config_ptr = NULL; + + if (!(config = malloc(sizeof(struct sp_port_config)))) + RETURN_ERROR(SP_ERR_MEM, "Config malloc failed"); + + config->baudrate = -1; + config->bits = -1; + config->parity = -1; + config->stopbits = -1; + config->rts = -1; + config->cts = -1; + config->dtr = -1; + config->dsr = -1; + + *config_ptr = config; + + RETURN_OK(); +} + +SP_API void sp_free_config(struct sp_port_config *config) +{ + TRACE("%p", config); + + if (!config) + DEBUG("Null config"); + else + free(config); + + RETURN(); +} + +SP_API enum sp_return sp_get_config(struct sp_port *port, + struct sp_port_config *config) +{ + struct port_data data; + + TRACE("%p, %p", port, config); + + CHECK_OPEN_PORT(); + + if (!config) + RETURN_ERROR(SP_ERR_ARG, "Null config"); + + TRY(get_config(port, &data, config)); + + RETURN_OK(); +} + +SP_API enum sp_return sp_set_config(struct sp_port *port, + const struct sp_port_config *config) +{ + struct port_data data; + struct sp_port_config prev_config; + + TRACE("%p, %p", port, config); + + CHECK_OPEN_PORT(); + + if (!config) + RETURN_ERROR(SP_ERR_ARG, "Null config"); + + TRY(get_config(port, &data, &prev_config)); + TRY(set_config(port, &data, config)); + + RETURN_OK(); +} + +#define CREATE_ACCESSORS(x, type) \ +SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \ + struct port_data data; \ + struct sp_port_config config; \ + TRACE("%p, %d", port, x); \ + CHECK_OPEN_PORT(); \ + TRY(get_config(port, &data, &config)); \ + config.x = x; \ + TRY(set_config(port, &data, &config)); \ + RETURN_OK(); \ +} \ +SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \ + type *x) { \ + TRACE("%p, %p", config, x); \ + if (!x) \ + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); \ + if (!config) \ + RETURN_ERROR(SP_ERR_ARG, "Null config"); \ + *x = config->x; \ + RETURN_OK(); \ +} \ +SP_API enum sp_return sp_set_config_##x(struct sp_port_config *config, \ + type x) { \ + TRACE("%p, %d", config, x); \ + if (!config) \ + RETURN_ERROR(SP_ERR_ARG, "Null config"); \ + config->x = x; \ + RETURN_OK(); \ +} + +CREATE_ACCESSORS(baudrate, int) +CREATE_ACCESSORS(bits, int) +CREATE_ACCESSORS(parity, enum sp_parity) +CREATE_ACCESSORS(stopbits, int) +CREATE_ACCESSORS(rts, enum sp_rts) +CREATE_ACCESSORS(cts, enum sp_cts) +CREATE_ACCESSORS(dtr, enum sp_dtr) +CREATE_ACCESSORS(dsr, enum sp_dsr) +CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff) + +SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, + enum sp_flowcontrol flowcontrol) +{ + if (!config) + RETURN_ERROR(SP_ERR_ARG, "Null configuration"); + + if (flowcontrol > SP_FLOWCONTROL_DTRDSR) + RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting"); + + if (flowcontrol == SP_FLOWCONTROL_XONXOFF) + config->xon_xoff = SP_XONXOFF_INOUT; + else + config->xon_xoff = SP_XONXOFF_DISABLED; + + if (flowcontrol == SP_FLOWCONTROL_RTSCTS) { + config->rts = SP_RTS_FLOW_CONTROL; + config->cts = SP_CTS_FLOW_CONTROL; + } else { + if (config->rts == SP_RTS_FLOW_CONTROL) + config->rts = SP_RTS_ON; + config->cts = SP_CTS_IGNORE; + } + + if (flowcontrol == SP_FLOWCONTROL_DTRDSR) { + config->dtr = SP_DTR_FLOW_CONTROL; + config->dsr = SP_DSR_FLOW_CONTROL; + } else { + if (config->dtr == SP_DTR_FLOW_CONTROL) + config->dtr = SP_DTR_ON; + config->dsr = SP_DSR_IGNORE; + } + + RETURN_OK(); +} + +SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port, + enum sp_flowcontrol flowcontrol) +{ + struct port_data data; + struct sp_port_config config; + + TRACE("%p, %d", port, flowcontrol); + + CHECK_OPEN_PORT(); + + TRY(get_config(port, &data, &config)); + + TRY(sp_set_config_flowcontrol(&config, flowcontrol)); + + TRY(set_config(port, &data, &config)); + + RETURN_OK(); +} + +SP_API enum sp_return sp_get_signals(struct sp_port *port, + enum sp_signal *signals) +{ + TRACE("%p, %p", port, signals); + + CHECK_OPEN_PORT(); + + if (!signals) + RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); + + DEBUG_FMT("Getting control signals for port %s", port->name); + + *signals = 0; +#ifdef _WIN32 + DWORD bits; + if (GetCommModemStatus(port->hdl, &bits) == 0) + RETURN_FAIL("GetCommModemStatus() failed"); + if (bits & MS_CTS_ON) + *signals |= SP_SIG_CTS; + if (bits & MS_DSR_ON) + *signals |= SP_SIG_DSR; + if (bits & MS_RLSD_ON) + *signals |= SP_SIG_DCD; + if (bits & MS_RING_ON) + *signals |= SP_SIG_RI; +#else + int bits; + if (ioctl(port->fd, TIOCMGET, &bits) < 0) + RETURN_FAIL("TIOCMGET ioctl failed"); + if (bits & TIOCM_CTS) + *signals |= SP_SIG_CTS; + if (bits & TIOCM_DSR) + *signals |= SP_SIG_DSR; + if (bits & TIOCM_CAR) + *signals |= SP_SIG_DCD; + if (bits & TIOCM_RNG) + *signals |= SP_SIG_RI; +#endif + RETURN_OK(); +} + +SP_API enum sp_return sp_start_break(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); +#ifdef _WIN32 + if (SetCommBreak(port->hdl) == 0) + RETURN_FAIL("SetCommBreak() failed"); +#else + if (ioctl(port->fd, TIOCSBRK, 1) < 0) + RETURN_FAIL("TIOCSBRK ioctl failed"); +#endif + + RETURN_OK(); +} + +SP_API enum sp_return sp_end_break(struct sp_port *port) +{ + TRACE("%p", port); + + CHECK_OPEN_PORT(); +#ifdef _WIN32 + if (ClearCommBreak(port->hdl) == 0) + RETURN_FAIL("ClearCommBreak() failed"); +#else + if (ioctl(port->fd, TIOCCBRK, 1) < 0) + RETURN_FAIL("TIOCCBRK ioctl failed"); +#endif + + RETURN_OK(); +} + +SP_API int sp_last_error_code(void) +{ + TRACE_VOID(); +#ifdef _WIN32 + RETURN_INT(GetLastError()); +#else + RETURN_INT(errno); +#endif +} + +SP_API char *sp_last_error_message(void) +{ + TRACE_VOID(); + +#ifdef _WIN32 + char *message; + DWORD error = GetLastError(); + + DWORD length = FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &message, + 0, NULL ); + + if (length >= 2 && message[length - 2] == '\r') + message[length - 2] = '\0'; + + RETURN_STRING(message); +#else + RETURN_STRING(strerror(errno)); +#endif +} + +SP_API void sp_free_error_message(char *message) +{ + TRACE("%s", message); + +#ifdef _WIN32 + LocalFree(message); +#else + (void)message; +#endif + + RETURN(); +} + +SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...)) +{ + TRACE("%p", handler); + + sp_debug_handler = handler; + + RETURN(); +} + +SP_API void sp_default_debug_handler(const char *format, ...) +{ + va_list args; + va_start(args, format); + if (getenv("LIBSERIALPORT_DEBUG")) { + fputs("sp: ", stderr); + vfprintf(stderr, format, args); + } + va_end(args); +} + +SP_API int sp_get_major_package_version(void) +{ + return SP_PACKAGE_VERSION_MAJOR; +} + +SP_API int sp_get_minor_package_version(void) +{ + return SP_PACKAGE_VERSION_MINOR; +} + +SP_API int sp_get_micro_package_version(void) +{ + return SP_PACKAGE_VERSION_MICRO; +} + +SP_API const char *sp_get_package_version_string(void) +{ + return SP_PACKAGE_VERSION_STRING; +} + +SP_API int sp_get_current_lib_version(void) +{ + return SP_LIB_VERSION_CURRENT; +} + +SP_API int sp_get_revision_lib_version(void) +{ + return SP_LIB_VERSION_REVISION; +} + +SP_API int sp_get_age_lib_version(void) +{ + return SP_LIB_VERSION_AGE; +} + +SP_API const char *sp_get_lib_version_string(void) +{ + return SP_LIB_VERSION_STRING; +} + +/** @} */ diff --git a/src/libserialport/timing.c b/src/libserialport/timing.c new file mode 100644 index 000000000..25876d622 --- /dev/null +++ b/src/libserialport/timing.c @@ -0,0 +1,174 @@ +/* + * This file is part of the libserialport project. + * + * Copyright (C) 2019 Martin Ling + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 Lesser General Public License + * along with this program. If not, see . + */ + +#include "libserialport_internal.h" + +SP_PRIV void time_get(struct time *time) +{ +#ifdef _WIN32 + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + time->ticks = count.QuadPart; +#elif defined(HAVE_CLOCK_GETTIME) + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + clock_gettime(CLOCK_REALTIME, &ts); + time->tv.tv_sec = ts.tv_sec; + time->tv.tv_usec = ts.tv_nsec / 1000; +#elif defined(__APPLE__) + mach_timebase_info_data_t info; + mach_timebase_info(&info); + uint64_t ticks = mach_absolute_time(); + uint64_t ns = (ticks * info.numer) / info.denom; + time->tv.tv_sec = ns / 1000000000; + time->tv.tv_usec = (ns % 1000000000) / 1000; +#else + gettimeofday(&time->tv, NULL); +#endif +} + +SP_PRIV void time_set_ms(struct time *time, unsigned int ms) +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + time->ticks = ms * (frequency.QuadPart / 1000); +#else + time->tv.tv_sec = ms / 1000; + time->tv.tv_usec = (ms % 1000) * 1000; +#endif +} + +SP_PRIV void time_add(const struct time *a, + const struct time *b, struct time *result) +{ +#ifdef _WIN32 + result->ticks = a->ticks + b->ticks; +#else + timeradd(&a->tv, &b->tv, &result->tv); +#endif +} + +SP_PRIV void time_sub(const struct time *a, + const struct time *b, struct time *result) +{ +#ifdef _WIN32 + result->ticks = a->ticks - b->ticks; +#else + timersub(&a->tv, &b->tv, &result->tv); +#endif +} + +SP_PRIV bool time_greater(const struct time *a, const struct time *b) +{ +#ifdef _WIN32 + return (a->ticks > b->ticks); +#else + return timercmp(&a->tv, &b->tv, >); +#endif +} + +SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv) +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + tv->tv_sec = (long) (time->ticks / frequency.QuadPart); + tv->tv_usec = (long) ((time->ticks % frequency.QuadPart) / + (frequency.QuadPart / 1000000)); +#else + *tv = time->tv; +#endif +} + +SP_PRIV unsigned int time_as_ms(const struct time *time) +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return (unsigned int) (time->ticks / (frequency.QuadPart / 1000)); +#else + return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000; +#endif +} + +SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms) +{ + timeout->ms = timeout_ms; + + /* Get time at start of operation. */ + time_get(&timeout->start); + /* Define duration of timeout. */ + time_set_ms(&timeout->delta, timeout_ms); + /* Calculate time at which we should give up. */ + time_add(&timeout->start, &timeout->delta, &timeout->end); + /* Disable limit unless timeout_limit() called. */ + timeout->limit_ms = 0; + /* First blocking call has not yet been made. */ + timeout->calls_started = false; +} + +SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms) +{ + timeout->limit_ms = limit_ms; + timeout->overflow = (timeout->ms > timeout->limit_ms); + time_set_ms(&timeout->delta_max, timeout->limit_ms); +} + +SP_PRIV bool timeout_check(struct timeout *timeout) +{ + if (!timeout->calls_started) + return false; + + if (timeout->ms == 0) + return false; + + time_get(&timeout->now); + time_sub(&timeout->end, &timeout->now, &timeout->delta); + if (timeout->limit_ms) + if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max))) + timeout->delta = timeout->delta_max; + + return time_greater(&timeout->now, &timeout->end); +} + +SP_PRIV void timeout_update(struct timeout *timeout) +{ + timeout->calls_started = true; +} + +#ifndef _WIN32 +SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout) +{ + if (timeout->ms == 0) + return NULL; + + time_as_timeval(&timeout->delta, &timeout->delta_tv); + + return &timeout->delta_tv; +} +#endif + +SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout) +{ + if (timeout->limit_ms && timeout->overflow) + return timeout->limit_ms; + else + return time_as_ms(&timeout->delta); +} diff --git a/src/libserialport/windows.c b/src/libserialport/windows.c new file mode 100644 index 000000000..2825a9208 --- /dev/null +++ b/src/libserialport/windows.c @@ -0,0 +1,569 @@ +/* + * This file is part of the libserialport project. + * + * Copyright (C) 2013-2014 Martin Ling + * Copyright (C) 2014 Aurelien Jacobs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 Lesser General Public License + * along with this program. If not, see . + */ + +#include "libserialport_internal.h" + +/* USB path is a string of at most 8 decimal numbers < 128 separated by dots. */ +#define MAX_USB_PATH ((8 * 3) + (7 * 1) + 1) + +static void enumerate_hub(struct sp_port *port, const char *hub_name, + const char *parent_path, DEVINST dev_inst); + +static char *wc_to_utf8(PWCHAR wc_buffer, ULONG wc_bytes) +{ + ULONG wc_length = wc_bytes / sizeof(WCHAR); + ULONG utf8_bytes; + WCHAR *wc_str = NULL; + char *utf8_str = NULL; + + /* Allocate aligned wide char buffer */ + if (!(wc_str = malloc((wc_length + 1) * sizeof(WCHAR)))) + goto wc_to_utf8_end; + + /* Zero-terminate the wide char string. */ + memcpy(wc_str, wc_buffer, wc_bytes); + wc_str[wc_length] = 0; + + /* Compute the size of the UTF-8 converted string. */ + if (!(utf8_bytes = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1, + NULL, 0, NULL, NULL))) + goto wc_to_utf8_end; + + /* Allocate UTF-8 output buffer. */ + if (!(utf8_str = malloc(utf8_bytes))) + goto wc_to_utf8_end; + + /* Actually converted to UTF-8. */ + if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1, + utf8_str, utf8_bytes, NULL, NULL)) { + free(utf8_str); + utf8_str = NULL; + goto wc_to_utf8_end; + } + +wc_to_utf8_end: + if (wc_str) + free(wc_str); + + return utf8_str; +} + +static char *get_root_hub_name(HANDLE host_controller) +{ + USB_ROOT_HUB_NAME root_hub_name; + PUSB_ROOT_HUB_NAME root_hub_name_wc; + char *root_hub_name_utf8; + ULONG size = 0; + + /* Compute the size of the root hub name string. */ + if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0, + &root_hub_name, sizeof(root_hub_name), &size, NULL)) + return NULL; + + /* Allocate wide char root hub name string. */ + size = root_hub_name.ActualLength; + if (!(root_hub_name_wc = malloc(size))) + return NULL; + + /* Actually get the root hub name string. */ + if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, + NULL, 0, root_hub_name_wc, size, &size, NULL)) { + free(root_hub_name_wc); + return NULL; + } + + /* Convert the root hub name string to UTF-8. */ + root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size - offsetof(USB_ROOT_HUB_NAME, RootHubName)); + free(root_hub_name_wc); + return root_hub_name_utf8; +} + +static char *get_external_hub_name(HANDLE hub, ULONG connection_index) +{ + USB_NODE_CONNECTION_NAME ext_hub_name; + PUSB_NODE_CONNECTION_NAME ext_hub_name_wc; + char *ext_hub_name_utf8; + ULONG size; + + /* Compute the size of the external hub name string. */ + ext_hub_name.ConnectionIndex = connection_index; + if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, + &ext_hub_name, sizeof(ext_hub_name), + &ext_hub_name, sizeof(ext_hub_name), &size, NULL)) + return NULL; + + /* Allocate wide char external hub name string. */ + size = ext_hub_name.ActualLength; + if (size <= sizeof(ext_hub_name) + || !(ext_hub_name_wc = malloc(size))) + return NULL; + + /* Get the name of the external hub attached to the specified port. */ + ext_hub_name_wc->ConnectionIndex = connection_index; + if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, + ext_hub_name_wc, size, + ext_hub_name_wc, size, &size, NULL)) { + free(ext_hub_name_wc); + return NULL; + } + + /* Convert the external hub name string to UTF-8. */ + ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size - offsetof(USB_NODE_CONNECTION_NAME, NodeName)); + free(ext_hub_name_wc); + return ext_hub_name_utf8; +} + +static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index, + UCHAR descriptor_index) +{ + char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) + + MAXIMUM_USB_STRING_LENGTH] = { 0 }; + PUSB_DESCRIPTOR_REQUEST desc_req = (void *)desc_req_buf; + PUSB_STRING_DESCRIPTOR desc = (void *)(desc_req + 1); + ULONG size = sizeof(desc_req_buf); + + desc_req->ConnectionIndex = connection_index; + desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) + | descriptor_index; + desc_req->SetupPacket.wIndex = 0; + desc_req->SetupPacket.wLength = (USHORT) (size - sizeof(*desc_req)); + + if (!DeviceIoControl(hub_device, + IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, + desc_req, size, desc_req, size, &size, NULL) + || size < 2 + || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE + || desc->bLength != size - sizeof(*desc_req) + || desc->bLength % 2) + return NULL; + + return wc_to_utf8(desc->bString, desc->bLength - offsetof(USB_STRING_DESCRIPTOR, bString)); +} + +static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device, + ULONG nb_ports, const char *parent_path, DEVINST dev_inst) +{ + char path[MAX_USB_PATH]; + ULONG index = 0; + + for (index = 1; index <= nb_ports; index++) { + PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex; + ULONG size = sizeof(*connection_info_ex) + (30 * sizeof(USB_PIPE_INFO)); + + if (!(connection_info_ex = malloc(size))) + break; + + connection_info_ex->ConnectionIndex = index; + if (!DeviceIoControl(hub_device, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, + connection_info_ex, size, + connection_info_ex, size, &size, NULL)) { + /* + * Try to get CONNECTION_INFORMATION if + * CONNECTION_INFORMATION_EX did not work. + */ + PUSB_NODE_CONNECTION_INFORMATION connection_info; + + size = sizeof(*connection_info) + (30 * sizeof(USB_PIPE_INFO)); + if (!(connection_info = malloc(size))) { + free(connection_info_ex); + continue; + } + connection_info->ConnectionIndex = index; + if (!DeviceIoControl(hub_device, + IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, + connection_info, size, + connection_info, size, &size, NULL)) { + free(connection_info); + free(connection_info_ex); + continue; + } + + connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex; + connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor; + connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub; + connection_info_ex->DeviceAddress = connection_info->DeviceAddress; + free(connection_info); + } + + if (connection_info_ex->DeviceIsHub) { + /* Recursively enumerate external hub. */ + PCHAR ext_hub_name; + if ((ext_hub_name = get_external_hub_name(hub_device, index))) { + snprintf(path, sizeof(path), "%s%ld.", + parent_path, connection_info_ex->ConnectionIndex); + enumerate_hub(port, ext_hub_name, path, dev_inst); + } + free(connection_info_ex); + } else { + snprintf(path, sizeof(path), "%s%ld", + parent_path, connection_info_ex->ConnectionIndex); + + /* Check if this device is the one we search for. */ + if (strcmp(path, port->usb_path)) { + free(connection_info_ex); + continue; + } + + /* Finally grab detailed information regarding the device. */ + port->usb_address = connection_info_ex->DeviceAddress + 1; + port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor; + port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct; + + if (connection_info_ex->DeviceDescriptor.iManufacturer) + port->usb_manufacturer = get_string_descriptor(hub_device, index, + connection_info_ex->DeviceDescriptor.iManufacturer); + if (connection_info_ex->DeviceDescriptor.iProduct) + port->usb_product = get_string_descriptor(hub_device, index, + connection_info_ex->DeviceDescriptor.iProduct); + if (connection_info_ex->DeviceDescriptor.iSerialNumber) { + port->usb_serial = get_string_descriptor(hub_device, index, + connection_info_ex->DeviceDescriptor.iSerialNumber); + if (port->usb_serial == NULL) { + //composite device, get the parent's serial number + char device_id[MAX_DEVICE_ID_LEN]; + if (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { + if (CM_Get_Device_IDA(dev_inst, device_id, sizeof(device_id), 0) == CR_SUCCESS) + port->usb_serial = strdup(strrchr(device_id, '\\')+1); + } + } + } + + free(connection_info_ex); + break; + } + } +} + +static void enumerate_hub(struct sp_port *port, const char *hub_name, + const char *parent_path, DEVINST dev_inst) +{ + USB_NODE_INFORMATION hub_info; + HANDLE hub_device; + ULONG size = sizeof(hub_info); + char *device_name; + + /* Open the hub with its full name. */ + if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1))) + return; + strcpy(device_name, "\\\\.\\"); + strcat(device_name, hub_name); + hub_device = CreateFileA(device_name, GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + free(device_name); + if (hub_device == INVALID_HANDLE_VALUE) + return; + + /* Get the number of ports of the hub. */ + if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION, + &hub_info, size, &hub_info, size, &size, NULL)) + /* Enumerate the ports of the hub. */ + enumerate_hub_ports(port, hub_device, + hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path, dev_inst); + + CloseHandle(hub_device); +} + +static void enumerate_host_controller(struct sp_port *port, + HANDLE host_controller_device, + DEVINST dev_inst) +{ + char *root_hub_name; + + if ((root_hub_name = get_root_hub_name(host_controller_device))) { + enumerate_hub(port, root_hub_name, "", dev_inst); + free(root_hub_name); + } +} + +static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match) +{ + HDEVINFO device_info; + SP_DEVINFO_DATA device_info_data; + ULONG i, size = 0; + + device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER, NULL, NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + device_info_data.cbSize = sizeof(device_info_data); + + for (i = 0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) { + SP_DEVICE_INTERFACE_DATA device_interface_data; + PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data; + DEVINST dev_inst = dev_inst_match; + HANDLE host_controller_device; + + device_interface_data.cbSize = sizeof(device_interface_data); + if (!SetupDiEnumDeviceInterfaces(device_info, 0, + &GUID_CLASS_USB_HOST_CONTROLLER, + i, &device_interface_data)) + continue; + + if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data, + NULL, 0, &size, NULL) + && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + continue; + + if (!(device_detail_data = malloc(size))) + continue; + device_detail_data->cbSize = sizeof(*device_detail_data); + if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data, + device_detail_data, size, &size, + NULL)) { + free(device_detail_data); + continue; + } + + while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS + && dev_inst != device_info_data.DevInst) { } + if (dev_inst != device_info_data.DevInst) { + free(device_detail_data); + continue; + } + + port->usb_bus = i + 1; + + host_controller_device = CreateFile(device_detail_data->DevicePath, + GENERIC_WRITE, FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (host_controller_device != INVALID_HANDLE_VALUE) { + enumerate_host_controller(port, host_controller_device, dev_inst_match); + CloseHandle(host_controller_device); + } + free(device_detail_data); + } + + SetupDiDestroyDeviceInfoList(device_info); + return; +} + +SP_PRIV enum sp_return get_port_details(struct sp_port *port) +{ + /* + * Description limited to 127 char, anything longer + * would not be user friendly anyway. + */ + char description[128]; + SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) }; + HDEVINFO device_info; + int i; + + device_info = SetupDiGetClassDevs(NULL, 0, 0, + DIGCF_PRESENT | DIGCF_ALLCLASSES); + if (device_info == INVALID_HANDLE_VALUE) + RETURN_FAIL("SetupDiGetClassDevs() failed"); + + for (i = 0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) { + HKEY device_key; + DEVINST dev_inst; + char value[8], class[16]; + DWORD size, type; + CONFIGRET cr; + + /* Check if this is the device we are looking for. */ + device_key = SetupDiOpenDevRegKey(device_info, &device_info_data, + DICS_FLAG_GLOBAL, 0, + DIREG_DEV, KEY_QUERY_VALUE); + if (device_key == INVALID_HANDLE_VALUE) + continue; + size = sizeof(value); + if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value, + &size) != ERROR_SUCCESS || type != REG_SZ) { + RegCloseKey(device_key); + continue; + } + RegCloseKey(device_key); + value[sizeof(value) - 1] = 0; + if (strcmp(value, port->name)) + continue; + + /* Check port transport type. */ + dev_inst = device_info_data.DevInst; + size = sizeof(class); + cr = CR_FAILURE; + while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS && + (cr = CM_Get_DevNode_Registry_PropertyA(dev_inst, + CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { } + if (cr == CR_SUCCESS) { + if (!strcmp(class, "USB")) + port->transport = SP_TRANSPORT_USB; + } + + /* Get port description (friendly name). */ + dev_inst = device_info_data.DevInst; + size = sizeof(description); + while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst, + CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS + && CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { } + if (cr == CR_SUCCESS) + port->description = strdup(description); + + /* Get more informations for USB connected ports. */ + if (port->transport == SP_TRANSPORT_USB) { + char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH]; + char device_id[MAX_DEVICE_ID_LEN]; + + /* Recurse over parents to build the USB device path. */ + dev_inst = device_info_data.DevInst; + do { + /* Verify that this layer of the tree is USB related. */ + if (CM_Get_Device_IDA(dev_inst, device_id, + sizeof(device_id), 0) != CR_SUCCESS + || strncmp(device_id, "USB\\", 4)) + continue; + + /* Discard one layer for composite devices. */ + char compat_ids[512], *p = compat_ids; + size = sizeof(compat_ids); + if (CM_Get_DevNode_Registry_PropertyA(dev_inst, + CM_DRP_COMPATIBLEIDS, 0, + &compat_ids, + &size, 0) == CR_SUCCESS) { + while (*p) { + if (!strncmp(p, "USB\\COMPOSITE", 13)) + break; + p += strlen(p) + 1; + } + if (*p) + continue; + } + + /* Stop the recursion when reaching the USB root. */ + if (!strncmp(device_id, "USB\\ROOT", 8)) + break; + + /* Prepend the address of current USB layer to the USB path. */ + DWORD address; + size = sizeof(address); + if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS, + 0, &address, &size, 0) == CR_SUCCESS) { + strcpy(tmp, usb_path); + snprintf(usb_path, sizeof(usb_path), "%d%s%s", + (int)address, *tmp ? "." : "", tmp); + } + } while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS); + + port->usb_path = strdup(usb_path); + + /* Wake up the USB device to be able to read string descriptor. */ + char *escaped_port_name; + HANDLE handle; + if (!(escaped_port_name = malloc(strlen(port->name) + 5))) + RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed"); + sprintf(escaped_port_name, "\\\\.\\%s", port->name); + handle = CreateFileA(escaped_port_name, GENERIC_READ, 0, 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); + free(escaped_port_name); + CloseHandle(handle); + + /* Retrieve USB device details from the device descriptor. */ + get_usb_details(port, device_info_data.DevInst); + } + break; + } + + SetupDiDestroyDeviceInfoList(device_info); + + RETURN_OK(); +} + +SP_PRIV enum sp_return list_ports(struct sp_port ***list) +{ + HKEY key; + TCHAR *value, *data; + DWORD max_value_len, max_data_size, max_data_len; + DWORD value_len, data_size, data_len; + DWORD type, index = 0; + LSTATUS result; + char *name; + int name_len; + int ret = SP_OK; + + DEBUG("Opening registry key"); + if ((result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), + 0, KEY_QUERY_VALUE, &key)) != ERROR_SUCCESS) { + /* It's possible for this key to not exist if there are no serial ports + * at all. In that case we're done. Return a failure for any other error. */ + if (result != ERROR_FILE_NOT_FOUND) { + SetLastError(result); + SET_FAIL(ret, "RegOpenKeyEx() failed"); + } + goto out_done; + } + DEBUG("Querying registry key value and data sizes"); + if ((result = RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + &max_value_len, &max_data_size, NULL, NULL)) != ERROR_SUCCESS) { + SetLastError(result); + SET_FAIL(ret, "RegQueryInfoKey() failed"); + goto out_close; + } + max_data_len = max_data_size / sizeof(TCHAR); + if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) { + SET_ERROR(ret, SP_ERR_MEM, "Registry value malloc failed"); + goto out_close; + } + if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) { + SET_ERROR(ret, SP_ERR_MEM, "Registry data malloc failed"); + goto out_free_value; + } + DEBUG("Iterating over values"); + while ( + value_len = max_value_len + 1, + data_size = max_data_size, + RegEnumValue(key, index, value, &value_len, + NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS) + { + if (type == REG_SZ) { + data_len = data_size / sizeof(TCHAR); + data[data_len] = '\0'; +#ifdef UNICODE + name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL); +#else + name_len = data_len + 1; +#endif + if (!(name = malloc(name_len))) { + SET_ERROR(ret, SP_ERR_MEM, "Registry port name malloc failed"); + goto out; + } +#ifdef UNICODE + WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL); +#else + strcpy(name, data); +#endif + DEBUG_FMT("Found port %s", name); + if (!(*list = list_append(*list, name))) { + SET_ERROR(ret, SP_ERR_MEM, "List append failed"); + free(name); + goto out; + } + free(name); + } + index++; + } +out: + free(data); +out_free_value: + free(value); +out_close: + RegCloseKey(key); +out_done: + + return ret; +} From 6305aca09b93d88a441fa7f37fd219512fa3673c Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 14 Feb 2023 08:45:26 +0100 Subject: [PATCH 5/9] feat: create upload_reset binary for windows to remove java dependecy on Windows fixes #67 Signed-off-by: Frederic Pillon --- linux/{upload-reset => upload_reset} | Bin macosx/{upload-reset => upload_reset} | Bin .../unix/upload_reset.c} | 22 ++--- src/upload_reset/win/Makefile | 23 +++++ src/upload_reset/win/upload_reset.c | 85 ++++++++++++++++++ win/upload_reset.exe | Bin 0 -> 227850 bytes 6 files changed, 119 insertions(+), 11 deletions(-) rename linux/{upload-reset => upload_reset} (100%) rename macosx/{upload-reset => upload_reset} (100%) rename src/{upload-reset/upload-reset.c => upload_reset/unix/upload_reset.c} (95%) create mode 100644 src/upload_reset/win/Makefile create mode 100644 src/upload_reset/win/upload_reset.c create mode 100644 win/upload_reset.exe diff --git a/linux/upload-reset b/linux/upload_reset similarity index 100% rename from linux/upload-reset rename to linux/upload_reset diff --git a/macosx/upload-reset b/macosx/upload_reset similarity index 100% rename from macosx/upload-reset rename to macosx/upload_reset diff --git a/src/upload-reset/upload-reset.c b/src/upload_reset/unix/upload_reset.c similarity index 95% rename from src/upload-reset/upload-reset.c rename to src/upload_reset/unix/upload_reset.c index 1d03bff51..975ef258d 100644 --- a/src/upload-reset/upload-reset.c +++ b/src/upload_reset/unix/upload_reset.c @@ -1,5 +1,5 @@ /* Copyright (C) 2015 Roger Clark - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -17,7 +17,7 @@ /* Copyright (C) 2003 Heiko Noordhof - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -38,7 +38,7 @@ int openserial(char *devicename); void closeserial(void); int setDTR(unsigned short level); -int setRTS(unsigned short level); +int setRTS(unsigned short level); /* Two globals for use by this module only */ @@ -53,11 +53,11 @@ void closeserial(void) } -int openserial(char *devicename) +int openserial(char *devicename) { struct termios attr; - if ((fd = open(devicename, O_RDWR)) == -1) return 0; /* Error */ + if ((fd = open(devicename, O_RDWR)) == -1) return 0; /* Error */ atexit(closeserial); if (tcgetattr(fd, &oldterminfo) == -1) return 0; /* Error */ @@ -65,7 +65,7 @@ int openserial(char *devicename) attr.c_cflag |= CRTSCTS | CLOCAL; attr.c_oflag = 0; if (tcflush(fd, TCIOFLUSH) == -1) return 0; /* Error */ - if (tcsetattr(fd, TCSANOW, &attr) == -1) return 0; /* Error */ + if (tcsetattr(fd, TCSANOW, &attr) == -1) return 0; /* Error */ /* Set the lines to a known state, and */ /* finally return non-zero is successful. */ @@ -114,13 +114,13 @@ int setDTR(unsigned short level) } /* This portion of code was written by Roger Clark - * It was informed by various other pieces of code written by Leaflabs to reset their - * Maple and Maple mini boards + * It was informed by various other pieces of code written by Leaflabs to reset their + * Maple and Maple mini boards */ main(int argc, char *argv[]) { - + if (argc<2 || argc >3) { printf("Usage upload-reset \n\r"); @@ -147,7 +147,7 @@ main(int argc, char *argv[]) usleep(50000L); write(fd,"1EAF",4); - + closeserial(); if (argc==3) { diff --git a/src/upload_reset/win/Makefile b/src/upload_reset/win/Makefile new file mode 100644 index 000000000..4aac4846b --- /dev/null +++ b/src/upload_reset/win/Makefile @@ -0,0 +1,23 @@ +CC = gcc +SRC = $(wildcard *.c) +LIBSRC = $(wildcard ../../libserialport/*.c) +OBJ = $(SRC:.c=.o) $(LIBSRC:.c=.o) +CFLAGS = -DLIBSERIALPORT_MSBUILD -Wall -I../../libserialport +LDFLAGS = -lsetupapi +DEST = ../../../win +BIN = $(SRC:.c=) + +.PHONY: all clean + +all: $(BIN) install + +$(BIN): $(OBJ) + $(CC) -o $@ $^ $(LDFLAGS) + +install: $(BIN) + @echo "$@ $^..." + @mv $(BIN) $(DEST)/ + +clean: + rm -f $(OBJ) $(DEST)/$(BIN) + diff --git a/src/upload_reset/win/upload_reset.c b/src/upload_reset/win/upload_reset.c new file mode 100644 index 000000000..414e0c6a6 --- /dev/null +++ b/src/upload_reset/win/upload_reset.c @@ -0,0 +1,85 @@ +#include +#include +#include +/* + * Utility to send the reset sequence on RTS and DTR and chars + * which resets the libmaple and causes the bootloader to be run + */ + +/* Helper function for error handling. */ +int check(enum sp_return result) +{ + char *error_message; + + switch (result) { + case SP_ERR_ARG: + printf("Error: Invalid argument.\n"); + exit(SP_ERR_ARG); + case SP_ERR_FAIL: + error_message = sp_last_error_message(); + printf("Error: Failed: %s\n", error_message); + sp_free_error_message(error_message); + exit(SP_ERR_FAIL); + case SP_ERR_SUPP: + printf("Error: Not supported.\n"); + exit(SP_ERR_SUPP); + case SP_ERR_MEM: + printf("Error: Couldn't allocate memory.\n"); + exit(SP_ERR_MEM); + case SP_OK: + default: + return result; + } +} + +int main(int argc, char **argv) +{ + if (argc<2 || argc >3) + { + printf("Usage %s \n", argv[0]); + return -1; + } + + char *port_name = argv[1]; + /* A pointer to a struct sp_port, which will refer to + * the port found. */ + struct sp_port *port; + printf("Looking for port %s.\n", port_name); + /* Call sp_get_port_by_name() to find the port. The port + * pointer will be updated to refer to the port found. */ + check(sp_get_port_by_name(port_name, &port)); + + /* Display some basic information about the port. */ + printf("Port name: %s\n", sp_get_port_name(port)); + printf("Description: %s\n", sp_get_port_description(port)); + + /* The port must be open to access its configuration. */ + printf("Opening port.\n"); + check(sp_open(port, SP_MODE_READ_WRITE)); + check(sp_set_flowcontrol(port, SP_FLOWCONTROL_RTSCTS)); + check(sp_flush(port, SP_BUF_BOTH)); + // check(sp_set_rts(port, SP_RTS_OFF)); + // check(sp_set_dtr(port, SP_DTR_OFF)); + + // Send magic sequence of DTR and RTS followed by the magic word "1EAF" + check(sp_set_rts(port, SP_RTS_OFF)); + check(sp_set_dtr(port, SP_DTR_OFF)); + check(sp_set_dtr(port, SP_DTR_ON)); + Sleep(50); + check(sp_set_dtr(port, SP_DTR_OFF)); + check(sp_set_rts(port, SP_RTS_ON)); + check(sp_set_dtr(port, SP_DTR_ON)); + Sleep(50); + check(sp_set_dtr(port, SP_DTR_OFF)); + Sleep(50); + check(sp_blocking_write(port, "1EAF", 4, 1000)); + + /* Now clean up by closing the port and freeing structures. */ + check(sp_close(port)); + sp_free_port(port); + if (argc==3) + { + Sleep(atol(argv[2])); + } + return 0; +} diff --git a/win/upload_reset.exe b/win/upload_reset.exe new file mode 100644 index 0000000000000000000000000000000000000000..27cdc459b25a8baa18aeae0ce578b825af206900 GIT binary patch literal 227850 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 CZ&!x^ literal 0 HcmV?d00001 From b7abac85e2943257eef207a7d7c6d4e136c5e533 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 14 Feb 2023 08:27:22 +0100 Subject: [PATCH 6/9] feat: create check_port binary for windows Signed-off-by: Frederic Pillon --- src/check_port/Makefile | 22 ++++++++++++ src/check_port/check_port.c | 69 ++++++++++++++++++++++++++++++++++++ win/check_port.exe | Bin 0 -> 226511 bytes 3 files changed, 91 insertions(+) create mode 100644 src/check_port/Makefile create mode 100644 src/check_port/check_port.c create mode 100644 win/check_port.exe diff --git a/src/check_port/Makefile b/src/check_port/Makefile new file mode 100644 index 000000000..16a48cdfc --- /dev/null +++ b/src/check_port/Makefile @@ -0,0 +1,22 @@ +CC = gcc +SRC = $(wildcard *.c) +LIBSRC = $(wildcard ../libserialport/*.c) +OBJ = $(SRC:.c=.o) $(LIBSRC:.c=.o) +CFLAGS = -DLIBSERIALPORT_MSBUILD -Wall -I../libserialport +LDFLAGS = -lsetupapi +DEST = ../../win +BIN = $(SRC:.c=) + +.PHONY: all clean + +all: $(BIN) install + +$(BIN): $(OBJ) + $(CC) -o $@ $^ $(LDFLAGS) + +install: $(BIN) + @echo "$@ $^..." + @mv $(BIN) $(DEST)/ + +clean: + rm -f $(OBJ) $(DEST)/$(BIN) diff --git a/src/check_port/check_port.c b/src/check_port/check_port.c new file mode 100644 index 000000000..4dd9bb7fb --- /dev/null +++ b/src/check_port/check_port.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +/* Example of how to get a list of serial ports on the system. + * + * This example file is released to the public domain. */ + +int main(int argc, char **argv) +{ + /* A pointer to a null-terminated array of pointers to + * struct sp_port, which will contain the ports found.*/ + struct sp_port **port_list; + char *search_name = NULL; + bool found = false; + bool search = false; + if (argc>2) + { + printf("Usage %s \n", argv[0]); + return -1; + } + if (argc == 2) { + search_name = argv[1]; + search = true; + } + if (!search) { + printf("Getting port list.\n"); + } + /* Call sp_list_ports() to get the ports. The port_list + * pointer will be updated to refer to the array created. */ + enum sp_return result = sp_list_ports(&port_list); + + if (result != SP_OK) { + printf("sp_list_ports() failed!\n"); + return -1; + } + + /* Iterate through the ports. When port_list[i] is NULL + * this indicates the end of the list. */ + int i; + for (i = 0; port_list[i] != NULL; i++) { + struct sp_port *port = port_list[i]; + + /* Get the name of the port. */ + char *port_name = sp_get_port_name(port); + if (!search) { + printf("Found port: %s\n", port_name); + } else { + if (strcmp( search_name, port_name ) == 0) { + found = true; + break; + } + } + } + if (!search){ + printf("Found %d ports.\n", i); + printf("Freeing port list.\n"); + } + + /* Free the array created by sp_list_ports(). */ + sp_free_port_list(port_list); + + /* Note that this will also free all the sp_port structures + * it points to. If you want to keep one of them (e.g. to + * use that port in the rest of your program), take a copy + * of it first using sp_copy_port(). */ + + return (search) ? !found : 0; +} diff --git a/win/check_port.exe b/win/check_port.exe new file mode 100644 index 0000000000000000000000000000000000000000..be48c8537ffc7aafcbb111f86b67fbf36c7d51fa GIT binary patch literal 226511 zcmeFad3Y2>*FHP}27)k7P)6dTNDxqP1y`b|2@)MJXcXcK0-`|_H%L%aFkup599rXo z`-1z1iayBZmH-lP4T{R9L`0bwR8+)(OMdr#PIY%B1fSRI`u_ZKDRa8}K1-cCb?S6= zPtD*9%L6R~fj}$#-_Q^UEWjuKvgF@?{-+q1_w2H0&%oTaA9h`klKWxTp_h-Hka6w! zYsQQpbyddbQCDAmO<~3*mt~AEx;kU*)fofM8j^9X%U5gey12q8kPYDEC;N0Gz(}XDtXOzZy+ReWpLHrwu*0c@; zy6)Qw?HUPahMYFMpjC+b!HedM;;sct2at180!a#owi#{olKfkd5_s4;Y)V%2ND1_8 zdJ@Oc!j!=Ibo6fijwrnBhC*CR-GF~+P!0Y^JM6!aXx$N)jw&35lQ4^p65j;A!>9F^ z6$n%uFb%l|4+Ag^MM;@b$<&2eTBQM$vu1}@_ zADxen8eHc(l3GTnWsiEAoINq$5pL+@aceb62U1ton4Usx25j?U{BO{p&F%bZ?V0Jbi;7!N&tR!SfdD61$u zbs_sTIch!rS+$OWBVPiM*ejlvd{d8Ka*sPM7sbQVQv$KRDTR4`Dx$HaJ(rX(q(#XC zAfoOK+8dsqmtIh^vt3GI4nJBHO^+>LYxWG^dQ(F~L!!JM2YptQeG;BoSvwYI!d;4S z2D(Ef(3RZ(V_a6*;VuILf!Ga&V9f$>K%$uWvd@Z~vI;UEhI0kw@K0Z~EFZkNPVjS# z;HVS%LOw#P@sS9`gR^;<2>uM)2P9IXPVga~h!5zVksQ7n(T$e$U1IFW9-4pNxkDf| zBbw-Z7C54b!xxN(^BXRUCR+92po}K2O|9$X+MT&9Tsj6$SeV3MY4|J}uiqLCzj}1E ztfJ_fXyVxYA)-%1qIIl3C0u$gaEaD1zw~ubRl&Vs2mNO*=YlS42$x=lPuSb16SW5* zsjz)cpNd87tUfCms*~rxC;rNY=!VGNFb*Ae55Z38t-l%?qVX2VnQPH2S?IGw=T8Qw z1e}{vqN5w4m77~e<2#ZyxR{&h@hUDvb8SjA z{&Vub01u3Bg}XWj1|~Z0AB|T=V@pz#7vX#~b3@Tb(UhN}RWc(-G}=##=i^h?G?7mpa8 zJ#0yVJ0{@L6_EQ5n2p=YUiiDAVIk9B@|7>VlXGzrn%)8yq4f+tlGmYCRg${ll{4mgBIck(u9wMm$OH zl(GU#tZO9mqw#N{BQHKUEgH{HPad`uqN;K@3Ioe>e#igY1F^|zEv9sfCUVjlZt=w! zAw_k7p$(6$!psQK4Yi!R2`oxeU{-20o>LF@l<>Tq?Xj&Xr4@x?a26QO7tt3{C#RZH zx`qRRc+QsCpzi_t2hxebXkUKX!1#)R@oJ>EXiEgA6M7siZK#gMCZ`9A4hOc< z@O1+HI%y|zfFkb@qDRw#$>(b%A!m?Rhj&mT#4WdNbz(h-SQ}DC(=gM^|jRPr|LvV zVlcGO-^;0JyoiDLs;sDZjH;@#@;E9)RaG&h${!D_ifgPR08@D=SF#WrF4@s#ugXgI z$^CsY!zCf2r^^Srw?+50=q!(h%^Uvf54aAlKUyMDByzUY9gPzVDD_+LHV#zdpD8kE zBbzZRA;8W+d^c1t5W%sfS;Lo@WYSxLH4)4+oCmR2ogW6JgA}h@#h|MUi=`QvA@2 z1KV1Rf62@eX|0T>Sd6{{_xBx`VH~)OY^J%3RK$|M#DS$Mq8SJ7-;4thImUs7mc+|d z;&m$VSgdaNS;2Rpn-xwloOIj~q&>&wsera3Kpcl^Kt}+AsmL9kJ)0SxJ)=52zx+fS zO5rO>BaP{J|MgF4@0;J!I!J9kUp!**->Lj2Uwo?kS(zx9k*S8tt`WoY&q(GA??^EH%b36VJ&rMa~yYt*= zi~qbv#;sBQqnb6Yh1acF%@~(ujB9NP-&rj!H^$wp!oU6IAG#HFEy7_j`OrX?P4h%X zld|b-74?d5XAzUnZHAADZwhHAaaLaKBMcW<41<+n`%ZD;!5d|0aG=+n z!r>K_z~F?JmnShP$tm3u&|U?+t^(Gm05jt@o$j=qYjKC{w(}#>P0Pa)l~tuK^UA{~ z3?JKhFKH)oo+7XP+B3VBrHoi!MI)^8aJ0pKp0cMa`*nV+YadW{G?+GuyAH7!4^YMp zJE%U?)7M)!8de1iG6H(rM}fd1vA_v+a64bbCeYg`ah7buO_ofUD*&ZKIAOj8+M6(M zP&IFen&v0WL@;5vnNe;b?WL=M%6_4+Yn~qr(1nJ9R-OskwX#&)fRmXD2$x=vLUF-f zJa!^G>-iBHE3n#=^jgRgmSPDz#|YC}35^S*Q>6K5diwj6%R?z;3PG3yT>Rrb?;;ba zcM%!1GWnH%k%`Q^hzwSltn@E3k$4x8K`N6^`4_Y7ix|O`$!Y$@sC_ZYi&uCTrB3Gc zz13hn2IO=X0{TRugWEnpGXUktPLg&a3xDTFNTa44)lbv8hvUQC+SUc5v7CC|;MGT+ zj#!T{PSJZwL}ra#idD2|bQ${J#|$0ieMW5Z)#uRwq~weTh~rqW7c8TR>yQpaK0GoWoFp3+WMwUnf%b z8yyq6PCY{YT9hapr7;V9J!vO$zJd?a=1BSWjDpX#z=ITgsDk%ZFjjyX>TZVE!z^Tm zB2yH(ha%~vx^sYRVIj9O2(ga2O|0E1J-t9`I4&lw=2g?K4;1;5A|FyDwKp47j~Y$} z)m@~$WLK&Ju3GO06_ednhJnE`3bY#>4`}cug1HI^m%gf=>BnOya;%EGS^Qi(Q?F%M z!a7>Q&KF@-IVf_lX493KdekHLqja*&y?l?2+Mcfp|u?&9u~jCur*2KNzzW_ z;a~X?`bOHxB;rr9NM#&(xFeH=W-imVbA!++pCfHxBFM^%I)k@lFQm1)MgUdav1Zv& z4PD3J;CQ2#UON=D>$RA;gDR>-1truzi+_MyhZV<$>XSCL37}Sye*F1)_p1c zQaeqrRGlF{`IbKE1I`UtA9j86DQK7L3yoUOuP`-GcUrRGcEDxHDEPGDWV0V2jg+JJ z4Nv}zBPaBxD+1ZRGT9amlV;a(yj^aX>FHsloyb+n)oYFCX@ruyLQ=A2EA2-#X~ovl z@OKCQ{-904mhG5}5CGA97E3yGqntNk?#U8lAUeJn*nR$W5 zI9nM%ghgoOJS?%ejD5g};;`jJvXogYla%E_W%+fT&+>O$>I$B3zz1OQFPF4YFYA9> zfQJjQ{$~cXnUOtEWiqQ0kXS{Ko*ufGaHM=rw=%EnT#7TM**}tYB4IV`f{=APM-G`SCi|D@n{xvbgU)?;@Xr9{u8}YEGJs{C$dm3QbM$9K=FavQH&~ctEt5+}>&HovXlX;7ok6FBbp75d}F*ZsZf&37wZzvj={4ODFn**L6 zrcsQ)eMu+s=V<&L{S%uQ>L_i4fI0L^e1<#h5~(V-D(ie2M-5e3!+dh2PhRSim%C)t z$vfY(O054>tVgoUm-A582P%>$sI3cN-=rnb0|(L8t4JsE7pSe%e#DUzdQS2S*cZ^& zFTtrPVnZ7>Fd8g}{_F)A_*aK0V28eAE>;ykhx14&4X$fBTo>^lNvY5}?R4M6Q;F6l z2&4Gcv%Lr^lT&U3BA!zL&bJs&#`af9C-N)Q_V<6lkrO)1wY`G2clB)V=Gq>sxVDMq z*S$?S2(_x>>Ho{}5Ah_;jg6^98_R`cRCt!Z(HfR7jRO(SSq{rvT9*GVv6R1DE$^U~ zzb3f`@?=$d4BD(-9}7XEB{&EAn%Mq2MuM?@`Tw%LgKay}#&#ha+1?O@?Wt-z214+3 z+H1UiqS{`qw&!ob6(@9@YkM`l{vtTl_Lm??wPfWjDxpe=(Jo?%9it94-U~0nTdSe* zvkH(#;|kJv&Z8Q?sl$;IYUOHNO^unJ#uJUks^U#h$3N=#r(>}O9Le8#dnu2s!f{MP zY9=nUgaE9fyTvFTurw}4|3Gebi_xDzyTxd?3ed2a*}M~JC&K3sFm)4_eawPd?Zd5b zDiPey!D7JQlXfEQ6#UpKKOJAA;1w45Ed_t|y-1#+V41)BEBIjxT(00(6?~(DCA&rx ze2oPjt>97xb43(3vm~wMgKyZ}-vS?};PVt5w9I&eV8YaOcdw zT7W+hJkJ83q2O@}{*Qvi<9rJU;6p6%0SZ1v!Kn%sk3Xs4zc^lv%|DZNB6}(LH;oeU z_(TO)Ti~S%{x(UT(A^3aGX?^jD5JwMp!TQ|s<=lWfajC<$Cjr|&$(Zyns=0XAXf9o z^qdE94%F`+g{u#^BNhF}r(aQL<}iGCMP6k#b03rpOl~QK8F4+4FJ#wnq~1~H=7u{t=$eg`OZ!@p;@u~LneSm(k@6QtccUA{X;9@x%1xl% zNSXE~Xyf&pNaH?XGe1JnkNrr&^B?x-g%U8Vk;j zmbO&Y)<=;Csy6Xrr38AT;&vS>3b*MWlXfEY-%8WhV427rsM9@0Q;kvQEQ|FXWqnIo zZ?(qwU>#f&446gk7}Bf&_}r2Yxo-g;(TXD18xt~dEyG(9W(d@l5F$gMrz;9J>@T9+ zA#k#)KV8(jLtw^KcL*$&h-2m9J#K~#UKvz)scP2~VnB{>z~yQ{J(NC+!iqj)?>t1> zyXkvt6ONovYu5m|>1*d1fDvsPE~O7^FHb2ZWBLFhtFf4ATK#J=PokPm1dp<8ZIRzH$h01!jvgT?Qko7Ph_tjajf=5~0q;uPDP#0P zVZj((X>LTlTftVb!GETD_klcWr9!gucrz&BRd}Ko(_N;Bag6DUjcyL4b40hhj8OVD zKu#zGrIHjRrWb=#W4a6j$<-e&#S55fHUjIGA6RJC^X-^$>2U(9cZBE1Q$Zm!?74Wyk&x*}iJsHFiifmK?_*A@BW z264jFD$fa6rol^CO5ki)>pJ5G)WT_ACMrPKLV%3y!6T8hMCE# zD`_Wkg>wD)uH7fQtilF=eGO=n$v2bs`Xo~YEEWN5SVHdQxLzyMLn1ie@N(_+MbMaY z#nP~ADb_6Wu64(}uI8ez{MFoZkEbW(@gi>yF<;4_Jgzt`x#x|Lrjy)Y%gSuE(oAx9 ze<>j$nDoF^hf>WI{5T>PBX121-Tx)oOKfMYWrpvz}?L_*i*f~pW@A(Ul$O$k_ z-}U61Km+1~xq|tO5p*o*2SMjbwj7+6$nO~++8v1ej3|hV!SPC#^G@Wq^%YKgZb zd9h{CIcm`RiX5i~N!-5|1asrLr-#M3uQJ}HjNO*_aet@BXvO{a2x->|Uy;UhYh|sr zrmb_y>OJe8XYstCJl&M%O>3+i2%gyFo`FKVlopH`mWy)}k?TpDX@&mF$uMiRGO;`k z5i)!}spF#bAj8-L^U=vZBe__42+N}`%Szao5h&_gl>;P|1lt*QKD};u1?fG1j=t_S zejTnmp}!W>KUf#6ozMy=%uBM6o*s?oB+-FUM{emj_5wFkB<60=FCl}*b2h~$Z^FFt zGpd0E4$Kp@T^23Y!ajFi`G~ffCump0AlLVokai;L*775Cq?m=O1y3;6O05yhw!p_K z_+7-_gBARm zf;qL+9;9H$0+%Rw=Nf5Xo`S`U9a5!uZXSUYSBkfUUu=B(PQ1jr51)~ zR!q1kj5lxSf!WP{@ww%&xsqro-SbeJJrHKGX@9 znUbWn#lLg5&#zOw@ttQZ687wD`QnMU_VBa_<*VBzI;>{MiCFz4c?abg$V426OaIWT z_gXrxkStRBHLfI&DFiN#b?roOg0jdx(-_j;D)^c&aO8x3sWhFifWz$zaN4&o!J`fT z7^H=RK__x%>x(Ip5JFH2HWa6LPWAQ#(OLnmf4vCO%z8hQ_SUaQtJXiIo`Xj!sCAU9 zweAAQ$67~9PSPc|0<<-HVopYQY8J*vT`TkM!Pa=rTxh!6Xky-(20D>HSM$!!&!N@{ zmA$QbXD)8}tKl23Xc}qHFJK;I1RVkTWYF&10@E`ZPb%`Byb~(XCU}!dTO)uq!e1{? zdE{QTp_AC4FOdEq1Gdo(O*O%0dR(fE!mGvea_cD=9 zBC9v4jIwz0m51-=!dGLg+AT-a1&=Xc&I&zA>vVz-e^!v^uMz~_tgsrM1~&NH^Y}p1 z*gLhLkpZ-KZdQ$(rGfa;L+xie=B*;=0TCg0aMzy1RA0zx>PaJ!L-an-?hw7o%_UZy zQ+EMC<1K~)i{Wo+thuKGZjiyz)RRGbuV1ZPCC=$*O#QQ#Ux%b0kR8#qLXuTkmurh* z?k?G}=Mi3ZeCS%RYRR?sIdu)Q<42^uN4X1Luh+tIFRfNeNOVyf%PS^Zr!mLXE{a$iBaS>`Qr1k+%-+{k``l(=PY-N5H{u z9d;mSw+{P`@n%}Pmb4SOdnG?Y&!Pl#TWcoMg%KIu;9Z1yX>rz83 zYfe{dG88#Vt&tfdJxDJz9nf@nzu`X?`G%jK}$(*kmNDgyJc6i=MY1=L{&&vmUsiEr?Y@)1$jD$@L zK&FPFq`hVIgVew~Bw`^_RzjA7Q&YoU#$3E9RjxMShO$CbC(ym}Mst(8yS=eMzGAca zaaGLRx(+mk5KcIu2^A8Pa4&8gYI~&6q~Ki#d2>p*45b#&J!1)Y&=PR2D*!WDxiJkc zlw`TONr~NG#B-1BZq`d|Ay*|W|6MA2Q8f}#Y_c`EHpZuL7mbEwh zS0ZErp!q#c6ppxamOA+}#Hgv02PW@DtpK%Kq3W|)AWc`SAnj%8hd#iO6Iv?44YiV` zGd;D_pjN*Vn#MWoksa1uawf0&cgakr=q3L>)2ATQ&Cd7JFmsn2HO8=j?MK>)MAVA5 zSn_hSa|q%9*v|ro6`VvhK$GYC%GNjs4@6#S}!B|Ae2C0APD*A;xb zf*(_`+$G9fH)H&70RhAH}SuAdVj#MFugmZcbndS!mMJY z_mPH?>3yir2!21kZ*y7j)MXVyO=p#0BBv+5i>k=nbk+V;j?_)s&)t89OUIde z1>|nFnlR*Um&85BZgcl9T{U-y%X&gaa@3`4gCvbv538@3tL`D~C5>B=ClNRw%W#D* zNgAy#b8}T;bNQQh3z92yot#w=h4nb(aIB!_aMh1%CsAXGy!F~mm4{33(mb#?j@>-| zqI7TV4SHo|hLyned&$9XA5zmf1FQk>*4!e+yip z;DrjlL&5e8@t6g^Tfs9FJXyi^3^CpU7btjyg0E1pH$y}%WIsh7tH^e~4V)oX>H226 z!E=Ua587MYXjm%E+(UfAO2EDa9BI!G;QZu%fZ-;tJ1qn4&JO7IjK=Fu%T;V!twg*E z{!Sx+ol-{Hi9D*v$6oaPyk9H&xlsjwzQvfUjF&0nxi9#P8{MSAa>|_+I$NwAl=Tp0 zZD~zK&yv-f7HaR)hSJV2Njs74OZXA`Ny`gn#o7s?F8HPaGe^%MEv7TI`Z>CKKF;g9 z6Rw&}jIA;x6C*#!cg;{lb9Lc12{Wmo-Q;W4&{bI@ab1<{Qbdo%R|d>$A?q)uMk%8A zGX`>$hQ&blabj0()F6o&SR+OBEhF4~gU#rSqW^OdU4`r^7H~c5Mmdmm=fZ)>L240e z$@skxj6kAAlSzBi!X1logcRYskRl%Hfcy zsW;71+)5SK=*uemsNy>$4xzY)nW)fHtVJwVQ#3`b{*ft4-&Hj!%6mU`mlX8}8sny@ zpFq1QDmD|e$vW4Qb|U4K{0I%eB3qLbb*=>-q~OsCZg}1w0W}gD!Cn@)vx1LP@D>Hz zDeBLAd^5I^b|P&RyjH<>iu%|BFH!LN3bDCL!Cs1b+Cn~{$k!Bkxo-ng)OwvuiVU79 zYAk3>C1(9qxyE4SibZU)QHsiv6ovIK!_9~~l(hHkdbqN;7IwcvZEYAh#CP5;tv*_j z9R;aNHk^H=&;7-O4+%ECR;i3T-ywhK{ipqoU=S#ym5T1NSZ`I=~~;<*q%y8;%Uk13yH>9!uWTkf^I2N-PdW3 zRZAwi13*UJgp16`V@GY$FaLgU7o@=f?5GOR-sTJ?Z;?h17=6fA#Hcm>966$KX=rh*oew>)WH`JEgeI`L{ z`y{>Schp?NK&L%N+KF^kI$;nD~EMjpx#u9ds3S0Fi zWrhZ;Fj@B;gyz?0FQAM?l*XKW>abgMGrxH?mvkRYkd%Ti`O+$>btVI(aFC#q%H}IPG>c%w*A< zNIQ}CYDDyLyHDKrY+_ro++x)9Nsf`gKFI{VyFU34kpUM@(Y)rBqOC0hb~5~&$dihk z`-&f}ud>AR%EC{GGe$2{o@X&b?=g$zZe{7GER!uYgOo+r7sgpE zBbBACvK+2j&@+MBPGEs|V>K->*!5AzSeS4j}(5s5L=FgjV8W-<`4RQTWs<+?}5}d z*Y|$`-Dt`4`Img(KLXnIeZFPdKsD_b-c>lEeIE6FuXRVTrv=_$!S5<~rFN9~{!{3N zhyK7Fhui3%NIQ}H75uh>rP0qQ_#+FvSix5+c(#HiG2aZaPg%(O6`8HbhZQNMBEK#+?Zz}2PpD~dE$f)k9baKRCi>U>1-dv$+}|?(%y9TfeQE*t3&Q| zHW;99+tccqxnyu6lT{p76R`q=b9C|jmarL?u&-ZK zVeZXtqfJMi#KN&A)@C*xxz)Xh9Dk$G!J~~51Yz)C(oSUS>--3f5o5~Xm<;dvuFUiL zZRwpz7YqQt7XKsYrmw{>Rw+?6)=QyF3>)XG`J@pyioEUxHcLxrdWRXbFbJ`A!G(-G zZIwHj;7vdMvac-ReT!B5hHBoupO);D2dR1!d#+K&{u@NvdlJ-Lb-pV)Az5x>7lBjj zp`Kva*RnLEmi{=G28Y%@D3-!Tdn1Kkh-{X8l z1y3~Q1RpV+ED!G_jhyU#tL1W_-13lHD)AC-7{n3Bv^RC(z-0I=!lW)d(-j9p`inTX zF6^#~PjdZ$X}dD{8aVaV`61*^^9o5_HZ-Lt@>;R>bK1Wvt#^V$?q}vn$y{92SuU7O zT%6#^ywH*JIJSDL+k+cIV8#heT!?@7l(mcWL{=+(nIq0#O%Kn@+Dl)i$cX3hRezq@ z8yjag#W9AGL8)X{sq z(uxP%?T!Z~*r>fDw4(#t#OhlVhPh2C0dTR;+Fpbj*7g=_+lpkXSWQbYzeV98kZ{XU zDk=q{xC;$Lr9qNsQkpF{&6b;H$xW?DwxH0O6yrPHVh_gR%Kz4wZfnHO#C}WCZH?)T zHA*vljeHzH_q0VNf&FBA`G?$IHl%HnujSVrV-7?UTW$DkpshHA_909kD#Zu<#XNBb zX(w_6ig=8^VfWdi&#(0`0{j=M!F7R=z|l7t^zKLBkt(qs~pD$0+!03!I~1dH)%k87Nq0>NX1QZh_Mk+(9L`P_R@a#obrcGLS8?qa-sWNi}_X-d=i~N_U~|CnGMWGGz{Jlrongy4~`85okAM zrZ3CdJ5ZMoK2j-lXBeu5CVZT0S$DiS*Q$=UoB^v9+lpy^X{xqTOv z|K6m{sjjAlQ~Wl+MB0fwgJKbF9%E^`#?zF+5dS>jD$a=2w=BE`|Ag=0@({f+1pkEZ zxD`jPCEe<7GTuh-|Al__kN(Dy*}%wz$9pYy0mvrjCU_dLzn8)wk+CA7)tFbWvSU|G z_8YmJv=gah`R0UPd&2M7+oV-ZYq{kuyfwa4bHJlZ-cyZ4*0d8zdyh}0E_6b7ieNNU z9-n>(PQRwjvCPR-bB^8`dq>;G zwlumm$S`-5OARM`ZvkoVj`BSfaJL9hH)5~<;N6CS^fb`!9p#CS(}{KM(aJQ|>@VIx zVZlocoVRo5lXfE4so?vie;VJ;Ww|92(EOqZ`-}Us9zfdM(0SY0XR4e|P5Swl8e5QpV3&TREZmSaER!@lY@^@)-Tm9as~_`c z+7Cdxi!sX?)@DS!N!p2g%Zb!*yfMDS`0e2Ib+ z3htv|dod>40w1g3ixu2O!QNs_Ckxq5k;f=9tVnM$<_AWfY1-GMoyZ=FoP(kSO``#_ z7_-De&R1m3)8d3uEIAn`VCZ;t{nBD9NXra2gLD$6+_dpYh3uq_HoYvc99aR&?%5 zRxe1Ows;;;o=;F}AVe;D#8>w%>i}o)EW9RPZ3XGXpR6F&)mkq|cUi4H9rE0A@I=sV zkan{y=%g0psRf(jUjNi;B@)~|5sapZ-;;JC-4y(o<<{e9ZX&qC0>7o;?U?A%wiybR zAZ@GQhb?fqf>$W`Mg>d4UoWFIc#Q=ft>A|hJVwECAM%QV`&;1S6nu?>gO(Xq9#alqTF0Lp7ZM-&@H0o!}VsJ#sbl=5hQTA>NJWatB3hrkGpveOT z7WhI1->u+Y3byk=rUgD+!37HLq+l-(ge_!CMfOu<8%26~;M+pKX=_MhUnE67r_tl( zfj2DVD~e1$E>5_4n&$-kB2KZp_PA8?fUZ4GG0a?h91ptb+T+VA>4SSI$rGPb`}j1@-xuBus$bEm3LCqSC%>?+buBu!Zt zTC-eT3trh}L_bycFGlnu5BTABCuld^&bBPbQ44OzjE8XBOO2OlXDlti{-_o>UBROi z{GsKdehU75Ja|mo>PS10V-&nd!4hs^1;1y3-&SxN1wW@?8POY4#EeHQ@SO@?%bC;( z%~Y_A=+_l|tp&bR!7nNJXv>W00OLk5o-?Z%M=$(0yL&|M_Z{62wCm{Pb)bzq){}N3 zJ=BipOTCbG=l3@(@GA$la*!gc%cN=Exc=r^-w9ukb|M*yd@ANS!5-K61vj&9 zhlW0FxH-Q+K)UJtzKK&6o*arpb>8HY|Enymqg3l6MV>g-8=!TUX(}K?KZ~KaGQ^eP zmzh2T7cbLf=TiQJNg~+V;@WwQG;WA;RjC?u7wdlifr&Iulhz6{AUv3~-U8h;Y4uV` zo$jK3-_pAb8|&*^RcFJ);)JMWDZV-iOY_yt5f;l3W%)o^GMYDYsg+v~G|V(}AJ9$B zd{8A_d#7(EZ*=Rf*4EKXe%TKFeyt*Rlz0xUZ6>$AW-&gajK?eEoMNA`+1z@)#d@W( z{>gdP2@ThQFKKx+s~isF^z6?dR51(5|CrjPo5`OxlTbP&)?SB2gla zHZ{`-3p_-@n>Zmlp;RjtO>RBP0w1K{`3n9`yU@<9K?}U&N-^U$1%IPpFSoAaRWliU ztjLjy{8W)%Zhh54KCQ^(6j|sSAootwEaXj!ip$C@j~4lzNvhED9M%9 z22(7a-^NPw-d3K)>W={a>`7p$m0g#T!At@RKsU8>hDzGYvXj}>F>K7PC93lhMLy*B zL37!4sKppn#$L*J&P`qe%`PiVD%X82R{18O6ZsJZH6onCi#vw*)_!i|5hL^{G3yw6MDf4DU)4S5n$5b zas@xH;QJJ8XV+&f@Iwl|S;1ur_Ok0_3wfO)&rxKNBE9T7#6q5~$exPa$2UN-YcC7g zS&@Hp2695*-{3i6x7oGsGHocc>ju(Iv+H{*YqdDk&#wP9e2npDNjs5QiY&R_8=!V} zooX>mREBGmp>M)xFxi!FU}{ZxhQ)S@vh`KA_IB%<&#rqKW@gtGpqpl`Jyp`MX*9sk zu3ucLK4IJ5CynRBsBYm==QiI|KfA)(;FA{5eabUOc`j9d{8M%Sobfo>tAty(EkkD&90f21&6Bz^8UCJ+Ns9V({AnB-U0^{oT=u%Zn?;0*A18W zZuyin-qTg^6AHGo>uVPH83k`ZnE*$WE7;DiWfpjnf?recWCh#V^?VDQtKc#P?`N6e z)vmLf$*zxo`7g5TbJKlCKMdM+boD6T9ZN|&k-s?0;Za?oM2R@sWY;Gx@O=udR&ee_ zKcqed3j%kd1-?STPbxT5!FF~XXn{{s@I(b4tY9y@cCnCqD>7G+ofPS1*WX6^O{*pC zL=IHs0*xUWAldbO3;B*B>u(n)%$VRgVYk`UG2G0qC8V2X*Edzxjp9&0yXIS32ddV) z6xnUO=S@4icDESPm0^@JtS$2yOm^kNH_fg;jPU*NHEAbuh_bz`dII>fYeHT1(1n3H zhM8IGDbP)`7N4UbSpF`d0e*I!Wa+$0b$*Wd9mpdsQ~m4;YlAr!Pp0xbp**ddw{xjg zyQUgu+WF_jyV`lJN;=oFli778pl%89E@>xnnj$w`=ee}G?0Ub&I71mj%6RX!K4Y^h z1H&!Wvz7G|l+^IesXFxkX=UJu&;Lbstt#~g{Tra&LBDRe-|CM^JCQuK;9)hM5#eUn zmo4xU3ht)h^ZYP%R|ZNfaFK$yW9CQO1}NChu0t(wRKY70e3XLi?0T>T-cP{~E4Yh- z?d-a9nBTx3Njs5i6#SNUtC-jyBmf#{y?6c#(pCv_i^c*K`ZqUcszeAbFjF?d)225w4g*cLQnsF0+DHDA>!c zl@{`KMINWfg^KjD>wOk7p~&`%ywEp5vg=hAa+D%Ba;kSiM_lbWVYk`!NW;zS+KqJ6 z?E13G+Fu;%XV>2^^xIrV+KF&8A837doHs!2?7GZiSfmU?l;P%LpTT5TEV!ENdWXdp zQ?~t;E$=F;bpbNxjel2 z0^c9&NIQ{xl;=712Sd@G1(sUb^##LBJ0Atz)Xqy(QvFT7oy@KiES+OiXJ18@_AOZ_Ao*AN{YV)OW(y z?w~IN?GF0MmIc?T1@d0I6FOOqmqBk<2J$TM00l?X+#QySOzqmu0(Vky61NL*%XbR4 zv+MTrd`Emw8vFhzc$I?f?7G4Nzop>Y6FId7dJBD)J&ldf7G8LLRQjzd3#r6dRrXoXV(V|AMc(W(oSTeBFBsot*l|} z?0UJyFiaV8l!5PanRiv{Om>yGZ)M%JkHywQ+4fYnUsO-itYz1(+lFf6n6;9in`W&| zoT;5q|LbXhpIzTFY;4=Bq@BnjMNYWUH`ULsur?UCcqS{)t;#c~c{`U{*)`WN)6Oi= zP3;`2k{+Ds+sW)2v2?aoorfs0o8Je`W!LpX)GuscHEAdE^HhF>)?Vf{u=(uzxWzhC zS?4M1G#&c?RJ)FU|6kOu7s1zVc0CKUJLtPu7VNDS9HSQ0sPT4o{pB3LrQeap@0=+3 zA9>-`pZhJs&G@I(dM+4V{bJVL?63LdRsJG-82fsaz~ z5CwB_bC>M8pqcDC?ZbbOU0YA`9li4g-_i5V_I>vPX(#f2vAE;WCcH} z;G+uskopuXh`C`FI8VXXDY%P*?d*D_1@5Nc0SXQ&*vqa#3%Mgt4E~QI|I*0tvglo5av+G?dYos{T&#ot0 zT8~t%mn*XEC7w6!?7D}=@b_8L^y8I*?{hWDuKZq^t_*xisPRLUvIUgw9@P`TpIsB$ z+4Ww-%&c`A=%!igbI#QGWy0%dfS+AQSUQKO&e@8LSf={fl`jh)YVmYYo*R^B%P6ZC z{2F_ym0f>4QyWP;H-c_z=V>abpJgYr>wLq;B>5s~C$hgH-&LKG>6&?GV2Z^!UKzic zEUvhDq}LbCXV+6L*5j4+Ic4poL;s($YsY2(BD?m0uifmrFK9QrRt{EYvDL4Wb|MF< z1yj{{MufXEaE}F^uHYTGQ$eSnp<6nuz+?d*Dj1wKN-k104^!FF~H zS>O}}k5_O|!FG17$@Lq!inJ5SQ7{)bcge1AHj`a@E&mtUwR(c@=%t`tN1t!mk*jvR zg+d6v+joQ)((e0Mhg#q+3NBahDl4Q+cK!PdzlFb$b|Rw{T&Z9?yRNjr?<)8>1;3(T zFS|Z#As$$XFiRPFDZ?e#`V6Lam9L*l?OJ59 zja9Z^FxSEl$6@^np%%d3?y_rN!_2I880e;1OWxOaLbr~iBtN^RSUP_jC~bRGb>fA?> zWBfj7u6E6^7&|KCmn>SG&;b{D4QxKUejD}MxrVe8c|uv=w=()}RtDx({EO`R6MXGv z*Ka_(gMPGS!Fg&yhFZ{Fji;yG?0TF9K19L4;!XuE-C()M)UItU@L#7(+mbjn@AHQiDcH`guUOzG6+BKQKdWFnyH2&h6BT@lg1NZ4OLnbjCcD1B_+Mn# z2e0-WeLHB^(K}D`TlgbsCo&&*Pw?Fv7l<9=XtOf#p#`o~@NEj7XoZx?uCpxgJqjMK z;L!@Uv+D#4JVwF26@0dWz3e*BLY}0^){4wlq?cX0SjfEY!%uJGIDXIEGoyvE`gtvth&r}zJ|)BC#Op_Ys;Dxki8~&0Ga|@6!DG$ zCuG|PB|D}NcpwkBS66+DBJMIl3@;dr;cw~k%O(zb4cmJ9{QQ=%%P+e=7!3Jg{^3?r zx@uESU?qiDobsjhg0o(1UTV!xTl)ivT*sc?1iEQYr>UfqFY|kv^V34ZM)$o$8vEyt z7oAnAQ!4Sft#As>w!V{9Y%vxp<4ejoWvJg(H+hWKcd~LU)=Xs`udIh!c_@plyM7yE zpGE&-e)?vtpEkb$?WWBo*`UqDFrPH`+re!SJYA~B)6=zYBS_$udoA#73SOe%Q_l5U zdZ&WNTHxUdzE{DADOl3xr3&t6fqN@>tb+feV40teS8&(@w^T51T)~^HATnQF+tUKKQ1FQgUa4SdQ(LqNo%Z!9_%IImjIEBHkP4^yx==?}G#QAL(0GFOq_q<@HoJV24>De?!b5SqG5CjEeg z+;);U;c!J(=6OzNH0k%YzT&c&9PkP!{duIDPWn5pl4idm4%LZ~>GC$i$8nt%>7$5Z*t#rAM#kz;GUZkvlS}A%oS-r2YZtRC6 zcl?ufA_ptaoHKoOM~b@O>juo7cAh6~OvmmfPO#=uoN#yANv}ejxB!^w zdLj^8u6r$EMNckaCkp>k3$uv~FZCz}w|&uU(_;9t>`SRGA1r+NMA(Fj?As?u<9DG^ zLcq*x)MpUO+gShScQvB$`(K8W`w3i5+S^ZHu?paNms?*kj83&w9j~hHSLE4N_w1y; z#$mLF#rXFLG%hki8B+)Q{ff>oj8+(ZOt@*@5@qeKtgq`JlnA`lW|gj;|BmU}(~|v} zTeWLTj5Id6h_tt<+sCL7;j^^ScGvRD(*D=a2Uw=`RZ|{NuAsI8Ml|o~JuJ0JzozcgdVG~R!+xb9c3uFCa-(G|QvY{hO2?0*B7{l7tbyA^L?U4WfrL>0G&vIoyd zaGq!>I#Ly_R-SBE(bhL2-i!@=_T(oj7woSxKz@Z4$pgENFXHKifxU4J zzh7f`xp!*HL~JLRlZ5kP-?xZ=g1Iz2FVHVkv{#d}xKrSnsP5VK;PE(w|LFYNNqgJf z_f|V64KmK(ipGs}zb37>VBopX;y+XQO}xtY8Q`0dhM)U~fT63H3?jpD^07ci(oW<{ z)&NdusJOFy*9A2ozdz2m_bbv~CaO^8g#&$k!8ZjFeBCfn)$^pC$X$xAmDahchG07F z8+FEYXWq+*#`Ak(i^bl#@xeHm(=*C&b%M`~fB+Pe)kmu(XD!6ghaExwK2AgRKujeI z&{YB5!OIEWX7IC)B5HWO3$IW|&?)>ihSk_TJvrluK!C>dy+|Fs0CEC`MA+|2!k!}` ze^*Gej6k;$bh-I!^vm~-Y)^@X+>RLIq=kKGn4IHjG|3)7_$DpiDfJjG69)WhFdRI% zKDy}R--mqj^g~PG!R684zmH=7p33?*(aIgCMC0#8dsXLRP71%mS+S|`MqBH#yug1H zipp>?-9%eV2<{%*Yd28Q=S$379Dc0A2#alDkHZ?fRo?Hn!3gvm8umc+_Z|LxO8flt z+@(kwzwVfMUrhaKzf(=)D|hZis(%vXwEgdnmV^~ zXB$^O8XjNi%5T(VaGZ7-TyDO;3+rPQsSM=bQO1gIoM;B0CoWFzjVjojf%AcM@-pNT z9A>MU!3Kh@j~Hsax-6@&1aF4t)TV0XYj|mFNPb%4oL1<8yVzIQ91Xv@&h>{@yb^T= z^@I_(!z}uyi8unWCuHB)))Z_4xrdC9+NX^P+|RGboV(MULo?B_mB}=#nG}LXF}mmm z_lI1cG!WSXukb{JVp=5%t-%IJ0?ALC-d{|HC7Cco1=04zImi>nTTY&O&lqqmS^f4f z-XIuWOL1d5=B8Eg1+sF42&03WiqS=NuGM1CyPi-EX)~Tjn(jt#u1sQgXZ*TtQhKQ> zr=FiIFJV~>K%In&co1emF+Y9-sJ!Zzr zOK>ErDLwRoZ-p~hsaPzR;D<0x1 z-rIG^n!`{|(a5?(pxenqy+frHt>}i?j4mk@=w=)PjO$x>bqg{lb4Sj1Skd~fiGA4P z%5}~jPz2|EXKdsl;%iYy&oi(6x3OpFKk-aWBBv%+zsE$VsZkFdOkmWHTq&SzOw*7 zS`b^@Vmkj#!9-CVjhAt7M-%!Ht7wliH8@k1^Fcex)e8yH7DqM_ZN(q7cY3Bk%*uoioK82H~PKuV2@`s{LAcDuiRl z%!$aZVkNR$O23vxhk1tqY|ac!ydoM)wvS@RXWSkeWB}U{Bipvoc*S0I?s@D~?BxAz zj?pVE7_2|-M6Z-ArRPU*N-EisN2~o#pp&9;F?T?`Y%7j(<4!$2SM~w^<)2bu3)D_S z;;Jf}0rDywCxn8LQ1oao$|d;lWu z@<+2=wcRN&ac9(XXJU@JGhD`BmucRtHfk1~1+&CwMR>ze)xzuzJ<+NcT8a(4x;ryP z!2dQ=U}9!_&rI&qD|wE6rGU!h80fXkIG<*8v&_J(BR2BUyTiuARpcFr$!}mH58<7S zhL>%0X82y8Rj~{jl*yUkbzSSkRILG?PaoH z={N*N6Ej7iMsQBN(#*2iEj**h*bg?=w(-yHUf(2J-|Gj8lp0Z#7d6IF;F2D)a%6|W z>Vu%;NsbKl9lW}4cs|Bc3QkZ&+;b}~wGYp)_Riy-193Ob?`faUaL;3_b&OZ+8ly1T zd3|{!51XF=SkA2#k<-flXe{Y|^Bl{JTp4U3rZM|6;LmSEH z3mIZgBC9W#OeWwf^K_CU-KaAmGf{eCGxHcDwlQ>^+D3BMLj3A$@QiR1gyR)Fl^Wn!x* zGLlB#>J5S3f(4G{(WC2t7P!VGi!Alkk{6i}?78v+s>RmT4TU!)@*l=5^DurvbrxiA zwda?I{eI@Ob9|tLxcm~!u8;Kb9JA>b(vm2GJ+Iib&n{19H zrC{a@Jc!lb7%n?e?08cr!#fY854@X+1E~W=byXl0!qL5Nq8dwzh0SVJO*33gTpE{x z{3wX6{Tw3jYpe?}gcjH%@K_g)LSm&%nw;R$3&5tsKozP}^h=W`vobbv*2-3$Oy^{7j>M~Aem2za%S=Zhe%J*+YHT_+e8(< zWD28ILCrJlX3PNX5@i&^?cR|GRg#RTM+H&)1O0EGzg5mJEBganyuu#gl9p4ZDl3!6 z9Kh)~T=pth6J;H7Jzn-F&}w-a*s97_rNSUAa1Ma8HrT>f~?nry!y`$1D|R>$Y?GaQFj7bN`cu6=uYUCufIU|#{H!5!={9C zo#s^Gl++$6dP=Y0p+RXy(E=0{1}Z1QWlP0cG%8gEUyUa{loA)g;nI(ATAP7b_M5Tl ze+DALNt-dk9caTbJyb*;{hix=As@4P4eG$QQ70IH+PXF%ZpVY`#7v5ppJE*h23=?9 zDeFNfsWBn10%%bN6eOSM1in_~{59|04Wpl)HXT^n3G+7{;N(=Wi4*_BrdmN1g==&$ ziwmakdaOdKsJrOYc-aE<0dKn4M@2^?KYqeosOb{F?-N{N4xPv(28RWCBOh2`G?x+nc~%c*-3W-B4a@ zR1u)Il*&~Y^QeNR${9ay*aOo;E1Z$$= ztveqlAQ{*sC1M3wHk=C?+T~qwSZxjy`4!ri_pvXX(DJj$7)@xbJpz6-0Rh-hTO|Gr z-sj6fc=!7KZmm%?f~=WlF0IFYBy?lrl-r5LBh>!q*aSF zu=+9E10&paKQK$$o%)TmdpQi`d~daTwK+`WFV}WIM&IK5->%_ODLoB-x7}C5=ZTy- zSa(e1%w?rk!T9W(4z{={EQ|1tesGGfh+|5oZ1~%WoTM7|5e<+kqbed&w|erDokU&@ zi?@KtJEF0?F6I#XWN`E<_K>pG9)ydDoTpGe zgv<63`nh<{`b7SEbbSq$)0gq`dYYHBn!k2`KO23j8d(h^tJO&PeyTXl-zSXS6){Jr;-Ze2J@xd?#iWgaGdShBJ7u2R!&6%tbfz z!GQjBsy4jnWQhEkdCa$Kqd9aUd>;qS8)e&tCX2XX`yeZiagWZ#5es3{>p8O}2%f{` z1-Z`P*}QRJee4W=jyEWM@wlx3WJ1$ zM1NKARvaV70=3scSb3j{M()CW@0Omioh=JHm3>mUw-)Wjcx`|3B0K@`&zHOH3I2*; zj`eL(*t&{EQ6RRnMd9ADohgN9dfq zV@uH9uZn(X#OV4zxvs6HpCSv6aIeu{P1_^(-4O0j*gY%U;pXmn1Hv5!bRQYZY#pBV zA2*ud2R{@;JPQs}JIX@SVWXCE~fbE%``E$|gXnaj_D?%X}uR`2}OTS~E;d}X1;_N>! zTKNrrP#UNkGOBO|Mzw5*-afB=_JZC-I_=Sw!OhSab+7`AT$G;P5P9|i98=n4U=jnm z4{-7-VjJHnOvOVs{76^PUa{aSV1X4&^Der01V$8pUMia4T2*3b_rBQ+vcM?sk_-qB zsED@gTt*G?Gw=+4O*B3vts&A6Dv%Q9HAG&xpUOiq^e&#AUy6Ju@w>gYE4vcEOA6M+ zd8vT(1SB^xAU!>KGEj836WTTiZ90-kve5tt^>WFdOvj!x3Y>UCy zWt;FOp>tU(Y|kE+Jv{s3Y&>SsJW&<=2ngndcLM<7JI-R5#r`f1&&VMa-;ul;bw$?n z<2^OE1D9x-I3qQ2Q>)yRt>Jkqa}%k#DZj^dW`s+7fhjz#4v^T+)WTb1JJZ5t8+dNM zF`)pl9KVvHVFGOMO!yB>2o$43XM6x|+5>~acf7-c_zr4MZo&h|g81=l?9>}!z8n9E z$eB|SA)kbAAHu#)9NX@`K%mdMs5ALblP80H06=UHNT5UIM>Y9YL=+*mqv7-H*iuC2 zlAZ%j?9m#qo2zTvLk!{+5@qojj*l;HHzYM&b~EL}l-dFi-uR2{%nFz7prMK5wLR+Y zqJn7I_8Ue;1W`ac;ZQ^I4JCOQfGV=9n=!e?-E4X$Xtyp5;KkKttP2$1@H@AV9sf8Q{~QAL=u=^U zOBSJ~4Dd!KkX(UEEE-?J4m>&So85H`G0E>NkAPnVj#_SkZ+FQ|mih&)}6fEtH@ zN+z~rshrm7I7q&M+*5bAXCK6@0aruh4RZ7bhZ|}7iF&>ybMS@u9qiF(_lu^iEXmBv z!Q<;x^hPn2^7^Fob}hp9RNzz=#(y?omErl>9S7i_)|iG<(hE2-9F^@vk-*x=bDiAf zJ>Bs*0Kc`Gi;JJ5e@y;>XP9ALQco)1=-P4Z`_0Qtm%u4tNcXF94 z$IrI?gM>Ji`d1W`^wn<4^IcKcHon}{Q^qGhh37|G>&a4fA1bI|FSQ>gQ^3H{dHr%z z7MGmRxStD3Zlq7QhUfQZ$M$E(w$P3}%rzaQYc)Dn{Iosm;0)v#49mBoyp2ScMl-96 zlK+prH-V3{s`tjvGfQSBnWU38ZId=_rz>e`+9X|QOTnaBn$T<{X=xGebds4YG|MoP zbOWUVB4xQ&L@#R5h@cb%5m68o3Wyf;YQ+r{rJ`aL(TW>a)cJqE=bUHenI{X#%l*Ii zeqQGDIrCf2@BGewp0gihsilVD`-A<|n-Kn|QsJ*>`O(G9SAX!hs`sjt)laFxsQ>t5 z>GVPR_t8Cy;p&QlzX|F8 zNZgNoQzZ@Szaz`%wVM|G_4p$v=b81P@!C1hRLNlka{Nq|h^DUUjZMbWW{JpaWb&uR zh-SI?b=9>8Py^Ab4F6OH4S{UUGQ;=O@DsHtyDccY&DVEihVLAI)4^k?E^%LtbCb7m z{ZR~75WvRuPmMf}(G0yqf2+}W`o(OH4`f~xpjf$3DMvim4TFmD!*@S%*)MCZt@k$> z&(J}-4LG;8{wxtd#X~ouFkV#uu3t;)3ZJMim6){M^DFF2t_O4b4vSlAL3d)E3Sm9CmN@`a~VXSz<$@K8;SO^qBL*30qe@SS`9nsB%_2&b1QNSgQZ20?hk%L%?0q*&MG+>^7vU$gBdzD z=D+ThopIIvO_)Ej3!0fla?2vJ*V=-?J?G!t2vag}5_i^ zYIv`Pw`h2ShL>v?*RWH=HVrpvSfSwp4X0}8(D3D}wEr4DrQxF*-mBp)8s4DcB{ z?9{ML!%Z4iXt+SbsTw*oeEHqle+kp+^Qh+EtKlsg-k{;-5}NYAe*5B#E-F74{2l+D zsAMnK{3$NyIsV`N4Sq2*UBvG*X?r@6wx$?b>5QM<{=msheWNz|l#MR?b*B6Q8yyQ9 zG9UM97<^I5@6_<9mOu3y#jn)xxaNERp!j|b0~)ey9Eb_ANYgHtt|Rf{-Jr|Xv-JReW`Tl z;SFECcv;;wH_Yt~zwnvUf@gL%7kuM8`JXF?{Eja@Wv4gZ@ksZ_8b%wA+!lU*&Br31 z^WH!6@cw73TE4KW;>??${rqQVUmf1?!hQd>Gzg&6819N-Ns$5?Cv1?9+ zhd%v*%1`e3>Gywq(FL16`~087q3_loDSzclA9?wf`>H?qovUu#vZLU0gNPQ*auhI{ z?Wiy`_h7DvW+%q$G)Jc@b6_#bAq-BsNh7wvF%72Gr1=>j&7)98^CxXiqJIXnI8m}V zu{^jqwlvrk?nh=IvH3#|$D_j|@j<3~duyn+tu0j5ws}Lad8EG|R*8}RVPsg};BYif zCzH#|vN0GQh-&RZY#Qn7k5G4FI6l$^kD|fup|~n5i<#s4H=f?6+NKS`Ru;Fk;{gPI zs7n_pIG@}dgA#l#CoNl~o|25T$Bsa?am;XSO=lUu$WSy992^=BjwGVN zt?iqF!}0K7BJFzobZ_6<+PWdQX(SO0qgI6@5oA{)xI5fG0&QWWG&P2Iqwa+}`*oI# z7Y?OoTSLu;)`ptN+_MnHY=x+LD7G(EV^jHrNXr7GqhR$FRvES2>ZW#ZWFQ(3r<#*= z0kLW@%W1lNu(5f~eAY!LyM_j0{n24rGc#=x!+oraBZI7@%DZvPJ)^K8h~~IucQoD~ zj>V#pHd%pFEihYMrJy;wM|rDie>Ac@7~LHm97e(Ek4M9ieZg3CkQG<^mzGz-2=)yI zJHuVOdg5%-wGh%_ynIsOIuDVo9vT>^r8o8v>5^5pck$lL25LNgvVCe8L_zP11iSmg zJ&aQe!ka3GW-P}Kk1RK}iLNjbNVP=cwi7&kusAVE`=sI}D{wW^Y&cqnube$*uj#%$ zDwCz7Zy-7}V)X!5 zP2t3@anf#Lf2;e^0g(kN9v_O^oj!RQ>LW}HrW$4jOv%z@^3{@L@>?(;hZ%-B^Ymmg zALbX!lF9pFu7Q~-y=A$R+0BM^2n7!1uDX9H@jA<$wYwg&LiS0#y-a@uP&rKmhX!9?|3c@-NW3S?a%3+;;>5~i@(VBrVJ?7K2~!gf_r2bB zM(LL!WXrHg#w^_(&ZyvQ9T^STIZAyOST)(#Hopz8r=3lIJEUvX^|mU}{@UbBFW8o+ zzVrCj3*Zi35NDO1VUy{B-pucIGSKU*eO7MEe{T>HV+;I2lRJo zQu)Cl(+N~lGMY-6NU(2UAR6gIE8M@2wwCmiCEc0=Dc1}@B#2_gpvs?3DeG2FTsnelF5f)-UkzbIRhpmsV&J&EljtO7z3UPK|1viVp|TfQ8IHe z6`!iazQL~E_|Ty2XH1%8Hx@OkMQkKn z4AJOuh%^ ze3()g0aMhTO#Z$tnS2!H12DZXGI_1unPWgJFO_(fhH#Sj>-H9fqi!hPgo%ni44_&% zFG9y*%vaV_Z6CgxlUH3sgWY{SBOH68l#QLD7%yFv|IonRL;Em3J*kXKecKzc18@gS zH%tQN01TsqUazc8Z^U0&4$&YFb*YguKTA>F`$^A?sDv9Y+!_6?SQxJNp}!@=^ZLs{ zVt6PP?8LY=)8%XW*VfT)b@H0>)&HV=O-I|mq`#*9Uz6Y7(!6qeOI@AS6D0L`@lfRh zIXy}F_%ODd4Zu{wOoMp=yV19HUnY;_;0L)dFBit}6VH_~uhy6uYp}zwY zfcg2mF;;;2@_P_&m?+FTm>ihVYmrVcbudLRzr7}zeEB+r8|EW0gD_PvKRA?39)Y~Cs*VO*E^o>)Fo{JJD8bYsJ&_S&|Fs>arq zwvJFu?WV1pu_m%1D9TopuP7Jg8_G76Gt}uHx)nW9wO|tJ+!x}6RN4}l)qaen%{~%M zbjADRvQ0{d)qQGmIc1xveKsXg^o+8Uvbv}J?!HJU))z@>u-gxW2S>WYa>74O zA-jDnJ`}-vz=ZDAVpGaG!+j?vxQB-@31A7KRe!IXS5a=k@4^hVT!|tFbT`(RtaN&% zD(zi{oLtM&c9>#kM>xb;FRhOgL6q;}RE(*D{%~r-LPt1tVA5eZZ6?3m2%wz#MaRRm zmEr8f2cBKwkd#VWNeuc2hXyAWv4%6$*Bu&+MkCR5b}_su$L!JD)Q_=;g1zb7lHs%Z zKSl-g%O1Q;C`4i${i?@4fdJzd-IMNWo9~6B} zp61J}WaU#|L1h7nOj?B}C1UC`8K5&%fX+~%>CW&7iotM{>6?}hrPyY4XrFd(u{ZVf z4QEEsrq6C|*O#)_`cyA4<$J2Ws_2ErSljeXXwP0EI*AEed{gX{kD2jJ+iO0SkyD}) z$&Bw9Yg_oz_NG6R>%#yd(>t5Kw7u3B8J4YF+EHfs##r0*rR`09iOKcZt?l|Ivfn#2 z7}`73-A#E*`Ae}=5zyh#`Ttt>>^wk}UwExSyB}kr{Y|KDfGlUKLG9%CS<+Z{3TY}8 z9EP_)j2#70PWGc_Mp7-UlF76mz(OeYFQlE*y{iAx{kZn5Z;@!{NRMt{Y&l?22K0aX z{)7MR;a{9s+#gwiZZH6IX5xNaJGM8(YWg-~7={v*sEO_#(}CogPBVL4SbC?qK>k&? zG_|(0H+0lWs;#A^L%_obyhP(Lo`3(^x}sf!+=gJTV#cFASkjK~3+{??HoLy6t>(O{ zw%QA7YPU61*EUtPUZDDy2xF5hn09Sk>{k8XwrCHvZi()z-8*)E;@pvFT&~|+eN=k@ zBUl=o<9narPcQT~*y&etN zwxT9UhOj2C_cm}q^xFF5D#f@9!|7d2!PG+Yg!&q}HGymK*rK7gmk=aGAECM%8{euZI0Q6}|3|f@9=ujH-AKwqgtp2O~oR=(YxB zyBjR2X=$ozXkIE()?E7>=~r_|CG8EHVJCmwf*^;K*vNv7WZHSlw%WG3#+LJzidN1h zV>cQ4%viANMiJ{7?Cb993J-QggC(tvE$!`6Q^(Nogi;+TDIq#~qvmd(ZOm@$=2o?GZb3~cMT5h(Xo@^4h@8ddlA}_rJTa!E(eb7day9ivoshi z!EOnZ&$B?F3~m2hGUnx51d&AuOgY^`Au}Twa)l&q6+xp_eBjJ8or*z4Yqvq6FP#EPZrNzv?l)KjW&@gnF zF8A~e_hNV-i3YjHLO{P6_gEr25*b1gsrf|CvBT+57p4J_hY3!HE>10jOzKX~2BN93 z$}_Z>BpmArLXWs(48Yu%g#_z?VJyX}95?ADStrMS2KjYHacRXciL!SqmSC?N*i5oqlK-V2-xUC8(m_fV>W$dw)oy-w?C1Y zK8K#kq+4zB!lrL?b@hf|Nn3PxdD(JoiR;6z#m;@fruH4}6)ewO6IdE7uUJvBqD&^~ zTk>zE&s*i;t@`p-`|wtK_}}rpFu&XXYa!0=8ZZJEdj|kl*AZTjvOI3^?ISFy8}Cc+FfPP5>u7 zZJrQ(oq=#lP>5H66L!u=e9tu`T)9w)0C2*;!4v~0Y*`{i32?&U(}Y+JobX|cTq=PR z-o6@V<$)7Ea|Xr?zzMt0M4A96{M$yP18~B1ILdh`aKew&2yr!V!a#!%Hv%WD!?}-9 z;Dmo@72?yt38$ThyCi@Ue&Ovxd=)rh=tATZa6)fLh-ZNl`gh`J2ynvDFpi7>C;TBN z&e{wKPjy2MIAI=EGYWwdUWd85MZgK4$4prnaKfd-$YbDy55v?0CyeaD7!5dK|0P1~ z1Ws6U8ED{y^A8BI7dYWDm@9!3j$VlqfWQgg`EDT&11DT^719?t;Xe-waUXEPXRpDT z8Q_FhUMs{mffHWvULl?aPPpNa5WfIU_&m%h;Dis}D8%1^6W;Uzq*uEkVI|Jl6aXhI z{4mNTaKgX9EC){b(T^bifD`Wi7~%$;uwxWu5jf%BVJ-kp_`O?&=mk!A?`~X11GG6X$4NW1!g;N34!kfz7vqI!Sw52ioUjY# z5OBg5VQ!*4VAYqAR+IsJ0OlUxgr2V;t$-8$5at+g!r#Dr4>;lShftn?mjS-#VbmAk zgdaVM`U0Hr@kfLZTMY@fJcjxLoN(;Dq0TSq+?U={J!UzzOGk7i|S_ z!YhA>Gy#4BaMshPKfr^4*TD1xKLq$0n7zR70sI`yrNEB@{vPH4@Kb;nKZEoEegNYp(Y$dM#5z>b^;QL|j0X_=o`!VVf@Bm=^S=1xo2LONk9O@D96M%D1pzZ(<0xpO7 zE$}kHV?RSZ0)8B@@_Cdc;Dn!n@oqyn0n2}mdIY=@u;Le}N5ld9VM>6<0FS~f2Tpk5 zFHx?5?*u#nvk^Gq%opGX@F3v(VQPSn0{#G|o-%-aze0Kfj{&YdiSh;<=T5~(VLB)e z_&m%7z;WJGEd4do892_GioG!Xln1<*G;o|D6_3Fj0FHB`V#9BcPrz}ORNMh`BXFDp z72krnl`??8g!we^Q-FmpBAtQbY^vA_^8j$1PZb}8ISPCf@CPu*fFJ*z5Z{M64*dVd zkG>i%L%23+*a?`OC9*5B%G^6$F=wmes88FAmtY6^@8P@uD;SmqLc9H+!1EL+d%~1{ z`bFb)y1h5JoJOn0;}*Q_b>I~i87uyJ+`b-}e^qB(hbPD7&N1c+QZkMv-yUCU7)%-I zc2?T$y_PtdGSp+`PlQ|Lt$5o6I;}Dl7MY3UZNakXd3gfdDsRQD@>aeT|9@F# zqI77pr1R^+@3qKVb((mNYfX+btJ6`2^6YZBDgA~a%kFq#nn>?N^5mQ0n+P{`+U@VP z#CJSA-~H}T^&EGfaGpZg>BlYFPq#z3D~vLG8!z=#Xg$_&n(_=Q4gE9aOr9OmKYm9DFSkJI zy5cUfm5+`inYGe5cR|8w_Kd&{T95v;8n)c zJnv-~D~+H}W8u|+_W*c@EWBRuPJ%aT;oS({E8rcq@LmD0a5wx;r2W`<0Pes$WZ~@v z?<9D~Exb>ISF#5>Exc3UwSqU^Z&dT|*6<+>zop^x8k%nZqG|75rEivoB^s{Nuuj8& z(=evt)fyhw@NNy|qml6Bdz$`*hJVv=#y;iW3Jo`CSf}Am4KLO3Y7KAF@RJ&TLBnGj zKCR(jH2kNA{{70oxf-s}@N5mYYdEN(nLhh9eT{}6w%OmR>H9Q%NW-sbcw9qM-;Zqc z?=+po`F|GAud1`KVM-qU z$6hNDA;rs6w(;_pDv=_LH{m&Z@#JMv5mL)$RrF8eC_fZ&i?|9(V<0ic`z2 zlR{iCuRPFq4v5Ev<=zQs_@<_LBDP8t88tY^KOC**X=dCz)UJ28ECqjeUstqYs9NtD zJMNL@?)Ra^=}P%pW=+)reiB zIwp6Mw%?T^_B$H}5n5a>vVTmtf8cD4hIfx)N0nGe>55sx41j{6G$9cGQ@Y>dM}dR zQzXQ9O^%EnW>4KbZ_i-X@^%;TBS|BdY^O3Y514gcUnE-H8;*AjNy|;R6+jec@w~gd zKSf}jA`}aSqJz8paBN)&hobkGjA^0=C2DXt=F^1SBhPaJ1Kbc?B#;N##e^AC!Ogxx z%ob`xAm(8O_7_XbZ0Jj1Pbf~9=)GR(J%CpoO2ndF+=G_h|GU>U5FO}>?Gxf1E^Nod zeP?muR^bU@uM&L9N>d1tM^k%Xxm(N>p|0p&o)akorVp4#akd8)X%F4Q#Vo7M9wd$C z&jlYx8N$P%i%0spc7>Flc_vqqYX#0&m_^l8tCNX)_b>~eAtBXg*soXi$oc_Mt5OqN z6+^@OVo_W!CR4Xh-Lu0Z0N5c5$#m*$7vWCqoE1BS3SEy-+qya03WdT9f8S7NsC#6v z%gjX_b&**moGPWd73Bhz7>@J}A(BqUEx+#R36hed7j6xbhLoD~XhESPe z(fIJbDsi4g2908Nd;j%wt7Rmhw$W%!+e5F*A;5q}&z+Dui= zwyM^KRTV2D{rwavfc^gzv!%AJxwbJKwi1NRG~rlZ=|G}%Pv2lE%5$lu_LTOQmzI~7 z=?HCv8@sW&?Tv+7BggKBIPy;{2!|GpsH4<^o9fGcY^B)WQ|xQV88psy=Flo;wBE=BioLpU+8 zVt4rh93jGq67-g~sZ$Kfv$L~JNTn*caGa`F%CMH6W zD6R@kO9vApF?nJN1Kr?x5EGdSFh??QyN~=9W5;@TNjB&qpKpTy35{SNuD@G75le}9qXTW$@4lD}#R za!InWZ&CLDzikz=;Kjfl;=6FB^;_(SD*Hz&CbC!l)vPk@u?JH6=d|fDNu}?zD8}Ra zr}UMtG40Lq%VVYj8&vv!vC)*bS?lme&YH+x`S*S7@>bz7&%3>1SEOkrZ(t{bmjBV~ ziSNIs362vE~#iG-+I0&kA0w0zHxkU9se^gH0AALO5Yb#_SiEh z_1!eypc0Oi{8a;{zT-br@|~)X+SP0SYxkP+b^(=tU!Bli`F9QGvs8Ll{zCcpmkA1( z(zoT`O?kV2O5bxSd-MI1xpqNKEBW{hratq16lCbQKPCTr?pT-h=KCq@$CWnI^O_Ht z^4Rk#)4zUF`BgWY^5*+1sG#HiRC;`4)ReaisqpUjq-k%y&oX0z{It7&i~jFTfy>d7 zyRjpezO3Keyfs+8e!V^~87v*ZvG&q|;Sr3_dZL4P7N!d%UxPVo5a-4R(dF+6mbO#` zOEL9#R?pzb`t`zJVup8|4~fsn>cWbUScvK^vU%G?Xjr%wElahvKCe4%Lq_%p{$s;&I^H53XYZk2(w&9a&@L8!jT#-EL@%$P&eY~|OQkNQ zl(?J0asPo%TppXS3REW3@TO=P9d`p7v%FC4_UhW!j)s=zP+M(vOIwY&>FqfMe}t8h zT7IkM^3?@7xgNH@X?7joHV_vozRU4ZxcRr7`85FEw2;0@K!kE~FN5=d(L6HH8I5Dz zK&{s##7?E4Fztq8U#@=f%CT@x{v7m!gJOfXl%aAb@wXyW-O}7qyB!Z4xdNWWFX5|i zw3gQo;f|DiPwtQmW^09{rz+ZOw62o$G(`uD*42_OP;{Zux<=B|6&*BM*GhVZqDu@e z1>=%273rCt941DY(X_W3ml+i*ay8Z*da4tm$dmmy1Zf?~nuM68$PFZG6JoX^H%QW%u!?|$@YYptH@18t@3!D@~OtCiI<6>3R^vhaxq^KtspAI0!3^Gu}Umd z#7+=v#Ue%Yf;dAgRz%Eb3-1+66tUN6>)I<$Q^WzIEwWdXDB^0Pt#hwfs)$2ITOuZw zDdHyB#Kh@}7==xrSgwfMp`cHcD&iiaZJk)5@CS^x^|WuiaML+vI)=~F$v)Eu{*C^`xIdfs< zbGdM*2^I|93sE*VdP1R|{-I8}tQ_v=#ei5<7C9YxvdJ*AbXz6c0-wXJ8XehCZEb96 z-W+P}XcJlGE7-~@f7Y%RS&vFOt94sTLyd6c82PM|S(F!!rA7h!hmum9KN*WZL5@_Y zSbsK@21~QkvbCe3xmGy7?O6IO0*<%LaA*vOi%p4(t%mDwCML34$8q_TBRC@qZNnpw zJuB2yUa_tU$3h(sxl0!urk1WfH_rMcb^Qi^Wj+t$Z~Mz*a@>a?3il8AHw`jwY$?Xa z!xgGy87NeXaTP>cSWc?|f6~d`lc}5K`c4|?sUCMPp@=}i7O0pp3c$LUftQopd_9%CS ziVVpeDPF}Z&XtK|HUa|#17_e9~ek;vpqR145QP{NUs(-o@|zfQ5?6mr>@`Q zUW9z895n)t4W1bfpmoWu$4(hEHfMUgBt>pxv?q)$G#fqMly_y~ERUDvZj_#vi?bDV z52*_AHbosJwMtYf>Nu&@qDoOGNUaf@6m`lEYOSbN6xuzIXNVd_1|+#o)G9J4$@QX6 zk!6xZOT1apm5MGG^@?s)bcJY8^iD;u66Yv7rs&mTi=q!GdW~pQH0DWU1!IdWD;Ul^ z3P-?khNpl{ad}<;a67gyiFF>9QIIIdlCfSgHhl!#fKrizE`d~0ga*Ov3ploU^4L(! zxDZvl)Rf2*S(X+IUe?YG8z+Y70H>`3Ab)4u=b8xTN=>iXloaNeK`e3U@1F1 z`*Vsm16MT)-GjDh7wgm|IROUIYxO&&z;S7grw6uf{w=P}|1CgKGcPc$%P*Us0|M7U z?G~FAkr9Zt+RY8^9c@+C{#u|WzksfmJPAEw$r7Mm;il5X4f)Mfr!Mi2i*xde*{&9; z?NxEHMbTpM1^Ig^SJ#K08Ec-nFyG5|w@5Eeh=0rX%FbV2sJSE5(XdIZJ1>7>z>j#R zK5BBK$M*ac42o<^x^`^}bOrIknXtq2}6-5E8Rib|>3f8bfuBRh!!dn^(s*)28O;qJJ=% zcx`jlrp8)fOe)k=wLP?{s=4O8hMJCg;h0pmroFl~)KRq=2XH3ycUx6sLyZos2L+^| zscLg=sHUYoR9{<#>%&ClA7>YI<{=-VxG}7!uS@)Cwx3;6GP*kZW8%+>c94#VzbMK@ zD&F5E{;KFKX&a9BM&jZX#qxqR(1$y+xsmO^6fc{+@Lt9Ho8tMwOC-dripnDu6Mt7! z0903EWI+5w(NjUAv-D3z6-Zl=RMZSm{oP>(N)*c|6oNCf8;>p-ik<};x2Fk5v7a$6 zrgd}xcRxFo{UXi4m_oP|Yl(7FA>76OINX$gh9}smC$ftD|BiycQOsa+(NZ=uPDNjC z(ms(jCe0n5Vh>A9R_l0HMfbz4oAzdQ)ipHMn)y}GSzK^%3bLmu+=cg|qM}QMROsPS zOSj&enh+6XgHJOylAy9iQLnJ~D_SgvXD&n6l#ZeHeFL3C{T+NHhAnsN~z%dVEpHW1C!N#toTehC}C|;rCVhDUz5yg&WAnsK}P@d2DoFW$C5FB<5 zsUVg(z6;{>idg2z#eCBj6tUd#2yE_G#0tko5DzG#%yA}Ee^C(?j#pvxpi;fsfiunG zONvi8ar#}v`w_&pSSRT0}A*MN9j5f?blh1l1Mi(41d z<@yOls9gVsBm(P7&Kymtkw&rp}qi(o&cT zMTUCEv^lePLAm?)kTJuVmJp5wbLP`?)2gGfJyc!Q*tn^xdW&$h2WQ;{%Z1lc!@c+` z`#S#AV3s{8i3#^N!Cb@-&W~yPIO}9~Ye!3KsIhiiZKGvw4h<|ipTe6zlX|inCl#8y znCfbV!#&mLv^I2Xs%ozl9v8bcz7OPGFde;`v_+_CYhy=4M?Hp!HMKPeK*cr;7n`>> z$!<`#&yn@QOgPxq5vpx!?bxBv=BH@K0VH1`6=JGFR*Pv;WSuBbjCEqVWI*i<#Q`>xn4HxpB!=W@N4kh2 z5}XN{MWnr|uC}VJt!jsuO|n|y#l*Mb#^ajWI!t8Lh&g05;{EkDF;}7I5uZm~PqHo| zjsb<#y_m#SlUhQGAJmS9rdm-+YExs&CQ(HUdTOhh#3qHew4vW8s?!#=HM(mnYD|eV ztClRPGG*$>sIC*6C2VZRlukWST!Y(=31PU@-Zf06OAsm~$tk3_$qzb)WF%Bdh@ceQ z(N{$5$YSji41wzfCn%9effD9hu6CN`*O}M#2JQ^gZ;igpnRkH zV6#0g_#KJ$u~X>3#Jvz=b)36WmBfE#;6vazL!l8orfD8wh)7O~#*Q%50OhSZjuR0M zv6))@SGn8azLZKZ3x}quZ#O!?%1=U^De+%@`fcM{qhq~G_zxES3byXw;;%kC)Vi&1 z8}2MC{4%BqKsAt>K2y#&y#$E{oWIZ~WkgBdC$e`HA=dJgMBc3`%CqFg|GeAsY2}@T z!yV-!@00#dKwp4Vg~#;XYJqX@z(YS`Ns3JYVyqWi&6Y zM~rG2l$nTim#CGv&snn5s6^{1$mPg;a2A?MXHaw936Sm>e4mK|78CW_zEInr16N2k zVVt8>^Ga&cTeS9osU3U%aEo#TVG)hm&Trb`p5;&%r>I4fw(^=*vgF9J+B}^l+UIm> zt5o!c`XeX)X6R4a@dWa&dFrq}C)AG!6$O-R*w2@90=rdIL)xk!2 z%*b=45xkw&vZ*O#Q4s#&d{R%CY!~Ni<)2u9m{G*2%Uuw{sUpm-q8ydx7QV*mCeH^} zJc?LNodZQgL}3Ukndx>QT@Ko&yaMYpDab$J=G;{w4%SR~%+5P)HH*$5oe)7FW6{1< z>(++!c?*oU(Mp9`R*iFW=g69evEhI)*3LOXS3V?~{1bCR;ekYtIv?gAD14N*GG*qd zqkK~@oAm?o6DGCFZ^8BCp7h zj!vf|{t0&;0yD=fKuBKe(Yn05yjv;BKjA(f|8n)Ak38vmDf2-#3jQIPiA&}2KkV6) z-ymaU9z&*>s_pZ9zK|^V2$$(*$N%qz4^yj*d=tI^JbC9iVoV_;P@uLqFtPbF4(DTR z*({Hy86C!K)=6$L!}OJyTcm{xQJlO+oAVP!8!mgq*)h2_7H>zzP>j*$B`_&zktM@}0=ZdnTLX}2G_qxB7j6oki+#;F z^QRj#Mo}2^3|Uc)-&1Q0Gf}$lZOk{OAI6s<5NoY9SqqHmF~l?wYwl1ijPQ(wMlpwi zX(oF3#v-Hm7<%7g4bHBySXASAM)egH&oG?0;!`%;t$JIAarmVLLd@eQRKBMoew@Q9 z&XG6xVqP~VI59Q!tYkNWRZsRH7RT`V)KBEMG78SyVU~p!(uiMC`rmcK?5l^|*%U5rYT zzeO{DhA2gp3Vce;qeD5Z+WLF2&N-$DHsU$I(*zs({3;zIwtTnffV7DGkY-;8_JhjD zV&hzq^KQ-OHzfay7NO@XLdP}#MhJ;BY(@V;7X4FN0@~%zIJ|x#iZZ($U-nQSiu4P^ zl$Tfz9ttnKkJnlr}v~tGn7%ce7NtAF6PPjmUXHdo0zh!xsw^$b3x=&DphO zx_CFpAh8|$1GLN?)@-))$h&lR3)z+KWg**qPP0qpb?gbIyE$k9q({n|AqF_0vxy7e z{27OzT!c#Y4n(p*TN!LFFAj8pe>&0gZl>jD@%KJBx)!G3t00a5xsAj#ARYqpWf$=&a!Su+bLe2Se_f>6#%q=LWlZOh2Ni z?ZJLdEk|c?BEZ-YjG4=tqC0RO6g%D*6x%}`wVT9_=Hcp*I8XL=L_68O&D{+zoo;%( zJk-D|0@%hzc|sqHNj*_>dFH!W9yYj-L2guzHRZ%*PCg1*6!W}w~Ts;wKl z&@Oi)_uq_NXlFaHdI@9Sp8Q`6#$8K?R*te89%pE8QtaW>d!@9l1k=hvHux*UMg|))(uxw$- znrsnFt<~{!$F;guNH$|KadWM1QX$(~-K4VVwYo{gGS}*I?UQm0zw-lmyBPdQCgrls zNjb{9Fe&$E7aU+lMNi5RRg-eWI4LI~Cglh@DJLN&I49l;EVCLNF<(5KPKR5lqS{1}5bsgOhTK!$~<}YEq6^ zYEq7boRlMCnUo`GPRbF_n3N+!Ps%A&P0A5BC*_En({PJPq$lM_r6=V`sYy9v=A@j$ z^`uq#SX} zq#Vigq@0CHP0EpHos@I&BNIZ)B8;3s3uSKu*|&=zXXWn-nlBZyc!EH zmpm`K3+AL*h5s1Jw9i?l$M69?ILgA{h&C}e$frkQsySF*V;s^4D)7mcKjZMnAT|wm zPRjuS3E{(S7(;pwT!=F(2@woxfs0b^d}ze82N9oySnwjaKY~x+gURj_3rW8W{C6+~ z1KQ~}=$_7AjM+-te2Pe)3QXG#DW5jOCvQy5C?Mi<22SZdy_*Rregn1qm~eNP_s#g2 zbmOCOHq0U@eghwmH~gu{`XXZU|Ht>j`lawp*7U0{1%qYaOA+|r@ul$DzZ5cAKaf}d z8ea;J`K6$|6JLs_-uhBt`G!sCTVD$K%}P#To1R*}A@SexrO2L#qUv$69J;Oy6rve2 z#;mA-llm6O6%{K3b21K*LoKeW+$_dfRN|UoMdj+#+0u=*l?y5diz2Y}doRL&ZdwMj z$Q)dAXpq1_>e}EF3~b7S-CbS%I8bj|Uni~IyPzXyrq8)ZH{kATs2Yr*$yiEX7Wkaz zvvuyxVB`gS&Px4_6PLjsw)T5CaC!H-4#Vt+PY&z4nGtkf0?+V$)uD5$-oEI= zM~y+a4MA|c8A132yuJj+e%SFo@C-eAF(w?n81~VNG45E!P@xA%ja3ZWSOxUhv5H|I zs~F~31wpfpRSfG`#Yl}+jLfl$VHu@3Q**>dzQMUTdjc4T#icsGpL?_N`!aMBxQ7^* zP$R$1B~HWR-YYZPe2~!0?9aeoW_B+2&`y0bGW*}4a4n4eBx()9^9C~8nLZrl*s`3{ zg|9pNy<7r%V`X5P*C~%C2xsA(Q_$i(uc3JphdIv6a@qBCD&h*+4|S@;7S8LXXsY-) z8`WV5=ZErVphitrnv`d9UH<<%-@I0xIZSXv)Y=PMa4H zd_UvheGz{%1UkL$|6uD@%|BvdrrtqBr>VV&SYjw~Zw(ea1_xPkVL@+3Z0T+b?~z;i zwgvO=qx-Dd!N?fP^OU7GD`nF#h-Fx@UGW2Hel?b*H(^;iA$BOc!YsAn^89Fg2wRo< z#reTphBlaG-)i}GWwA)O)V5N43@!+I7~%13#ZYh|2n^{Pt)c?RRpTu#*q4)t=ffR?-!MdyshL@`M3btnofLFT=J@2s0M*{a;1 z4@}HTrvt~O!noR43%=QEuY?GH#^FAGOU^*j6jB5Co%&$1oA9@c1(Ut7+2m}(-IJ! zJWqfa0@6d`yCD7p$a`S|KLHWo8LWBK6EvUvHIdUzg^k9o_z+61UxK^)sfb#?3FJu< z)cQ1#@4@6#E1Ribk)ZY@kXK&KTeltGV5w8%RglR@-9qFw(W|twR ziw-MCpmI8T?1MFuuJ#JXi9oXe%o5|PdM zXW?8~#O2Ez^9o|;JjWD9xfvmJxAX5hSo?*GLH3Y~PiE$A$Ic69lE0tAKVe+*Qu}8d z*gr#U_99~(UV_p&C8jnSV(ND;X__ERK&HKs8(^x{gRv1N|0Ug=ZHGVXqB-RP>eLzf zE*E|~oLm5YWr?a6PV62?fVBgA2%K2|b>22}0In2z+$EMJyg0E4?LbznaKW(8&mmaG2>W#5vXkJ-WK zbsvC_KIZ{ji@g>bwV5bChtt#Ej6^BO#q)^>i~af?FIw>|Y}Oha=?d)*hx&QPv!ieh z)1kzhUMV%L4ukK}697v|WSKUOd9zq0F#wmBYB(1zKStRJCkZ_ENrJ5O5~p+f!sqFD z+-U=knl=DPO&j=Rux!neXS}%skA3c7nO7ZY7p}rN>>Op8<3`tIxwA>j6Z@`fi@1>` zOPlgg&Y zpp%MajzOn~nrfSHjtxgT+Z%8$rMa%94clR{U0#&^arzQ;Kpi{@W}a&M)AZanq@!?D z@x-LuxFAo({#o(87QXp>!C$85GIIkCYy}y{GTG2zLqxnX-Ty%_3miP1J~SxL$o*}4 zUNv+VIxuv_j`CNPyP(5V^moNr$!q++(OuxeS(^Mj{Op_0lYB~PJ}3VWs5_CfIE6|N~G3)8lZ*vW*a1hAbmA+A=o#SV3~5WKTEJvc|^U@&EAb$N}l zT;Q-zx?HPNE<#;UDQruU>*mb47)jz|0+-qs>e!-rK9F}ehdGmM>6mLS)KT7xg}Qa< zs&kp@tt}n@&o0#EA^WZ8tVpL8>PVOiby84o=^$>|(m^u4rNcs{wseqZ-O{nb9OwAv zXCFf$bjyK`Z*k5FluS?@==hfS*t7Av)j-F0nzRhK)j-ErB5eyna-ic|D#>Cv)dL;h zGRXpr<&jFoYgeWlHDue=FWd?1~kr=G@dgx z4?x5c(Glz|k>?;ncp7LRw7XmwZ*#7PmLmV=2dONv4+kRZZJHXCCO3zN*r0!oBymm1 zB#N;)ev9)esko^SopHCk(E;8yYu%EDREyTVTiqy*E72y^z8g-?bv_5hE4SfeQ)1i^ z_!QOSC{ZYe6Fj&tOBkQle#moPNFHuE6~ZbbmMGOuQ2W@;%6j?2h$;EeAc-RzD*nM#YZ`cD+N9`^*=%ToHyw~jgNtu zhA(>R=7anEEP+1fjap(Bo`p%j9hFlyo8Ps3{UtIxLD{u)_*Ud|g?FvB4M^>%?7|th=P`Eq=8Pk*~Lp`YWcgOZ|0P5b?6d?&Vs!C|B^YonLDPkUl6qzcxIyxC;*Ngqcrw zn1_(VZbvUd_GiPn5WLxk`1eu%-GRTgw9398*yC{Zd6;Y-4q1U5`X`B}K~$qMm%?Pf z1mY_|?kDkg5YGYmJ_&4x7t`_CcEc=K4T1}%@51@;>@^@d!95=)`y3GO2XZY;&L4lO zLf0|_-BWJ;sxMJf7A{O#jG)K5Cn(Q76c57Hhs~&%2x^%8J!LGzAs*+=kohXK^4OO1 zeIULK%zp4mX&IoLh8oUH}te zS4T1CQ+rUy%5eikzi;@zVusESciAvf>r5ciNl@z&AiU)246Az=-5X|*%3!^M@(j|M zK-QC><8y%2!{jX29%lqerromVbTKdyB)I%NZFJ{D4b!dzD%z-%9)y5gNP->=0_lg5 zX=iG1nTV;%4Cr1+?xs`fxdO<$NKnrWKn}s=ROsN04QQnqP!mDg$=|cal&Mg|fF6d5 z4^t;S_!JQCw2&Tr0mywYGN7ggmx-9F%zz$+LNG1PKQ8M?jv2$*CVNpbMr! zLYJx!=-!R>v&VZCND? zb(Iu3Kekv)s}rZG+6w3E?|=uDy8LZd`h@XM!?_E3vi}p7+u(B>%!VI;aK7);m*rfh z#a(DVU6`HZN_@fBb@RveR4hbaz}h7cYm5+F2h{TE8l#9Ue1KhxHO6TY=l2xEDiVHv zS9yqCoMGht5$gQtS44OX*BQo4lOE~{>E6gXEwsBL#EY5M8^!d?9~T>p`4M8cHY*{{ zGy-hp&twbd9}>HaC4Ima`LR=kv)wTxo8Lfk@QKAacQr>OzGh69KH|%O&pI!&6<=2@ zd|cT3@Ud^>V{d6;C?sF8M2k4DgvUnu&N9@TL5=1^8H<$5| zf#pby*zvSVcV9HZJ^-gWft) z2>e*J9-T5~Xp;`Jge;LEx_=(O{&8e%H_Wt7+?T`28t41&xol3acu;mt?uN}RFmw9E zm!#Lvfp`Yy>{D8EE0YYrC#ORSNtx;>{V;bI)V~7Rzrf@!(xrn%=HrlMu}PrRtkC@5 zBPDY-Y9jSjc_39zb7R`W5h!?GDrl1mZq|JEP;wv91Uol*h^Y(xImCw_C2yI??X>7G zmDc!j9WedKiCe5?HQA}HpoV^lxADjfUrh-`<=d(_iE2&+_sLXX3eUxy^Aa5K6&-Wf z?Qmgc81E2@%4z62$He<{*g@)q#q|8NW*|gdjOEPvm(UM*QX!XZ6nTeS`q8Uy4!K};TRttk z4!P*2*W5@{2)*Ry&`WL^D{eX6TXD}HPDc0QmQb8=oyoiQT{q*;|2Puw(?Hz(6E5y` z$Vv=b#j~#f51Tr4PZKL%wu9b|y93t-gvkV*JALsMARJNxYKJEgR@g=ok%y~pUxfs*{OnyAkkN$S<6f$v$FALjwrZABl z@2i|zqyvgTf`q_+7#8*aL^tD2Svk84b>`hLx1zXXrA(cR&vNgEKR)L@I!DY+1y4Yb zzP}3Ji{6YSDxAO+5tuR^Pnp5+`lkquOII(~gzHHz`+AaV+|?tOT0H_ttsc2-3rC>G zZaQ_@7mnlxfmu_KH+f$`AVm)M7EHC=^OU}W{VT9Z->zA$uVDWszF8J_op}X2`L1ap zlvP~8PW|Iw!9E`&pz*I@r-F&EU_XhET2RdP=6n^Z3o>tCzZWhox3BXg5a`tH>!hu> zuamakzE0YD`#R~M<@R;bV{cz)a4om5leFBv{xC?(?dv2hx3815+`dlIa{D^TN?b3h zZ(k>Ay?vcNrEXtm*iyHzlStjZP9k;tI*HWn>m*XQuak(Gx37~(-M&uZfO-2miL1@q z*GU{QZ(k>ox_zC*sCoN3iQCQF*Gb%?Z(k>F-o8%!C@xQzx37~p214GxPU1KSdHXtv z)a~mePQXUqzE0vK2zmQDiBpEYeVxQB#W$kh;P!R**xT2?4jbXr*Rq?}tmF1|x*K)* z?YFO!eY?v)&h6{8xyNc_-k^@#*J<~Fvcs`r^_Y0-_H|kwwON{Oar-*0ar?SQuFN{G zE&3h8>yc}@&g*84l1Oa`eg>4wT+2nPV_k4{Sr=SA>8sWC4q&AOJ5gPa$}PU$)QT$` z0I#{?`W5&f3CX~{>hC3E%m(2(8JC}5j~JMjpEm(dUw*z3lvhkoU49+{J%!?T!sK#* z<5BdNOd6M;v!Z{)q(j1$S^#!sb`xBd1>l15FClNiAk=;dIcu7*T|!P?#wFwo13IhL zOUTI@a|t;ej=6-Kb$6Ug$SG^Pgq$qbTWp~CUFAt!Z|)GA&=PU<)*c?mhG6QtxNmY0x|jwxDRLQeXC zqU9yzqz@UYV6$P81>F$y^d;nMk!GeZA!iu{nZAUaj9?G`0!qaXO%+ALo4SM?caT4f ziaR5T9OiIP`jIERW9}fw736Ybq4hljbp<(YAU_@5x*R&U_6<@Oh~oxw_Wk7N9v6`3 z16Q>v;{tL9&ujHK;NMdbN?VhD@6RFg#N{62})`F#>Rzb_?teqSLtzpoIS-O>?LWQ-zT1NexD3|eqW*L{62B>{66v2`F#@U^ZTUI=l4me z^ZUfi^ZN?d=l9bV>BIUprbL=mOIF7DeKL4{UqW?$pXk{0`#!p~oZly%TI?lZF7`@6 zz1U0Kve-*9z1VA^Qj5LhSr>b89zVvZy-+ul=4E!I#{w1w&Lphv@FL|k*uct18!F4XYh^;#|f{T$j z==vg7Mw!U}ine>uxcfR<3%mI zPV1=9cKryp!`rOyyfL+4?#+jCqQBM7E|#~dSkheY}aAvH}=+azk6J8<)U;9|$rAAo7p z;U1`6BJL<6C5%myOehjPhFie($SXXQyJ3f$EX#?3%>KUh9)?+y^$*mBPmk*-@Ri37 zIqRA;nFF&!F{zNPLoumrxt<2*g@pyr zVfopRn=J2N=wB?;v>GSMvB1GIe;s%^A*v1rKA@}}Mm0{Ab5EY$Fd)9TaPd3PVZ=O1 ze5easEE;jURzkk0^5DX$KZeGDQ9C#s-=`MnzqBy70=%GllWvfWp0fC|vRH&1=Jt}W zC=#1mS8vIp`mkcHK;aoL-lF6?3kw)nLk`jTR-brk;lj(o;b60C zmkP>v7y7S47`+%8;Zb^CQ>OUeQ+&VCvIlo7_jL3kXc6)Kg?aCnv800b=s-AzClI6J z2Z~*Y(BbmOp%Lsu`r*R-Va8o}nd+X_@q(yssTD^TF8m}DmBq|6o}74kp=V+(u${wr zy6ibGvhEDtNek?^wiODIb=Q2%83^w@bU$Y=!=IbgP?$5r!@Y5AIu)~uUVsn|RECYp zvDRw;#O&$cghQY6r2g*WRs#8nrixwBeP{uVIrFZC57P$lSDa~!0cX(rB>4Fd74v;8 zE+Su^$y<;;3w&=r9xfXe3+GZOAiP%*P%UNDhW^tQ(hk?$=m5;g*lv?uHk(QdI{Fjf ztGnHNxWuyo%mvtl;Fey_O?MUw7GqAQKRO(>m;DvzQk>%@;crOY3uKpy@!2gUHLp7! zjS6p(Bf!lWDuMltQ9K=GceMP|DMx@`{%H5Psf_+Kk&u$p~UmD ziA(aBL^pzaDGa#kVKs5-6sF-ctU$a9e(>{J{T8KNd>sSOY~)l-99+T-Isn1_FxkW6 zU?~|lf%qUy*7vkard;l;npg<}-GOx3!&r&oeYdtZOk}q9&-joh2`{H#3ZbkUwbXRP zLoA@XQO$8Y%&1@GDF<&MaphpTewbJ~5Ls?bvV`Q8YJ&N13(_J>amLm-S>RbRu{_*m z7&pO>88Qi?vivTdfhFycs2Ip&%5l()rRlY+)Ac2e6>8kTZkBIR^*E&Nd0yq)yXXWz z<8UiFkv<5CsuE_+?MTE?rYtU6+)c-#T6*^sc*n>`!zS4^lAQ$WuP}Khv|<*%6;O$| zaWyh)nocU2AH|wr5!M1@!;O{ebfA|p(3M*EkPI>d9bl1S;Fc|BpqHR~Rt)2lm3>(` zEBpDN8)34!VolNI)9LENVBG+dH>8!aGW=Wx*eGY0uwLX{Z;1?FY13iNyd0OTg1Zn0$SUd)ahheh(TEdBNW#wz)ckrWR zp=qO%R^rQSH4KtJ!bL{VQ{^YvM2Pei{s}(V2MHtlALkd9MssmHq}f^2wPVf+}2fw?2Iu2lR$Z+ZXS8~v>V|* zbJUQrkf74ce7)42+1YnnCikbZuj@zeY8stP^bp-n_Kvw4uHT`P9Ro1T6F{WX@6eI5 zzC%aa_6{9c_IK#Wv%f<}Uiuw6Qt5Z-NLk;ZBb|PSj#T;`I#QYM(2-+(hmN%69XiH1 z;~hHM+uorg%lZyo3~n;tp?d%l8^u%#(o&|eQ_%-Z+9y2Yod9BU+QABCVozQ|8=I9~Tn7CgZFU-kMn>uX{@xa{G za5$B&e-9&*e@e=mu@6?^@v&ljywY!vsibQPUo;fQnWJ6NxcQhSo+4w#aTrZ~gLXT- zOh!AW3}Z{TT=xHonZD{URl1KHkyq5<$ugC|%6hBy$r>quXUtSWSE>E`E!}b~DbHXD zJZnbFfWbZO+C#i=OI##3vwt}t+2`l<@;NDXrE@ERkA-3Ib#oAgxR0X8zR z=Rh*mid#b9DK@e<;{8Otn9zG@SYp3wp*;UBRuX#o1GZM^U-28g@8xi z7~bC0!;x*f!&QS3Ml&Js=o>Bj<;%=9eR281`aXf@-=0H_iJ3KPY+b?YZ>&>h6E&Vd z@Iq83|0GhvJ!i>A$SfHDZ8$gHhC9Lf*lv9rj={zJ7fPyL6vf+cZ1To?8;-TPFcrr1 z%Wqh#$J20sXYk&IKQj_(0fCp{==Cg|z-&gBxp3?WOopQ{^8}_0n%Rn(b4=+In7qrw zFi&9qT}Hz^fyoVNUfIIo*d^7NO{#gg62~sd#;%)jj$P8Gz+z)LJBeeLw8icm)1CG3 zB#vFuwm4lhEKYIkk_9)Ivb4Iyu}fMmkZn7TT2jrTR6^R~j-!@b(DO4TXI&bcaWja8 z{3y8J5%kL7wZ!{+_#|yzUpz6~(K~{<&36WAlWMISnp#_MJycC?J0@(f6xb#TE(!WE zx?VH@Z9;y<4g_U5Tn0|>?7@R$m@MeU)sW(H#mD!H$6v2dlpkd%<=K^r7ck5FSl`|q z^f1_FQ5h?6Rj{lH!SORpi|ub~O)cX0el}ip8SKI)@oiI{M3}FGWI_7xMzDmReRIlj zt99j6@{X8dyahzgABA{smb=ZlvA4gklP@geiLwFI=cCjY`;{6Ne~lXP!_6PLm^OaPQnj|lomSi8j@GvMx?;8c#@1SETm5}LcbVng_mYqT?f?7lz)WV& zoO{o?XS?U#H*;r88R`B87q4MYwnGJvWt|E!=Uj}_#|PR_(1*CgAAttS`mtR90(=Q{ zG^)+Vk0AZ9CszRZ$ssgnh186w*3>fl)G5|eS=8D{U=7AT=qhCVnwzXOxbxFzFuZoZ z18|&|u?KJ#<2yjH7jVcT{yN3I#m|lw+Y*`Q0@)$*mr(ay><$a9z{xV~+=fg7;67D> ztxsmio7VGr1$DU3hkDP&?w*1RXDJSs;A%Z~XB95)#0j7Mb=KkHahyDg9WAdtw)un= z%lW)KA67qhx%#|<>^<({G*ag~Qtp>3dU&4-Mf*3Z&nVorFGc+#K+j?q(!WPYe_+!& z^Ayf^`+XZYf5rX3V9%kXJA|a2eCQFo5UD1Vs0H%9BY-KT#LILd?NW?cD}bOy%JV>^ z`KUVwyAWv!PDWtoCPZ4KMXFDZl{c*iq)0~t`9SP}NcrsNcslI8W)N2|2y=+zAitaUX05>;!n&nP}yV)bu0VTHABI6e0q zRMCW8@P1+7Xcq}by99Um(5+DN#X`x~;PPsM9){j8Dd3MR-@@e$*hQl?#pD6t{W8^P zo~LW{!Mf3hg&NKCpwXLAF~7kq8qHq|e}G+VeyB-(v#^m7r1NcQ=o1vSed9}LxoBon z(9CAh%qLOhPiw3-blTPenOVfbR zJDu~XzdBWat14pO=wQ~Tf1@>jza^mZ5vuwCyJ%Lu@2FOTaM2-X@L=r1A9YRf9jI#Y zJ^1-k+9NO1wX9LM>=Phpd*pf0vVBo^DR$Aa@i?i(&Mk`}?gmwX?SRpx*&?hR1%xW> z!UyBLA!6GJ0L{QI9C0a5&f*0f@f@7AV8@nX<42t-0H%g3s z*xy`=O4ec*k~%stfMbLK+>bl=Vi$J)MPcVZ!6jc+6m~vc*!fR!`80MR&zBU<7(L)b z7xbh&d6^>5A?z~VR`~wOV8yJGZ6MYcLE?GrLae{R$?Mp$?e|Mn#WiTpa8x;1PD}28 zxRUe|zzJ){aTex+2jiWVi9n482Wt#PMwa$s=Q?IE16movyJe3V!^obz7~ru&E}|Q) z5b{XU-wzgYK#drrEWvXV4Wefe?zGT0D%kjtG6CZRo%okY0$ohl#pJG~z?a zDnA}RbUrd!>i}}4XXHkUMpK!~ijY;ZKmGuM*g?s#Oa2TepJGqxnvd0Tei`M9ZBcFj ztUVWdoUlO9qX8O*xOKHtozSr+TInQj>Sz=riQPE zLda7Ws>t0HJdJ@(d)Qld$k>aoPl@ekAdq1puYMU8^3u;?h~=|V7xMb2pT@{~3w)*d z9#NtZzkA}BV*ElUK7`s~m$B<|xI#s?e{0^-2Hr&myb_BSJYnCAyKXJY;6`oZ0`aQS zQ}&R(;V=Pw+5B4mkb~DC@v38j4-_T+GD{a=oy_`%M!fTnN8=0jN5Nc6^RjHdlmS%qmm<6@fOY!W%Vm{Q>WV!p~5Qy-blnZRQ zV~22ARq+5ABa3}G57+T&9CQ_OaMD=oFH2zO=l>AkET>MJ@G@K$ z;r*+Y`XwvmBBRR#boUSW6!2%jvH2pXE$FghArDD+pkKTDH(TJRnyr0f5}^|djT}gp zx5JO0#}3$vCcJcI&0rfo1mt}Iozk>OJW4T_t;$9(?P4EvgK~u}!1eGLR)vS4ajQMs zvup5YmWPkaR(M>6@K(D9<<3%YWMWvijhB znY+h-6X#3YJ?<{&6MiS0;34SS<{U|m^uS!+5+0aKqt+g{Ja9pFD|mx`XI${tC?Z`@ z5Ee99d&C7b33sX^oF&yN+1)X5XqdOmI*7cV15awi4)Aho5-YtLSNL2nAq!EFD)bh87KS8z*oNwV3yOSd^N_bG$*yY)Jtf~ zq;v;R9Qu+Y&IB2@+!4uejQ)!nqKj&sIheS4@BxQo18bmS!2MVzuBk?B-#AG3oOVt* z8}Slc@0ZxK2Z#I4nqt*=GF$!~ZtuW8Bp18z_`1SrOa(F!}E-s>sdS!?cNmw%lFU|KZ<=md{a->>_p<3y^3pg;_>qM z{Ni?KvG<>OI1|_|r_)kLJv;lYhv=hiz595ydmOqN_orlm6P)fZ1nX|Cc!Bre@s`)! zdnWS5lowEh9|%1Rdh2#YaQ#|Jw@4|krF4rMyq3}}TJ*J)oYYrQ$$#v+ytB!EH?N|4 z`c+io^8=xOb5Q_q3I1o@;n1t76o`HmmFJOHQ3?3Zr=ybNAN4PE)Kq7oK< z6&2|`lQul8&lN)(mY-wQ7tMn6`fv?i(*KJ9E28nKNVm$dZ&97XAb2OY zA0av;os4`!179J$5V!WpFwLi*aqchXi}WWn9Qg^2ZXS(Jef&8`M|gLB@n1o&|64eu ze>HGBvabYnQe0w74@1xA#2*hZvi|`@ML2T+9ag4}v=^>2SH+?jHEgsa=8Bx$vRd7QA;gWGlJ) zISzwa*z=cZNqLgn=>p1r&PU`d^iX#%7KEVO`N@tKF{J3W!}|B=D8*oL|J2@+jle4X z{n`0-(_1=p4uACq7UEL zmqC{qy7IeB!opoLk^v@E25)_q-^v@R8qq2iF`cD$om03A*iT+cD&=Z`)!HGjpau^a0 zaI?U#I z_i+Q?la!AwqN0`f6?aK9)*G1;F)SkU^$$~FqflE9-y(ph+8fQ6Wy5Ro+Kc}{3jaW!xx4Ok1Tm^gfhn}wD`pB_$t=BRdAbM3-aYFhF3{CfnIEt<+%xWso;qrU?B=pTse z;X~4(YXyX2%ywdT0%m35tE<{3VylbW$Rj@CsudkuGel?_AYr~%?7X2gjlJ}w%11T@ z&adaiE+nDjaE5l=hN_1XinUgwQ>Hm*4rcqBS%NYJ#sWNv9QDBLQ3F}+Mj|mZ_(;M( zv-c5qAMo#jV+b@>80 zl^%!rR@FIr7sm#&)9g@p^%G(CjTLxoRaSKBzQp(iD&ceUBYvb%>6PFgKQZ88eYjmX zy3Sy$s}$l{k~gSt81$Q{ozk>ufi+`q#u$E|<6Z0mc#bt=933_nj}ykRCu)zzT)>Pk z5_S--_r+fFI7-c!#p-9^avJv1UlO!bbSu}CxOIvuy?9`wy66P2@9;TXEO~H_l`I)m zQNE9DxhvJ}7T~%UsEcQT>t3oZ7+l<&)Wv9^v8myfP9`hc)TlmasfS07R7)q9vZY*h ze*t#Y(#Z!i3akU*d;w%jCsz^nEnHuRU9@zv5afNhya&5z>Es68(k?}nVPK%8c)SD` z+aTtYmU`;8Xlb6hn8#)hQ5OtY?ih6;T6zc_tzDUB;Dhe>6-c<(kJW{6ub-(4>0V0h zyYY|R&vKH7m&U%}9hP%!;Y8>v21s56;*t8}fR#KJ-!r`czi(%avT|}J=QzmNvQ;U8hJ0|k^%Z+9YRirAvcWDbn22en zekK&G>(IQOBOt)D*Q3i;HpiWF*h50V3v<@ze4gSGV zc(8L|gd7!-w~rj6o4o&!V+$t@A)O(SI*`DMYb6)Tc$gOu z98L)#4~SMJD;gnrhs#7sOIAxnE5iJgl2rts*SL?IPXA|NLT6{p176pOloA$B~E}U&YcvQ|QgKJ9dIXS20 zkibDX_9+nbXjN0GL-S!(C8ZAUj~OSJEEgK~*qV@*#|qog_R5=9&kr=)y!4vclg?0{P6vCJSjYc6ysfzJznUrZz-83PboE-S8^jnJNXw=CH z;h(%b1~_?>Q*gcrJ>*Foax zijP3O)#PY%K9xR7gwq&B@TfeJ_9V@Jj_(uNzCmU#fs=+TPs*qPso6TZ#)1ebBQET~ zjfTol~d6Di`$i88nJ%rsu5e2Qz2kLI62l2_KxZxhjtF*pY zczCHt7-bQc;U-P{zB;nn~8%qI3N71MKJOM*?aX1SSuYR?Kw}U5c$D9Q3SaFeX@V3 zgC7uxL`$$x2H+xT&jTYmM&sz*gLEG=*bj2*PH|Ls^!y=FgVt%mP!)?()WqtCrIwHm zDV<=rig&^~sECwYL5H;wg6J)i^5rVJAkL^KI`tk!RqG@R7D)0er5&oU_G zLcmr(|DIBoyqD*LRgtio@*`@JDVokjrRpRsoRI4LF02#Hbu8-Fn$*sFwRSXS_DF2v zL9XwFJk!;p_EPnsvwYDA$T?6?Qo4MWuN?FpekPrx8<(q{5<(LpP~M=<@^nU?FU&^s zh8{x*6G1_h>F-NEqL2Ym8%L5UI`cwJQOX?}Ez%KUpt2i5swzkQ^+9st>i*6Jg z%aP0wkrm0VHH*cDM)f0eUXj^j#x4zCrMWD%SClnr5+l-gJ|hE#$?;Z+H1Sfuc9~eC z&8&LwAX(W*C!omP(Y=>oU;u~&9RK0?1*9C0n(rFsyXx4 zgP5z1M%EchLdQg6C~78onbC(b%dyZ!UO3gPh<2I>`w|xJCbB~$^u8%5CzQTELe4^W)KZ* zp>&|^N)tK^bQ4EIp;suDxsE^XM?W15FH_=ZY7`Z|9ByiUD8~zu#t0gE^GKkDa0al{ z&c{XRUE!$@9VvruCy=oWi{X(c2Wl$YQI&`}3uZh~fnZ@mDnlV5i_}psJBWl>^+8Rl zM5jT-6o`&Xc{1MShllyHi_x)4Xy8pcZFzobb_ZyAf*nq@#<}eYdO>o z=0XDD1w-xP^kEFfoI2zks?(`qGKOHGO@HjWmt;9Is2yPpb4MD(+!BA7TN)VP-su9- zKFa+?#FOdvC_mH)V`CP#uOCnZNM~{TrGmruyMM$qWnd{&HcfRLpt~WJ_2}$5W7-on zB%S-{TBM!nN-*2z8&Os|{|}Aqf}oJ2jXqa3tTcfzQaW^hH5BhBZ4`ZVV66GtszjF0 zhNV~`oU*^P5H(xI2I_I1>_d&Il|nfXEAr(V3GV}CCO;^MSR$9eoSdI<6q|N7M4H#o zh!vn-vW$21<+Rao)f#`^Vy~z%$ew*f6i5ph8D&*QH^h7$)PsJSkYLJS?`R*R=Ee4r z9nh$7Par#xec5lr?sRs~m+tmwpQH&16QgwnBjj*K*_)wXAlK5kPVGa3O;!;Zl1lA{ zMtK-pa;W8m6oUC;g1jJz#$_7~y9ISI1QZ^L02vmLoH;b7jU#1L+~Y7?rb@c!$zW{$ z{4rY~<6^#yi=ieV3H6Ojb~-6xc7VJ3L~^k1a*G3@%0>+F zO9%tfk{HTKTbFYf+LX2H#+d;G)3U=gTuf66k5j4OUWgB2iI0dd4AVA!sYGUdrP8JL zmVHJrmAH=(pZ{CHC`My?z05b&B%n;C_X{G){yMspg(D|SIc)9p)&s);B%MMvOpJDN zibLurJlE!%48Ac;rHT1y$-AdDlR5;FU8BN8+||*xR2Z-_Mm_8llHx2j@#Wlnj!fip zO)2-Icx9TMr)Ls%xb*{6f#6ihltS(=l` zJCzVb)+s|{VGstom2@OD4$2$`c1GCjrF51Z?s@buFf=YtKZ1(O-Z}C+hWe>T{Ei`q z?)aT2^21kN-P$g8Z9(07$xk%O^jTW>0X6h3>1`y4n zWon%*JKn5d`XY5kK}#w$_sF0Apm( zNvh!oGcWz?@4&!$2Kjv!%gbJUFz2`#pE3=Eb-FlIr;Ec<1jtdvaOoC$lE0KGRcU?@ zih_p%bgUBDT|Z)kndRdFL5io`AK$GG1JUBW11n)^TFO2_H#$mpqx^@HNUv~G2d2}V8AIv@J@KfV1KkK}oH9p_rK(zflt<@MtqF_|U+BfZ7A(}w+N z>~CO?<7Uhr8Otx4f-`#t4<`|JIu6bfo;CBZmWNAu_!Wc zP=Rv`{@C7t8bI$Br$s#d-dt~#uIWtAEApH|yiQaI1ZUYg&vAZi|FO^;1Po_}mx%wm z(96boBK|WkFK#D6D(*ZETF#F`MFIP+{jfr8Cn9QeUbr9$dNaL&xXeA*8<;#A)GzUJ zc{h1a+zI&ZLZF3TjG_i}(yNP6o~VzBd#7TYUvvTD36XJreU zn^W$UfSF`DIKS507pMKo(Y_5r(q6n>-}U0x6?#eB_Tm?Lr7UqX(B^pFBXb1Gh^?Nt z+8fb``&D!2di|Wk7kV)$)%!x+p5zUi1VnFG6Ph!*5X+T%&UR5rb{oVYrQ@vkl3&2p z9LVZeFYhqVIRR%U3*`8hP;e6HQ64L)Zo&IQYwa_<{J6cn9#j|e%uD{z>(_v*MLw_O z*}eshu1-$!`mMmdGj*F{@vnKFlYMjOIyu%Gf&!>cwl)!8?>f$QUy8|ch!LuO6mrat z&jr5=h2cO=rzU5>f`+^V78gPN&abS8g{4dfedn^ZFsqqGMP3nVr$uLpzjK}3a+Z%f z**)C9$X+M-nkj7OfEv$U6vKO&Hebu58`GG3&LZKL z{pq4}il`}XAYOmRO>vyTV+{{2UIKp{Xka-1juvPR=v;@IR(ei@H^5oF&Z{79e4TfY z_-o7Sh4QjSUQI#)C;w);Fv;1sLO%< zw}6(5_lac5sW`Kb=Rs(vW4qGM07y-Qub2Z9=$W5KQN??HttEKU);@>__6XgZ(#=47 z3j05>OH(SwbD(x94+r89tK^}IhZ#KZtsiMhTQsv9u(Sz1pjs-+8NvvV96bk$f*0Jr z_AYUE5&8nUGeW(Kh`?~^z{9EE1iX&X7(Y4I#GOSiBU+&^=2+WhkXTB~8g zqfS;lXSU!=!P580mXOm9oY{ZkL0E9xYl_P(C;-a?f~`aGL8#u?@G?B3eI0gL@3T0w zU+3X>a7o&5b4Drh+i&Zz^V4ghbpDGtv)|<5kA(e=2M;d~#QO6vjE8-AsNmr+9;Wbc zJP%wuKemX6MjT|C)2^HKB7F*`x@|EOIaMu~O zRp72HEG+W+Qxq$_{!_f{x1gDiL@EMnK5>pWp~cIYy;y1M+az`;T16u&s6!7%%={n@estz>%Ac}yyQ9FkW+y%R|IqPWlsEhaeB}Uulxw_ zpwoCn1M+KD(q=%#Is2|c^vi|bK1X_cqpv<0uy=*8mLQ~qR6Y!8@M7J3EX zCq70r?PdWUbu*I`GPq@P(3 zTrz$QvZ=vn)}TVv?$q1hX;=#dfsBU%Ddh zZqP9(ZkCXnLFu{KN^bg*o9~CXAtRq!5Q1~@+8JnAO^7#ykpajLowtFXh`;9bZ}bv} z#IF*4?x33)b{V8gpYZz6h$GM@oZq2E`y&}T0_w`Xi;xLIh6CH66tW1TSrnGkWl~aT z*c^r|=Sy1H6-wAMA#7+wHE#u*SFkmmuxo^{3)sBxhMGrVzs!a|fWe3Dd?)4BI%>EL zw-j@snsH+_QeVk*3Oreo<^~4_YjI~#+!@)1?#!ugLF@L1o0LHw2YUUF=ZTAi%66_@ zOPdYsp&Yj8Y=!g^{o}M#j2FEHvwc+=UV&r93D9QWK=&TV>_P%+F!9(;B6yOI%_7* z>^VFvB5VZ@=kah658vS7Rvzx+K}eyZQ%T`Lm7~nzkd&jq{gGpGNIK!Da!&-wN1=nk zu^C8iaW@hFp>Xir`0XMPy7ALR)Nq-{I-?<#xO3ZD+xe|k!=Qi9+7g++I={3yjQOD` zWKZ_;PeoPEch+uYZHS4^D^__8L8rG3?gb%q8VP5?!U(1tU;H+pC$vPMx$$L+Q8{9i zj2>xwu5*0N+hFk!o<6)*oIeTcbDf1aj~B+Wp~kZ?dZ03DGb&>QRtq}@`&Y0FW#nwc znay=K?YjtjfQQF;c$SA3dH5e5KH%ZcJY-?|O{ztII@NgtoH)0ABn)l@GQ&i2G294Y znFH22>=)t{jIZbvaLEBc9!KwUnLf_&M!;`T-pN4@7(W7vIE{L_e{Bo!V5ddiP@LEc zJSZ=hvl98`>^hyM5^wLgO~v_r>*5V)MZZHQOMk1aZD3q7o;_Wxbb0`INoG83a)70dpqOV)FXh%^qeg%@czA)MqBE&EPb1z`Yo>?Bh zU5P}|xhj>;2ZGMEiVn)BH74h;lFp?{D1y!o(kVs#Q4{*JpdG{To2hUN@igCAGsD+j zZu}(hT~Ho>osDPPKN87QNKqGKwg=hd1>Go$ZNCWl7IgEE3($6CX06Q3+T*Y51`D|| z<&2o)b)xR~yQ`Z|o{Mq22Vp5~3L5k`(Pl zB4s5w->b-Dq_@|{FV#FNE&Wp0Ez_c0=R1Pymo5tojmjlzi!-kgF zxiPuogouOTmF@gWlTa$06Nv&5>zxsf0>XN)rKp|ZV#u?sWgwc(YLVPJ*)>PV-VMDc zyd@zG@j%YTwZSb`3EM~_Gps<7d`zkwHK~^)_=^w{?`BvOGXrnq%>FYE%T-Q0C1ZMV z4u0CY8T%{PMQQJkIJ5aHqCEhI*f1XU5V2yJ`7jsFE6mLRZ zPh$U!b&_9i2!2qq%XpZ8L#&F289WGz`kMicrbxd)v{M#Vc+H9As(bPq_8s6*9~U!8>u4a3qCI))tsg{ zIT3%;PPDsY_Tt;6mUSie&DaGui8pa(|1U59!h?%-C1U+>aEfuTNAYr`%BUA-ta=mB zp2q$e_90joS5%#QGS2LUJgg>cEe{)b_!p2j>Z%z08AN0yzn6W4Hx}Xd?wa@%L1hqvlAJO+9qb%S$MUlK*C2<-1XGt<(?JIPIRK)8 zES@ZdKjJTu^b#-_xQQAg_VLZM_JL8tAMpbTe#9$q_Tevcj&qXzb@8jx2qqURIfU>^ zBB%D6xYP0$O7(=dQUnHAMz*7d!H#tfN9E&`jS0?^Gkyj%A zKADGyH2{AquRzrOESSeUIhbF8~19NoywiQag;kshe@Q>)(gQDtz58Oa%x# zl&a(uJFUvHF2v4qU5c--5{ON(pSGR*;%>Tj;^#gX3HeBOH$+$3S4c!CBIH9pTJ;Yu z1Y*l1pEGc;4J7psG@l6U%zU@mE@ri?>$5i|Z-~3>4YOa}{z@8kfd{%~Cc1}ed7x!0 zZ+=|0@Cjv*Pr@KktCe#X4y<4QR&YAihfURgF@6rgRbKJcjyx&3%9ST&S922#fq0DgL{b}>6>Wj`+NKOv4!ifWz}$DfPiFU0Ye;_g#; z4ba7}qbf{hl)nm8*X znGr->R00vt#xY&|5k`-DCu0}wc~iFMkGSTh=mmPM05Ggq8NjYefr>V;d?q_0d?M^m zPgjj5GByoQ{pKk3P5doyN&apU*gk*V$@>DJcIWqu_c<zf*y zn@?PL^zxRbbE{YIE5U+mLjXSG_*8JS#5u9Cp$Wv6FFHwxS~roON(#hz!pddy8=6jB zIQyJ=Q^Cr zK=Qa1^T5_IOXp!V=+l-gKlBh)2p>CN*&vyX)Rjq0i^0kCdCTju_W9CA2!;x(x9V5T zZkX2$BWQ-P9Ltr-Qyb8ztjIbU>moyc4KR&mjaK6cCqrHQwsLCo8UuSdbxBjp%6Utb zCafj8s@iEQPFu3He(F33s224#wFuJxm%Vn^wQcI*XB>aVGMMJ7F{{Q`j==)bV-_uG zIitC0!5Q;cLaJjzM#AEyMT^0?eMYl z#x6r78(%qgB?#lslI07Qu0-6*d~0lDbN!dGK6SU;`E5>Vovt3lWDEThd^KlzOZj38 zAp+kV9)or5m*NWk+W-`tp+=z8H!Q^Ye8kt5=6alAP}y%>L579eQgFTQ+=T5;0Yv|<6G8A0bR z$4x z0DdZ9_cty?DRjD*Y@K1W`zyc2!9bKpw>O%xUPdRq=a>QY1 zS;*m^?vHjwlnikcI^E62ut0pJZ%-sqAxfds-Q2uo$answmaZ7ke`Llaz5|2wXg4<= zxpnQr#)B(%zW~CN!bJaRzsi&!(}Tsm+Qkh^G5&4d{cTJomwLUMmD$+bu(E!|n5G7N z*l_nZwwu_U!br;HIT&Xz6e9>fpM{{(j7Wljo^Jf1J!DzKGEDTy5ri>x@dq4!#=PeS z87na)h(-A_Dr@Eq7*va&CNrksTCvUhJS5G66GU$rF|*A zrx|{eegN8xnO8B;-^~I=%7?GL?tyVpH!&>WAvo)81}cTjIg{uFhaZI0^oRVUZF7d$ z)yJ$A>@I`uMF;Rtcdol4X$=?(&UUi_g?pSaOEFQs`@6$*B-6omcgryqzF-eDw;RvF z^q^$HKk2RC_`UUR6woobHsB`y@hC*^`mfz_7cMwy+ijY!p`L7q!@_!>K1-wWx1=s&_ zIsN-c$>&7K$iMoROX%MyDg~?v83mXB8X<|k3Lh%Q69@Pb?Cy<6qMz!fSMNhMs(*zE zw?L0W(ho2~Kf{Cz1^L5n>?qMIiEff)LV^_Odo$dT{ef*xdEuZ3c@4#2w>mz`H#`xGGD6=zL% z#s3n=?*Rj z$^CI+Ya(4V}CPkwF zd@=D(LIB@M{63*X2=MH=sQ3~4LmPiCkKGf~=ma^9#hV0>C#3Sc0$O~oEv!dYbQ)^7 z(*8Cp`nLVwwpcd|@YCv`-?~Mpw=h-t)+pQ>HC8H~O?3g8B_Xq9;|ZyekQyxx;8irE zWb^e<8*IkC-o6dw+}rH$NdT)78}Vi-yjcowmc~;Qh)BE|g;%5SYBV0`QsZu&pn16> z0cq4-ZpRJ@ZlVHlQ{y*ZY{L{TwlBAx=GB{o<{^h{r@Bp>(4xzMVd>Wx1;^sxS~X}+ z%_h~nP4*{Jnpks6{d14JiIsQQ582sH-F~{lhwNu@UFBatYrl@`4*&Xf`vY8W@UK5W z&DqX7`r2BGNAd%;x_7vDyTVdzyyO^c?vK5%#_c)ox8vW2FXGST30z&Dd>-EgcV9?e zlZ8JwWZl6(9a-=5&n?+^XWMu@Uaa&fD)P@L+7LXT0)fGEo`-$A&wH*cPruCwOJzz>KmUBFy7fkUV*QdHoS=J3% zu}V=7Pc;te;iarc@~uwe?bAhZb%}n>32@Y@#!;8R;pT2k{E*$H`@_Va6E@$e z2{yO!8TJj&*zYo6zH8s;$Ufsn=MD$(JDkT9;4$ZUM;fyTNvy$r!G4q7*_-y0G5F5U zV>deZ!y@?enDZPHlIK{ADi;M-U2l_*>+P*J!X9ZzM|MAmt#`1Zs6awTINL2;0%Cd* z0RhLst(u8jGmi^;M8K^50NZb3tjTgGP7dz4)Uyx)F6!5^?+A^a74y8>*t zH!2Z^s&!XgK^cBve-*ifdu?np|2z_Vj(=W>z0E)G$NtJcpU19b3Kp|%8SB_bgm-)p z{z@U&=P3nv%6W}|*PISlVsyCoxd7bfZc%_OF5df_jlH-JOG0HEKMGOr`^|G*yrn#d??q75{G0( z>uWT5q+f!3jV2F(AYY@&10cxPXz~CE@-><~0D^ptCXbYi8zRdG&gU>u_j6}Gg>xZl zl2Pe%=Tdnl*>gMX%VI#dEcQYS=r6=xib=V@6#E|lP?OGC+_qS|(0DukqQUJn@Y(L> z*kimB=(B?U@p>Z72GVz8F!=8fX|_ZXU5F%Zxs6C2XCrmI+D4$c+QxgHw=&Odv%g9B zH|^g7u5k4qQDzp(2xKUr&A!eC2iMu(x6zS*-+si7H71eizsAaN|25Vk<0tEIZvh5) zA_7|cn*D2D{hCN3Y?s!Hzd$^)3OB0GK-rJ*R%_U}-H!MR2{8CV;$!?lKLYIc;#Ve+ zTVDxK-g%R*b(1Bdk|q0{hrEM#pJBk3!#Tl3R~%zA@P!xiJdyFT%a1jKiL;-Q3d zcG)KPA&wenSqYZ?20I%P6r0=bZSm0RE#9M^)YGHhiv+yr-5D1Epot4HBy!v1cg9f@ zH}?lDTH`+IJ%>MJm}i>d7rpj4io{v?W8O!BHwhDL5T@C1|Kfg5dtUE-1B6)*&zvSS zT#)H>p62bR-52nO{d=3c8Q#eXZ+4$&j*kwt&HbM1SNMt3O85OLpuj_gJaf)Qg($rZ z<7=fg_Xl!#{+P3kARzKgj28uIl4y@@p_y-qJ*u4O(b%g5yc%nl;f+YV5c0wK4_E+F zVJ9J_f-^0ZS7V!qDAf3B>`fxR8T)-K?`+?=&Q`|t8)8;dWv|9QrjKflNUzntioSG} zeMt=NaY^h_#oMK^ZxQgV*i90^_C8`i2WMcZC+*MZ50KU)7+T3H-MfV6uoWVBT1kkNrUD<PACCfH18@Acn zB;N83`#pHIia@`p7$#FZLfgD(gf#%L0maagxZ!sMOf_oU{NmU(b@C2k^ie30TJNE# z_s~hGW71L4ddmSTpM)$++z|D;M;wJ_o}Q+bQq)p_r4ZpPw`erz ziW{;;V-7(rR~kv1+Zp?eF7#RKY6mr4?Of-3lBlaQ_7S_Ek9fOA-4txs8?d!mHCV6+G4j6=eF4GAt+exvj0ve`n!E4d&w(fS4D5PB0au$jW6f&rL5M(cNu5sLNViq>j=|<<9j+mT9w~m=1cMIl7Ew|OX%@Z@H z7Sj~J?jO6)y6)R!70*BYin7@NjZ_QjF?RL1KMEOjy92v;Lapwqm3T zX!b?fV)SYihO6C%Jlx&lZga)=X?$u~#cs(#7ILi{ZTDvM0qpbch`D#7A9J^&@3P=! z{^@hEmt*LWZbC!bnelUi8`InPpo7~HoOU|zI_`Vuh20J4c`f(D;Iz|y*LB}RkMC~q zHh5q=IBoat@Z3Au)~!e+P+{ma{)4#tFcKuU6G;*JY5x=r+*4cmLcD|uV)L+n_PJ#( zvhm}Ee4#DE!dKOmZIxIKqF=i0zW^-2E^q|GT{yNOK69}Z$L91+P?X6ix0kTD_ki;c z;B@qWvoETy?g3{ia9Vr7Spb||&|`ie7l~O8NZoVbXoJqq`x zD2V)1UeDM1Z&CLo$T7s?DnbA;uIcIfH5q?EMJxg)S4iIow-WcG}%JJ(Z zjsqh&yx{kJXm#9E;~4LA`#x|=@V7ghM}WhPQPRPbB-X4D*WtrY6%LnBa_o!uvn)o@ z==PGrVQB}8{YLM~t2Y%6yGuz+>N<@3Cxyd!=hziEnm92E23rw!CuJ^I+`wUg!r^Lk zj{R5E$_1gK+X#izA7BS-p+@h@s{<6y0D&_oEzV)U>F_N)jowv{)`U7#k9O`NKJmww z(&slU(sZYxo(k;3GNFld+Z^1l(m1~L%2I3v+Y&9hGuBIaizpGTLNKDOmo_V{mv$B1 zwDr#o?{l3F|zTbT1z7x&&sw) z?K1f^1)fVIcI?XnBI-=bkP%19kaiy3vLNMg?R?F zjsc_q90rgx0V#<Kk*&e~U5sP1t(b%xu z`U&(E)bm&1l!b8?EM3vuuz6G%$Af)UgmD%wUD>?&)&0Xb{ee>z#;I>Y1YC#+5YXBS zIMqH5IXnQ6Pe)4}$#WGTbrGE70GU`GuIEdDv_^2w0_0njVVt#qv`26*2c+PzFs)kv z*%HCI2asdF5U%GZfOJN1o&n^;sxZ#~0AdXf>*Du-6n-&`W5c&fA~^j3d0=K3X9OTs z5u5`7sXac7GYOEo2+njsk|&07<^a+f!D#>_w_4&zIX42bF@keGAnmil^;``|M+E0v zfV_eqZUUY1D|_2~9N5^Zc}QWqP7UKc1e_f{4)y*dAbFTd32c>X?R7WNAgvLc9|N*Ag7Y&#Hb!t> z2BaO`c|hwuKsq8ge+J}&m0_GD;`g=)P7xscVf-7^vo|0+A~@xMe0FXaXDT2T7G4bW zbs`|IuL4?zTf;a{0n!-3c^;5A zA~?SWWJ3h!JwP75FkH{y0BMilB+#2}yeNz_1duHeoP7bQx;Tte0m$|U&LlvJFAL+G z07zE^XD%QgM{t$`QZOS~c_4yw z6d)ZD9DZ{1>zl*%EC6I%1ZO!Q&YfYL^?-CmaIOMmc?9PUK>i+qJON1Jzr*$X4qcwr#n8dDY%8>x<1cphb_fHr zB5HP}0#Kx+s3&q;T$HQvS3B=>w;M{ZxIWH;O^?4?0Yah=oE=1sY@eB zpMpu*IR2_SNYfgfau+e^o>v9Dh|sARK>H zM<5)3)kPp2e>FxR9DlV&ARK?SMIao1wMQTve|1D49Di+zKsf%|=0o@{LG7Z3mO5<- zcC^j<>Oxq{RT{?L#Zhd$W4GOh(PWJhAaSN z{DWc0*?=@Z6oy<5$S)$0Zvk?^BN8VjsNV%h`+-`g(MT&X;7RBU>h=xm;#rj1>+x_s z?1@(UINA%OG*Hq$c?iCVB`E5{uJ!`oqHO#goU&;z*a3@y+Q85GDHy>_djSw=e2&eC zk3=wKqZhPy=LKqxvF&Nfhf*_IYW81N`4Y|+j+*cRB%6?>BxD?CG$N2nekCFT8NWBA zuON#0#;5y2eTPAP1FDVCs;n@mf7Z{(QPkV}MExy;daFUb%%J{`L49+dsCOFFR~ytz z4C-4A>K%Qe{<=ZE(V$*zQ139PKiDVg+YRcA4eA93^)`e0mOfE`(V$*uP-o5sAiYWY z#rRf(`qn;C-)2y+F{m>jM5!+|sBh~Nbw<)i&Eu*K>YpHD*T{!Q{ z4bhObc=^0#1O@dhY+1Z=`IpfT2DFstc0R4*218fMX2h{{IK9bRqy`V!iuy&n>>`{+ zgSOIgWx%t7gyo~!{-iD$XU3V(rESB8x>Ghiniz~u zTIO28BEezQS5Sv+JAU0xqp!yD3V{wZnTv|6_i$MP_1G3l3CQ07DL6oCDfRbdV$@>s z68`?y7AaNS9~lwuiZPo1>tvvdU*aAuAlOVBi{>Q6G)I3Bc*>@G{Cf1}_>bPaI0Yl< z@izd0HQ={?9J35O{wB^}!YL!i-i#yL6W#cmIDZMJrX2ftAfV|f8-Ek$FX8B{fpcUU zZD77Z(ZbIYz!{fPgS_N#;*@Hxz~PzB)Z~30`Fl5i<;LIy^&A9RIl)bJ#^18}3%2|% zyDTj~%yzbQm+dGY9D{nK9fp=iR&=xvb_m-bKL#s)j#PqMY>l+BD4y1P6~MxxY)Zh~ zsEZdcJdwKi10!d(y=kUl)f1+vJ;az7e~W^KWJ4 zDM!k=q8D;L)0cCwthBDG7OUp-2{vi-h@xpUYU%=wOxbiitO8v6MG68gd!q{-56_2u zsDZRPRr3IM0fCZpgnyYlF&^?uhy?;iTL~^g8}&ZzP_1{)dC^Lu8})v>uXpOp+^F|< zfTiBk)1nXF2c82TWDBDk^?n|}Qtz)vZ>lTmy{;E}Kik)PXu)k&ht}zqUc|a8lv zE;k+#z$gS%Dd!T{YUGxGaVT)Qgf8HN0(ul7Ww35srO#wm*VoQNZjAd$;vlyHWDR~n z@F6&{=AfR|pXwaR)cfPWiRxl!e7O##Wn3-5S#;CB+=}W+Azh!MXRRLu0xc(9Zc~mW zmq*ncH?0cyMN3648Wp6%nL4pM96i&%FQr9V({Utc!6xgOHrJP7y1ZBLGi{15`HVQn z%_W6^=YS5+6wgyCy2F7Ta4ql!@2%n$#8J2F2Uj58CBF_T>M6f>uRP3g4CCsSUikZue18wEU9V_r|7sH+M}ACZcE-ON zQC#{Ly~Et7ueT;?eYFB1YR@b|eSHMO=qYb00k1v9)e|7Yp5kgfY@?^R+SLm=^96I6 ztA`fRXM?cqYB{%}PAO;B9^Is$PMu4?>E4&8PGQOJagLo^)-%o&jsi2)LmJe3{SjL4 zXG3$uj&9WZ-WXCyz0Zr@R9E!Ds$S@w^Q%4SeJX6MC%u=9flq*TcjJP;`g&KN5(sgw z*B+Jr)qTDi_~0j~AsRP!#s^zbI-_mqr)T%m?V>axtk9D}eD zZ4e-BQO^8BSScHAkHb&!$(LB1*HrD&L;els!V+=3CE@SxRKrmwq?WfMSp9}P$+!{vR)eY$ABo^c_FCG0rZS>5 zEmtU(j}t^2QHqiWiIi=ZS(JL)qQkcq+Cy~HS<{YQSPN&QrM0Bj4z0yLN?Xg7AVgb_ zZnTySa3C2;pn^0TEupO!mT(S~FD-#NmT6J6gpr`tQzU8ag(Vyao}?wng^KkDG|0a0 zLE3$tnvLq4PECEWX3F_0U(Oo?+FSRH`0;jf6;0`fyZN)CY6;ws%pibx*-r=lAi(^|d&^&#ko zwwGjK=zB4eMHQiHst7bKCB$Y}EiToF6EaqMs^s)zc~b|9zO7?C~zGcqDwZRmnU z=qa7O@RU_(n~X@&@0Vz@LqMeSm&%^gQo>sTz-dQ;z`~CJq-2}+0&T0Z9=7W^V1saI z+ZkJJM>#<&-8fhER&PO*_zzmtT6ELBRWT}on1I9V*0eF&A#)^YhwL4Q9o=Y$)pNBS zz7NfrI;9={5K5Q5)qu28q#fo%-O>)5qD0gc?XUn8y0b&t7@xnCHg*q6Msq(_Mf*7q z%s@$KJIAo*M*Ar!ms;vBH@+M^N&5+X7DiR4^?k&bOfwDd)^R+C@N+a?U(wUeyaZ-|fp8 z?>dG)ilf;-8APOl$mnD=k0t<;Gsv*bCrW z`Z6Z))OUiy6u%52+n$qAJ)JKT_i{1)wG#PXMwbg7XR> z9TA+r08;gWE~R6OdlJ-2^FRxE@Zu5z6&(vvj)3!Rvw^ibp zeGhGQHE^g+$KC=-C8HJLine<3G9AZ$f`nv>fkRt87oCN))p@3Yp#*L9LzI?%%CFPn z&{o@Ur@KCdxy`+(Pv$mAwbE>~=P#pCG9E5RjXaBPwAK4z%upoS-jLB&+k0WFT*1J% zRrOgWO-rMq%^75v8X9vLymJ6_C1@bQC30Ga#K2$mM{Pyd1{4 z8Ibk}#JL!IA|xY}0jCC3=|$0vc6iyj+TR~VSj03z%0@e!=-c6CX$_k3`4{N+ zAvnz6rV9^q~f#53u|TEI39$gJx_(0qPZV&m~X5Ar!wC-nIL0h4DUjV zWo+TfOy)+LujtO^)iaY-+hv4v>_d!7cA0G`TCF}UgOvXa)y~;riCGaKYm`>zV$R!dNi zX&$u0Hq;~SFmwMk5WXXAtPAy+8|B>A3pqFVauy#R^1sx^8uf*gbNaYy>Vo5jXuGtn z*5M8vJ#|hGApcpT?sTE^%#-~%X6A-Ej&1kjn1~D{5!o2W+7NDK9IL`TGXzoZzxDP0 zbzJ2|>fizfN`uEdv|e+w(&FHHkwc>+F!69#vczU zsI-mD&t7ing>9^l+D7mVIM7iSR{M66+QtYdOWMXU5}0zNZM62nHYVX+C>b{{ zM-Az1V+`y^+D7KSsjC;Z@n0#np+9^_)|=HuS1)Ws;?On@L&>O!v~9HF&aSYH`d-*Z zS1)X%0At3UY~z2g)3)&~XpY#?jd5ch(kogG+8%AVLZxlg`?gUVtw3GTHaf8P6gQss zZR28;Om7>rfg^1rbKEGY0KcfAyIlPzQQPo8_(zuI1@fO)dyX3thqO575RK2;Hrmvk zf3{Cy-YausN;10XKIQMdunn#xB5k7%l|*@Fts*zRLEFZi5T!YOoqA9 zHXiqFV~mLa2yLSidr!7;JYrN&abpc|q;2e-mLKLD)xEHdUq@{t_|PHvRToxkFKk2N z&^8W1$tX+OHrjD#SHum@M@ieroNpxYGXk0heuT7f7TuU{bojPWg`4SZ${BxxI6zHJ;6Wkg-kHu&aUPqx7|ucU2UhLY*y#*K($(l#>pDXqP* zjX(Le5&i~a!2a*iN&5Mr0RID!)sO)cgs7zRjV;1{sEeSiKGU|*0f4j(dTUe{=D2`3 z=0;zBrd{jnDwv3AAN1wLc*IfaYqMDiAk;;buZt2uOvah}&4-+&E=~uIIX-3X_bB3q z)CHf7H#hoeM=x}76j~$4U(qi(>Kbz~#+7m|N&5~0@kRn?oAzZf&AUXb+;Tw-q%Dzrf$rO^>8n{m53GisG*jTjWQ!rN9{$!PCD|Z7b8-q3xL)qhFUF z{VKq^iAQgm^KI=-M`OHHV^ltXv>1Y1wmF0-o(knaC@f+*@c`b53mpk856=d&kK z>Z1(mU45c{n?Ze|LA}$UeuzQ+lRi=3Y*4QkYXxk?T)YWWQwI7W$zl9xWP``y8 z(z4Q^g&#X;fZg?szD1?6)Lz9F^%nMhpd;GV&0E+3&-(r45YMXZS9jBP9W(b}yDGc1 zzS2EiBilZ1y4G@LoC#bZMal>1LCR*dYp4AE3|+JK?r}R1=OZ>&*``~eamH^$DyVRj zwIsE*>=gAngF465QR>WXBard08Pp5cOoX3G zuBaY?jQ@i{y`)dnmm1WQ2K5eu`X>hUvOZC7G^iIC)E_jc$AVa=tgfO@)LRVd#Rl~) z2KC&4x{5Y8brWs$dKZE3=tvv#FV%`F-HLQkR4w4Wt0HYXqKB}kZX#{KvyQYOo>kl5 z?56EHBJII;Rc_V#${a<3ie897g^C6y9 z+gCtha&E^QP3Snk2isM-LF+4X3?J92wVWAe!X#}Qc1gxK@3(8GA}!bSjM&(?V$F|l zbz3kDkKl|SiYYn;QP#3STgy&Sf5f0(Vo={|P%ks6xAlqo7K3`3L4BJ+eY`<^W1px$ zVNkCysBbr@Pcx{u_lf#egZe~+dZ$7C1cUnKK2d+xpk8HA-(gT+Y*6p$6ZLHd_2~xn zE`xfjLH)r#Q5P%Z!i)VGs&Ul@^-m1y-!Q0e=@a$sM%!x)>R?TKw;c74zs;b&wNKPv zH>lSc)RP8vu8ALwHrx6{z0;t+*q~luP=CjuzP(S>-!iB-8q|vo>VGt-clL?;4ukq? zgL;WUJr-maD$eid6ZH=a>a7O#GK2akgL+q=sCOCEHyG3_4CYwz9`bP%!HiP;^ zgL-8^UF9}kL8(l+jn36Jgc_1chh#A z*X_Y}RaR+zWzN~gZPZ%Mj5FaAZ5#I98S^^7T|1RoZO}FAEN&d%VTojMmF-3^^9THr z6^*n>Z7n-R{R)G+rKO?ysoZQ(j~lVBpik7fx_zXj6KH_P9WX z+T%iURvuTPTd@a5QuV#?xPWKvaUq^n+aK?y?b_q^V7n^$wO1KQ%qJ0aD+;uhyYaYd zwQY3caeljY%I52J&Dz4paZQYf9agsKR%o2@uLT~bB>!ADlGj!j)T6B~L`zv+#U8Y} z>Rwn~z_Zp@h-cOI7{rySkJDDS2isM-QR^$SMUCV8r#)EagvHu6(yR$)v}>oVu0q$W zEo$6@nja0RtkbQ~kny(#R;R3GqPCWuqF!lG-(pZ-Y*4??pkCD{>Jts>TMg=s26cXu zOnIeh`}96hpJY(qW>8;kP=CsxUfn0^RR;C#2K82h`nG_&@;LsImC56Dv+Yjxg?b<8%V7n?eXnl1PZ927*Ca^kXEsM3a>=boAuoR`^~8vbrhVSe^E`K!)1mLUL9zY}KvU10IKm;8Y)n2m3fZ6xx)3nR*`= z;#swQ8j`n6(MEgR9&A@-jn-FYZyML3wVWAeLQ>m?yTP|Z-f2)@ZBQ>Us82SiZ|oEG*A428 z2K8ctdbvTpy-(D)8`KvY)C&yiBMj=B`$YXkgL<7oJ!w$SHK=#=iTXB!dW}KdGN^xs zNBC9mpltrZK2d+xpk8fI{{%5N(i4sU*r2|pPt>;>)TbNNyA0~v4eDF_L|uI65@9R& zZKBGczQdrt)u6tuPt>;QNPciUSd$+YEa)`Q19v!^$vr2u|a){L7m?MkNW#3eWHGsLA}7B{-8m< z&Y*7nM$N15R1dq^pq@0S^U3;Xv^mD0p6nBKu45Ldd7NcX-)vAn+@N02C+h76^-u7& zK!l&lc7uAkLA|(7)NeGXcNx?-8q^0F)JytAeWO90Us{Z|z0IKhDe`B9qx!hAK2g8c zpx$Xv-(XOG%b;G-C+ckm_3Z}rR)hMB2K9-3qJD)zeVajjwL$#}gL+k;sBbW+Z#Ael z8r1JGs88<`^$QK^TMX)p4eB=<)T{eMz15)pph3OPpuWMNUehP)=Nr^J4C*xo^+tnw zU7x70HmGkls8<`*zhqEf+$ZWS2K9D>`gDW(F$VRWdBP8w~0d2KAu^^$mTZUT;uuHK>;v)RPAFwmwm>GpMgNsFxVj zKSl?q`ZzUfG#mV6nl;ihWeQ)Ir>ah!>b`xyql|jaa<v{`SH0Dl(I2NqYd%LL=cgN*XO;= zHrfO-o4Nn)9&@+R=DRqr!?##l9Ue)JbnPk+r@5zQZDUZhF>`;?%{|#}(5w0G#{0I@ zcHOSse?ql9_tC+T|GT*EB-1PLPFcSe2)X3grOz!ygRP2M2mO8}k-r%dU?{_ zj-pZhq~$0TdGVRT=*J9aMpl7b*WX*WG%X-!M6XAHoHR0XuSbFGKpW&KjC>e~-H8}^ z3do1d{>8{uAoQUtM!o{%1;P2>fE*Rbw}?jcdL`a#xcif=ALesA5c})%j2r_(2InR0 z0I`*1ruiix7oO%7U}Tq&w}hPkf_jNrd=|(>G5700Mug1I0z^wU7j2yJ{F$cIF)AG#$fS>0_wE|?l4&*EMn zw$cuH68+Mbh`$d)GB;90kPWT+s^%cga`@SK*%vX&Cdg|->m1+ zKLNy^3mEw;>V*%cW;FH%jf@6-o(Dqlz;hmXU0H{>0oiq{to01DJceFg&+i0{t#$M0 z?*g*rw5sqbd4>2%J^U(nKr`Z2S>ZJ_?YNcl8!)VX9;VTSo_`IvE()#w4G?l$@425R1Rv&1fBh4X7lh2;1|p;JZ9j&Y3O)ybNb8*i za!IUU1BiVtmnG~2xhAxF9!SmUhvcC*a-9}@{v60UTD;6(1ad{l{52rQM6Xx8A&Tha z>-F;*Aoe*umS+mc8K+emy#~ad3z#MbvLjaK9Q6|N{5tg#n*RupyFlYL|2ZJXgbu$7 zqy`#q;m-rH`8>S)j$JqF}5{_nMV2?%}sO#cDMGhYg2{t6H|)8~Mkce79m zzZS0eEs;KIz2a8p?2#V@a{eEQvz72oKLKrY`I<`TaOWL;?WV?b_*xjzZy zw6NaK0J-i~5TZt31F|b@?w3!8R1!TTg0>s|?;~X-Ev5p9t zKLDCh5fd%|IpZW;Zl-A$TrX+;@Y+Yw$3Szzt)NOetyZV5=^&)>f=i&eCVG7eNF>Jk z9FSuo+I$rVW#)bs&jGpq<bG-55D1#(@` z?7t1Y+*)AJ=yo7Y{Gat)WQ}%=Oa2DdsF~>)XpRZa?*wwv^&&o}fY68M1y5-wt!^|f zdNn}P6?*@)wO=(m78E@XZJ$T2am&jPst&-JVPuRv^lV;^`$(SHHC zAS~gg+rdZ3^I9Ogpk+RJ%FbL9zC1%TV)Qj2^zjjL8;HHX%%lG%kc(mke-Frx82!(H z*l#LvuNy$_5;E_*10DzQ{7hd33ofz(8=7|8bk@iZMESH92AojCjo^>W%!YqWd8R?z}7qxlbm=Cm07kAdt8*NJHx#0?||@oFGmfZYe2eU1)m2}!#}b!=5sUF(|*4I6_0khNj626=_R}uG*^XI zr-1Cbxvy>JSue#{f@TFYJ7N|Y5c{q(9(@zY8T|9|Jc6rTp|RfvLLcuJPgamm0jY_Z zejUg$ln)S0%uK&Y2(J9RM&1fL6f(aNh|f;B`hy)`(7X*aSH--J1EKkN3Eu~VJ|5X1 z&Q4?0_6tBpgthzukgk~fCkX*9ac7Nv2FOW4^Upvo2%2vIx%hNA_x(Qw0?gm*`L#f{ zggkcu*>y8Tq-~~c>~RhOhv@B~85exs1>};Txu5um(a!>jgwTYONRFV$>xoFy1W5&7C!^zg5$H6r|>{% zLqzp=gXW6pRR^*II`)D-uEy%=YQLf4JZ?AA!d_ zUchARpG2d=>rT?l3RJ_)V0pX2*Gln^CS~o7xS7>!kfMbeYko3r*PCgMA7MyUqOx|@ zi}(%BcZ}ufTDO;v`JP#?*(>UKr>E9Bc>-~AdTZfO!tM4;qAU8HVRTt5Zlr28E>fgD zLq?0cUDey}rco8CI&H64^MN*v!R#7^M4?^SUfvi1WQfZU5w+X9} zx`y8GI6XBv8I9?`X6Y~XTj7Fxcx}l8OYZI*(r^u(JoIDd*St>W&Ygp0G?GN+X#)

WEGKdJfMj@atC!H?33`^;EWdaStP6&gg>{#u;$`Z+cWM>uhBg|M4<>ir}TY~pBzrbzP)RVmNr9zn9&?5Dj> zr?*~}equsUuIt?^V5Ie&bh_JmA%X_2W7@mR4TmDyAQiR^dSn5ss4q#kfzl?la$R># z6EHszLB|x0)n<$h)X!_&|9#}%;P0cs-}eN6Ped_sP&&`2s%f{GQlt$?^bA)i=Hp2V zCJb8jG~1o_P=Z53RF$paB$C$CVDXRWxjF`@nT3todPE}_Yz1>ZqHQM>L2@{(O(tvO zo}JbfX5r;OtZk*!?+tF%W`f;Rr5kCxr>O4ZbbT1QtJlqz6u??v)S^98cMKNxu(yjr zJP!qo4$@6&tVw$<3nhj^2EnWah+6J&NY7uJQl-gxN~J~5e9%CLv_nvf4Mkq$LoVtt zzdQ<2wCV8hg`t1+-0-2l#sJ*)(WELZj3|iwwL;#iz$Y0g+Qw*;9Mba z+A4aT?y4B~pbH>|`v4NHwt)Wt5~ns1CJwqNZJ5het+0TvZ1wsIwS3TpV#6{CTMuYm z1uSK&Q&b%%2InaUT(mVTWver&fvrwA^&(`c_2K>dkDmJR}aq8Hq5c zjU*h9b5=_*-I zaZ<8Z{Vop0sk_WmI$_XO4Q`u>>UC7Vw{}$TB{^~&wccOlWRa{KJ87EZhMh!NPgp8W z3~_o(+x=Ebd8a1iWJO>hMF*B<%$-j9G!A8l^|Tjf%|c)6z0m@tLll-r8i`1d>K)Z+ zc2*&B9mh)Y3y;u26P1YaNpostaY@b1;;^71I&C5q%+Bcy#GXNk6>$oVq!l*iQ5_tY zn>hQJ9(l^UJoy!lcKKPXccPD~lu^a2O)3*?Ei(pTyJ>dl=!DAqZEX;Fio7bO!8c(J zB-_|{Wni^*YGGw|en!=nXHHEo;%qRtIK}gsS(qMFs2JWsVU~PW&f^SK4qHwrdZ&;h z&!f07gW`gvf$jDITOu|1Fm9-O>p9I!olUoSX~wWk(tLvUq=;-YY`UOqN^MRYW|4>i z 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 literal 0 HcmV?d00001 From 86543971a40627232e153866c2d09d6005ba4ce4 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 14 Feb 2023 08:27:15 +0100 Subject: [PATCH 7/9] feat: unified maple_upload and dfu_util scripts shellcheck and shfmt applied Signed-off-by: Frederic Pillon --- dfu-util.sh | 40 ++++++++++++++++ linux/dfu-util.sh | 23 ---------- linux/maple_upload.sh | 64 -------------------------- macosx/dfu-util.sh | 18 -------- macosx/maple_upload.sh | 64 -------------------------- maple_upload.sh | 102 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 169 deletions(-) create mode 100755 dfu-util.sh delete mode 100755 linux/dfu-util.sh delete mode 100755 linux/maple_upload.sh delete mode 100644 macosx/dfu-util.sh delete mode 100755 macosx/maple_upload.sh create mode 100755 maple_upload.sh diff --git a/dfu-util.sh b/dfu-util.sh new file mode 100755 index 000000000..7b520fbd8 --- /dev/null +++ b/dfu-util.sh @@ -0,0 +1,40 @@ +#!/bin/sh - +# +# Use the correct dfu-util program based on the architecture +# + +# Get the directory where the script is running. +DIR=$(cd "$(dirname "$0")" && pwd) +UNAME_OS="$(uname -s)" +case "${UNAME_OS}" in + Linux*) + # Choose dfu program by arch + if [ "$(uname -m)" = "x86_64" ]; then + DFU_UTIL=${DIR}/linux/dfu-util_x86_64/dfu-util + else + DFU_UTIL=${DIR}/linux/dfu-util/dfu-util + fi + ;; + Darwin*) + DFU_UTIL=${DIR}/macosx/dfu-util/dfu-util + if [ ! -x "${DFU_UTIL}" ]; then + DFU_UTIL=/opt/local/bin/dfu-util + fi + ;; + Windows*) + DFU_UTIL=${DIR}/win/dfu-util.exe + ;; + *) + echo "Unknown host OS: ${UNAME_OS}." + exit 1 + ;; +esac + +# Not found! +if [ ! -x "${DFU_UTIL}" ]; then + echo "$0: error: cannot find ${DFU_UTIL}" >&2 + exit 2 +fi + +# Pass all parameters through +"${DFU_UTIL}" "$@" diff --git a/linux/dfu-util.sh b/linux/dfu-util.sh deleted file mode 100755 index 2f355b4ce..000000000 --- a/linux/dfu-util.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# -# Use the correct dfu-util program based on the architecture -# - -# Get the directory where the script is running. -DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) - -# Choose dfu program by arch -if [ "$(uname -m)" == "x86_64" ]; then - DFU_UTIL=${DIR}/dfu-util_x86_64/dfu-util -else - DFU_UTIL=${DIR}/dfu-util/dfu-util -fi - -# Not found! -if [ ! -x "${DFU_UTIL}" ]; then - echo "$0: error: cannot find ${DFU_UTIL}" >&2 - exit 2 -fi - -# Pass all parameters through -"${DFU_UTIL}" "$@" diff --git a/linux/maple_upload.sh b/linux/maple_upload.sh deleted file mode 100755 index 37d21ce20..000000000 --- a/linux/maple_upload.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash - -set -e - -if [ $# -lt 4 ]; then - echo "Usage: $0 $# " >&2 - exit 1 -fi -altID="$2" -usbID="$3" -binfile="$4" -dummy_port_fullpath="/dev/$1" -if [ $# -eq 5 ]; then - dfuse_addr="--dfuse-address $5" -else - dfuse_addr="" -fi - -# Get the directory where the script is running. -DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) - -# ----------------- IMPORTANT ----------------- -# The 2nd parameter to upload-reset is the delay after resetting before it exits -# This value is in milliseonds -# You may need to tune this to your system -# 750ms to 1500ms seems to work on my Mac -# This is less critical now that we automatically retry dfu-util - -if ! "${DIR}/upload-reset" "${dummy_port_fullpath}" 750; then - echo "****************************************" >&2 - echo "* Could not automatically reset device *" >&2 - echo "* Please manually reset device! *" >&2 - echo "****************************************" >&2 - sleep 2 # Wait for user to see message. -fi - -COUNTER=5 -while - "${DIR}/dfu-util.sh" -d "${usbID}" -a "${altID}" -D "${binfile}" "${dfuse_addr}" -R - ((ret = $?)) -do - if [ $ret -eq 74 ] && [ $((--COUNTER)) -gt 0 ]; then - # I/O error, probably because no DFU device was found - echo "Trying ${COUNTER} more time(s)" >&2 - sleep 1 - else - exit $ret - fi -done - -echo -n "Waiting for ${dummy_port_fullpath} serial..." >&2 - -COUNTER=40 -while [ ! -r "${dummy_port_fullpath}" ] && ((COUNTER--)); do - echo -n "." >&2 - sleep 0.1 -done - -if [ $COUNTER -eq -1 ]; then - echo " Timed out." >&2 - exit 1 -else - echo " Done." >&2 -fi diff --git a/macosx/dfu-util.sh b/macosx/dfu-util.sh deleted file mode 100644 index 77bd42617..000000000 --- a/macosx/dfu-util.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# Get the directory where the script is running. -DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) - -DFU_UTIL=${DIR}/dfu-util/dfu-util -if [ ! -x "${DFU_UTIL}" ]; then - DFU_UTIL=/opt/local/bin/dfu-util -fi - -# Not found! -if [ ! -x "${DFU_UTIL}" ]; then - echo "$0: error: cannot find ${DFU_UTIL}" >&2 - exit 2 -fi - -# Pass all parameters through -"${DFU_UTIL}" "$@" diff --git a/macosx/maple_upload.sh b/macosx/maple_upload.sh deleted file mode 100755 index 37d21ce20..000000000 --- a/macosx/maple_upload.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash - -set -e - -if [ $# -lt 4 ]; then - echo "Usage: $0 $# " >&2 - exit 1 -fi -altID="$2" -usbID="$3" -binfile="$4" -dummy_port_fullpath="/dev/$1" -if [ $# -eq 5 ]; then - dfuse_addr="--dfuse-address $5" -else - dfuse_addr="" -fi - -# Get the directory where the script is running. -DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) - -# ----------------- IMPORTANT ----------------- -# The 2nd parameter to upload-reset is the delay after resetting before it exits -# This value is in milliseonds -# You may need to tune this to your system -# 750ms to 1500ms seems to work on my Mac -# This is less critical now that we automatically retry dfu-util - -if ! "${DIR}/upload-reset" "${dummy_port_fullpath}" 750; then - echo "****************************************" >&2 - echo "* Could not automatically reset device *" >&2 - echo "* Please manually reset device! *" >&2 - echo "****************************************" >&2 - sleep 2 # Wait for user to see message. -fi - -COUNTER=5 -while - "${DIR}/dfu-util.sh" -d "${usbID}" -a "${altID}" -D "${binfile}" "${dfuse_addr}" -R - ((ret = $?)) -do - if [ $ret -eq 74 ] && [ $((--COUNTER)) -gt 0 ]; then - # I/O error, probably because no DFU device was found - echo "Trying ${COUNTER} more time(s)" >&2 - sleep 1 - else - exit $ret - fi -done - -echo -n "Waiting for ${dummy_port_fullpath} serial..." >&2 - -COUNTER=40 -while [ ! -r "${dummy_port_fullpath}" ] && ((COUNTER--)); do - echo -n "." >&2 - sleep 0.1 -done - -if [ $COUNTER -eq -1 ]; then - echo " Timed out." >&2 - exit 1 -else - echo " Done." >&2 -fi diff --git a/maple_upload.sh b/maple_upload.sh new file mode 100755 index 000000000..2b10603a9 --- /dev/null +++ b/maple_upload.sh @@ -0,0 +1,102 @@ +#!/bin/sh - + +set -e + +if [ $# -lt 4 ]; then + echo "Usage: $0 " >&2 + exit 1 +fi +altID="$2" +usbID="$3" +binfile="$4" +EXT="" + +UNAME_OS="$(uname -s)" +case "${UNAME_OS}" in + Linux*) + dummy_port_fullpath="/dev/$1" + OS_DIR="linux" + ;; + Darwin*) + dummy_port_fullpath="/dev/$1" + OS_DIR="macosx" + ;; + Windows*) + dummy_port_fullpath="$1" + OS_DIR="win" + EXT=".exe" + ;; + *) + echo "Unknown host OS: ${UNAME_OS}." + exit 1 + ;; +esac + +# Get the directory where the script is running. +DIR=$(cd "$(dirname "$0")" && pwd) + +# ----------------- IMPORTANT ----------------- +# The 2nd parameter to upload_reset is the delay after resetting +# before it exits. This value is in milliseonds. +# You may need to tune this to your system +# 750ms to 1500ms seems to work on my Mac +# This is less critical now that we automatically retry dfu-util + +if ! "${DIR}/${OS_DIR}/upload_reset${EXT}" "${dummy_port_fullpath}" 750; then + echo "****************************************" >&2 + echo "* Could not automatically reset device *" >&2 + echo "* Please manually reset device! *" >&2 + echo "****************************************" >&2 + sleep 2 # Wait for user to see message. +fi + +COUNTER=5 +while + if [ $# -eq 5 ]; then + "${DIR}/dfu-util.sh" -d "${usbID}" -a "${altID}" -D "${binfile}" "--dfuse-address $5" -R + else + "${DIR}/dfu-util.sh" -d "${usbID}" -a "${altID}" -D "${binfile}" -R + fi + ret=$? +do + if [ $ret -eq 0 ]; then + break + else + COUNTER=$((COUNTER - 1)) + if [ $ret -eq 74 ] && [ $COUNTER -gt 0 ]; then + # I/O error, probably because no DFU device was found + echo "Trying ${COUNTER} more time(s)" >&2 + sleep 1 + else + exit $ret + fi + fi +done + +printf "Waiting for %s serial..." "${dummy_port_fullpath}" >&2 +COUNTER=40 +if [ ${OS_DIR} = "win" ]; then + while [ $COUNTER -gt 0 ]; do + if ! "${DIR}/${OS_DIR}/check_port${EXT}" "${dummy_port_fullpath}"; then + COUNTER=$((COUNTER - 1)) + printf "." >&2 + sleep 0.1 + else + break + fi + done + +else + while [ ! -r "${dummy_port_fullpath}" ] && [ $COUNTER -gt 0 ]; do + COUNTER=$((COUNTER - 1)) + printf "." >&2 + sleep 0.1 + done +fi + +if [ $COUNTER -eq -0 ]; then + echo " Timed out." >&2 + exit 1 +else + echo " Done." >&2 +fi From 90248bcd1a3b4b7f018bfe4f9ec4737486429bc2 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 14 Feb 2023 10:21:54 +0100 Subject: [PATCH 8/9] chore: clean up old windows maple_upload based on java Signed-off-by: Frederic Pillon --- win/lib/jssc.jar | Bin 153562 -> 0 bytes win/maple_loader.jar | Bin 52672 -> 0 bytes win/maple_upload.bat | 18 ------------------ 3 files changed, 18 deletions(-) delete mode 100644 win/lib/jssc.jar delete mode 100644 win/maple_loader.jar delete mode 100644 win/maple_upload.bat diff --git a/win/lib/jssc.jar b/win/lib/jssc.jar deleted file mode 100644 index d2b5c070aa930c06e653db0bcae7eab9c5ca4f7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153562 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 diff --git a/win/maple_upload.bat b/win/maple_upload.bat deleted file mode 100644 index 7d59bf53b..000000000 --- a/win/maple_upload.bat +++ /dev/null @@ -1,18 +0,0 @@ -@echo off -rem: Note %~dp0 get path of this batch file -rem: Need to change drive if My Documents is on a drive other than C: -set driverLetter=%~dp0 -set driverLetter=%driverLetter:~0,2% -%driverLetter% -cd %~dp0 -java -jar maple_loader.jar %1 %2 %3 %4 %5 %6 %7 %8 %9 - -for /l %%x in (1, 1, 40) do ( - ping -w 50 -n 1 192.0.2.1 > nul - mode %1 > nul - if ERRORLEVEL 0 goto comPortFound -) - -echo timeout waiting for %1 serial - -:comPortFound From 6c359dfa74832f45500008577ad0d81cd8b1afe5 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Tue, 14 Feb 2023 10:25:16 +0100 Subject: [PATCH 9/9] chore: clean up dfu-utils sources Signed-off-by: Frederic Pillon --- linux/src/dfu-util/AUTHORS | 30 - linux/src/dfu-util/COPYING | 340 --------- linux/src/dfu-util/ChangeLog | 93 --- linux/src/dfu-util/DEVICES.txt | 20 - linux/src/dfu-util/Makefile.am | 3 - linux/src/dfu-util/README | 20 - linux/src/dfu-util/TODO | 14 - linux/src/dfu-util/autogen.sh | 2 - linux/src/dfu-util/configure.ac | 41 - linux/src/dfu-util/device-logs/README | 77 -- linux/src/dfu-util/device-logs/dsonano.lsusb | 60 -- linux/src/dfu-util/device-logs/lpclink.log | 59 -- linux/src/dfu-util/device-logs/lpclink.lsusb | 58 -- linux/src/dfu-util/device-logs/lpclink2.log | 59 -- linux/src/dfu-util/device-logs/lpclink2.lsusb | 203 ----- linux/src/dfu-util/device-logs/opc-20.lsusb | 60 -- .../openmoko-freerunner-dfumode.lsusb | 109 --- .../device-logs/openmoko-freerunner.lsusb | 179 ----- .../device-logs/openmoko-neo1973.lsusb | 182 ----- linux/src/dfu-util/device-logs/openpcd.lsusb | 60 -- .../device-logs/qi-hardware-atusb.lsusb | 59 -- linux/src/dfu-util/device-logs/simtrace.lsusb | 70 -- .../src/dfu-util/device-logs/sparkcore.lsusb | 60 -- .../device-logs/stm32f107.bin-download | 48 -- .../src/dfu-util/device-logs/stm32f107.lsusb | 60 -- .../device-logs/stm32f4discovery.bin-download | 36 - .../device-logs/stm32f4discovery.lsusb | 80 -- .../dfu-util/device-logs/tdk-bluetooth.lsusb | 269 ------- linux/src/dfu-util/dfuse-pack.py | 121 --- linux/src/dfu-util/doc/40-dfuse.rules | 4 - linux/src/dfu-util/doc/Makefile.am | 2 - linux/src/dfu-util/doc/SPEC-differences.txt | 21 - linux/src/dfu-util/doc/dfu-util.1 | 248 ------- linux/src/dfu-util/msvc/README_msvc.txt | 10 - .../src/dfu-util/msvc/dfu-suffix_2010.vcxproj | 100 --- linux/src/dfu-util/msvc/dfu-util_2010.sln | 54 -- linux/src/dfu-util/msvc/dfu-util_2010.vcxproj | 120 --- linux/src/dfu-util/src/Makefile.am | 28 - linux/src/dfu-util/src/dfu.c | 357 --------- linux/src/dfu-util/src/dfu.h | 133 ---- linux/src/dfu-util/src/dfu_file.c | 444 ----------- linux/src/dfu-util/src/dfu_file.h | 60 -- linux/src/dfu-util/src/dfu_load.c | 196 ----- linux/src/dfu-util/src/dfu_load.h | 7 - linux/src/dfu-util/src/dfu_util.c | 346 --------- linux/src/dfu-util/src/dfu_util.h | 36 - linux/src/dfu-util/src/dfuse.c | 652 ---------------- linux/src/dfu-util/src/dfuse.h | 35 - linux/src/dfu-util/src/dfuse_mem.c | 198 ----- linux/src/dfu-util/src/dfuse_mem.h | 44 -- linux/src/dfu-util/src/main.c | 699 ------------------ linux/src/dfu-util/src/portable.h | 72 -- linux/src/dfu-util/src/prefix.c | 176 ----- linux/src/dfu-util/src/quirks.c | 56 -- linux/src/dfu-util/src/quirks.h | 27 - linux/src/dfu-util/src/suffix.c | 176 ----- linux/src/dfu-util/src/usb_dfu.h | 99 --- linux/src/dfu-util/www/build.html | 147 ---- linux/src/dfu-util/www/dfu-util.1.html | 411 ---------- linux/src/dfu-util/www/dfuse.html | 135 ---- linux/src/dfu-util/www/index.html | 119 --- linux/src/dfu-util/www/simple.css | 56 -- macosx/src/build_dfu-util.sh | 15 - macosx/src/dfu-util/AUTHORS | 30 - macosx/src/dfu-util/COPYING | 340 --------- macosx/src/dfu-util/ChangeLog | 93 --- macosx/src/dfu-util/DEVICES.txt | 20 - macosx/src/dfu-util/Makefile.am | 3 - macosx/src/dfu-util/README | 20 - macosx/src/dfu-util/TODO | 14 - macosx/src/dfu-util/autogen.sh | 2 - macosx/src/dfu-util/configure.ac | 41 - macosx/src/dfu-util/device-logs/README | 77 -- macosx/src/dfu-util/device-logs/dsonano.lsusb | 60 -- macosx/src/dfu-util/device-logs/lpclink.log | 59 -- macosx/src/dfu-util/device-logs/lpclink.lsusb | 58 -- macosx/src/dfu-util/device-logs/lpclink2.log | 59 -- .../src/dfu-util/device-logs/lpclink2.lsusb | 203 ----- macosx/src/dfu-util/device-logs/opc-20.lsusb | 60 -- .../openmoko-freerunner-dfumode.lsusb | 109 --- .../device-logs/openmoko-freerunner.lsusb | 179 ----- .../device-logs/openmoko-neo1973.lsusb | 182 ----- macosx/src/dfu-util/device-logs/openpcd.lsusb | 60 -- .../device-logs/qi-hardware-atusb.lsusb | 59 -- .../src/dfu-util/device-logs/simtrace.lsusb | 70 -- .../src/dfu-util/device-logs/sparkcore.lsusb | 60 -- .../device-logs/stm32f107.bin-download | 48 -- .../src/dfu-util/device-logs/stm32f107.lsusb | 60 -- .../device-logs/stm32f4discovery.bin-download | 36 - .../device-logs/stm32f4discovery.lsusb | 80 -- .../dfu-util/device-logs/tdk-bluetooth.lsusb | 269 ------- macosx/src/dfu-util/dfuse-pack.py | 121 --- macosx/src/dfu-util/doc/40-dfuse.rules | 4 - macosx/src/dfu-util/doc/Makefile.am | 2 - macosx/src/dfu-util/doc/SPEC-differences.txt | 21 - macosx/src/dfu-util/doc/dfu-util.1 | 248 ------- macosx/src/dfu-util/msvc/README_msvc.txt | 10 - .../src/dfu-util/msvc/dfu-suffix_2010.vcxproj | 100 --- macosx/src/dfu-util/msvc/dfu-util_2010.sln | 54 -- .../src/dfu-util/msvc/dfu-util_2010.vcxproj | 120 --- macosx/src/dfu-util/src/Makefile.am | 28 - macosx/src/dfu-util/src/dfu.c | 357 --------- macosx/src/dfu-util/src/dfu.h | 133 ---- macosx/src/dfu-util/src/dfu_file.c | 444 ----------- macosx/src/dfu-util/src/dfu_file.h | 60 -- macosx/src/dfu-util/src/dfu_load.c | 196 ----- macosx/src/dfu-util/src/dfu_load.h | 7 - macosx/src/dfu-util/src/dfu_util.c | 346 --------- macosx/src/dfu-util/src/dfu_util.h | 36 - macosx/src/dfu-util/src/dfuse.c | 652 ---------------- macosx/src/dfu-util/src/dfuse.h | 35 - macosx/src/dfu-util/src/dfuse_mem.c | 198 ----- macosx/src/dfu-util/src/dfuse_mem.h | 44 -- macosx/src/dfu-util/src/main.c | 699 ------------------ macosx/src/dfu-util/src/portable.h | 72 -- macosx/src/dfu-util/src/prefix.c | 176 ----- macosx/src/dfu-util/src/quirks.c | 56 -- macosx/src/dfu-util/src/quirks.h | 27 - macosx/src/dfu-util/src/suffix.c | 176 ----- macosx/src/dfu-util/src/usb_dfu.h | 99 --- macosx/src/dfu-util/www/build.html | 147 ---- macosx/src/dfu-util/www/dfu-util.1.html | 411 ---------- macosx/src/dfu-util/www/dfuse.html | 135 ---- macosx/src/dfu-util/www/index.html | 119 --- macosx/src/dfu-util/www/simple.css | 56 -- {linux/src => src/dfu-util}/build_dfu-util.sh | 1 - win/src/build_dfu-util.sh | 15 - 127 files changed, 15511 deletions(-) delete mode 100644 linux/src/dfu-util/AUTHORS delete mode 100644 linux/src/dfu-util/COPYING delete mode 100644 linux/src/dfu-util/ChangeLog delete mode 100644 linux/src/dfu-util/DEVICES.txt delete mode 100644 linux/src/dfu-util/Makefile.am delete mode 100644 linux/src/dfu-util/README delete mode 100644 linux/src/dfu-util/TODO delete mode 100644 linux/src/dfu-util/autogen.sh delete mode 100644 linux/src/dfu-util/configure.ac delete mode 100644 linux/src/dfu-util/device-logs/README delete mode 100644 linux/src/dfu-util/device-logs/dsonano.lsusb delete mode 100644 linux/src/dfu-util/device-logs/lpclink.log delete mode 100644 linux/src/dfu-util/device-logs/lpclink.lsusb delete mode 100644 linux/src/dfu-util/device-logs/lpclink2.log delete mode 100644 linux/src/dfu-util/device-logs/lpclink2.lsusb delete mode 100644 linux/src/dfu-util/device-logs/opc-20.lsusb delete mode 100644 linux/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb delete mode 100644 linux/src/dfu-util/device-logs/openmoko-freerunner.lsusb delete mode 100644 linux/src/dfu-util/device-logs/openmoko-neo1973.lsusb delete mode 100644 linux/src/dfu-util/device-logs/openpcd.lsusb delete mode 100644 linux/src/dfu-util/device-logs/qi-hardware-atusb.lsusb delete mode 100644 linux/src/dfu-util/device-logs/simtrace.lsusb delete mode 100644 linux/src/dfu-util/device-logs/sparkcore.lsusb delete mode 100644 linux/src/dfu-util/device-logs/stm32f107.bin-download delete mode 100644 linux/src/dfu-util/device-logs/stm32f107.lsusb delete mode 100644 linux/src/dfu-util/device-logs/stm32f4discovery.bin-download delete mode 100644 linux/src/dfu-util/device-logs/stm32f4discovery.lsusb delete mode 100644 linux/src/dfu-util/device-logs/tdk-bluetooth.lsusb delete mode 100644 linux/src/dfu-util/dfuse-pack.py delete mode 100644 linux/src/dfu-util/doc/40-dfuse.rules delete mode 100644 linux/src/dfu-util/doc/Makefile.am delete mode 100644 linux/src/dfu-util/doc/SPEC-differences.txt delete mode 100644 linux/src/dfu-util/doc/dfu-util.1 delete mode 100644 linux/src/dfu-util/msvc/README_msvc.txt delete mode 100644 linux/src/dfu-util/msvc/dfu-suffix_2010.vcxproj delete mode 100644 linux/src/dfu-util/msvc/dfu-util_2010.sln delete mode 100644 linux/src/dfu-util/msvc/dfu-util_2010.vcxproj delete mode 100644 linux/src/dfu-util/src/Makefile.am delete mode 100644 linux/src/dfu-util/src/dfu.c delete mode 100644 linux/src/dfu-util/src/dfu.h delete mode 100644 linux/src/dfu-util/src/dfu_file.c delete mode 100644 linux/src/dfu-util/src/dfu_file.h delete mode 100644 linux/src/dfu-util/src/dfu_load.c delete mode 100644 linux/src/dfu-util/src/dfu_load.h delete mode 100644 linux/src/dfu-util/src/dfu_util.c delete mode 100644 linux/src/dfu-util/src/dfu_util.h delete mode 100644 linux/src/dfu-util/src/dfuse.c delete mode 100644 linux/src/dfu-util/src/dfuse.h delete mode 100644 linux/src/dfu-util/src/dfuse_mem.c delete mode 100644 linux/src/dfu-util/src/dfuse_mem.h delete mode 100644 linux/src/dfu-util/src/main.c delete mode 100644 linux/src/dfu-util/src/portable.h delete mode 100644 linux/src/dfu-util/src/prefix.c delete mode 100644 linux/src/dfu-util/src/quirks.c delete mode 100644 linux/src/dfu-util/src/quirks.h delete mode 100644 linux/src/dfu-util/src/suffix.c delete mode 100644 linux/src/dfu-util/src/usb_dfu.h delete mode 100644 linux/src/dfu-util/www/build.html delete mode 100644 linux/src/dfu-util/www/dfu-util.1.html delete mode 100644 linux/src/dfu-util/www/dfuse.html delete mode 100644 linux/src/dfu-util/www/index.html delete mode 100644 linux/src/dfu-util/www/simple.css delete mode 100644 macosx/src/build_dfu-util.sh delete mode 100644 macosx/src/dfu-util/AUTHORS delete mode 100644 macosx/src/dfu-util/COPYING delete mode 100644 macosx/src/dfu-util/ChangeLog delete mode 100644 macosx/src/dfu-util/DEVICES.txt delete mode 100644 macosx/src/dfu-util/Makefile.am delete mode 100644 macosx/src/dfu-util/README delete mode 100644 macosx/src/dfu-util/TODO delete mode 100644 macosx/src/dfu-util/autogen.sh delete mode 100644 macosx/src/dfu-util/configure.ac delete mode 100644 macosx/src/dfu-util/device-logs/README delete mode 100644 macosx/src/dfu-util/device-logs/dsonano.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/lpclink.log delete mode 100644 macosx/src/dfu-util/device-logs/lpclink.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/lpclink2.log delete mode 100644 macosx/src/dfu-util/device-logs/lpclink2.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/opc-20.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/openmoko-freerunner.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/openmoko-neo1973.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/openpcd.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/qi-hardware-atusb.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/simtrace.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/sparkcore.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/stm32f107.bin-download delete mode 100644 macosx/src/dfu-util/device-logs/stm32f107.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/stm32f4discovery.bin-download delete mode 100644 macosx/src/dfu-util/device-logs/stm32f4discovery.lsusb delete mode 100644 macosx/src/dfu-util/device-logs/tdk-bluetooth.lsusb delete mode 100644 macosx/src/dfu-util/dfuse-pack.py delete mode 100644 macosx/src/dfu-util/doc/40-dfuse.rules delete mode 100644 macosx/src/dfu-util/doc/Makefile.am delete mode 100644 macosx/src/dfu-util/doc/SPEC-differences.txt delete mode 100644 macosx/src/dfu-util/doc/dfu-util.1 delete mode 100644 macosx/src/dfu-util/msvc/README_msvc.txt delete mode 100644 macosx/src/dfu-util/msvc/dfu-suffix_2010.vcxproj delete mode 100644 macosx/src/dfu-util/msvc/dfu-util_2010.sln delete mode 100644 macosx/src/dfu-util/msvc/dfu-util_2010.vcxproj delete mode 100644 macosx/src/dfu-util/src/Makefile.am delete mode 100644 macosx/src/dfu-util/src/dfu.c delete mode 100644 macosx/src/dfu-util/src/dfu.h delete mode 100644 macosx/src/dfu-util/src/dfu_file.c delete mode 100644 macosx/src/dfu-util/src/dfu_file.h delete mode 100644 macosx/src/dfu-util/src/dfu_load.c delete mode 100644 macosx/src/dfu-util/src/dfu_load.h delete mode 100644 macosx/src/dfu-util/src/dfu_util.c delete mode 100644 macosx/src/dfu-util/src/dfu_util.h delete mode 100644 macosx/src/dfu-util/src/dfuse.c delete mode 100644 macosx/src/dfu-util/src/dfuse.h delete mode 100644 macosx/src/dfu-util/src/dfuse_mem.c delete mode 100644 macosx/src/dfu-util/src/dfuse_mem.h delete mode 100644 macosx/src/dfu-util/src/main.c delete mode 100644 macosx/src/dfu-util/src/portable.h delete mode 100644 macosx/src/dfu-util/src/prefix.c delete mode 100644 macosx/src/dfu-util/src/quirks.c delete mode 100644 macosx/src/dfu-util/src/quirks.h delete mode 100644 macosx/src/dfu-util/src/suffix.c delete mode 100644 macosx/src/dfu-util/src/usb_dfu.h delete mode 100644 macosx/src/dfu-util/www/build.html delete mode 100644 macosx/src/dfu-util/www/dfu-util.1.html delete mode 100644 macosx/src/dfu-util/www/dfuse.html delete mode 100644 macosx/src/dfu-util/www/index.html delete mode 100644 macosx/src/dfu-util/www/simple.css rename {linux/src => src/dfu-util}/build_dfu-util.sh (96%) delete mode 100644 win/src/build_dfu-util.sh diff --git a/linux/src/dfu-util/AUTHORS b/linux/src/dfu-util/AUTHORS deleted file mode 100644 index 1b36c739c..000000000 --- a/linux/src/dfu-util/AUTHORS +++ /dev/null @@ -1,30 +0,0 @@ -Authors ordered by first contribution. - -Harald Welte -Werner Almesberger -Michael Lauer -Jim Huang -Stefan Schmidt -Daniel Willmann -Mike Frysinger -Uwe Hermann -C. Scott Ananian -Bernard Blackham -Holger Freyther -Marc Singer -James Perkins -Tommi Keisala -Pascal Schweizer -Bradley Scott -Uwe Bonnes -Andrey Smirnov -Jussi Timperi -Hans Petter Selasky -Bo Shen -Henrique de Almeida Mendonca -Bernd Krumboeck -Dennis Meier -Veli-Pekka Peltola -Dave Hylands -Michael Grzeschik -Paul Fertser diff --git a/linux/src/dfu-util/COPYING b/linux/src/dfu-util/COPYING deleted file mode 100644 index d60c31a97..000000000 --- a/linux/src/dfu-util/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/linux/src/dfu-util/ChangeLog b/linux/src/dfu-util/ChangeLog deleted file mode 100644 index 37f1addba..000000000 --- a/linux/src/dfu-util/ChangeLog +++ /dev/null @@ -1,93 +0,0 @@ -0.8: - o New, separate dfu-prefix tool (Uwe Bonnes) - o Allow filtering on serial number (Uwe Bonnes) - o Improved VID/PID/serial filtering (Bradley Scott) - o Support reading firmware from stdin (Tormod Volden) - o Warn if missing DFU suffix (Tormod Volden) - o Improved progress bar (Hans Petter Selasky) - o Fix dfuse leave option (Uwe Bonnes) - o Major code rework (Hans Petter Selasky) - o MS Visual Studio build support (Henrique Mendonca) - o dfuse-pack.py tool for .dfu files (Antonio Galeo) - o Many other fixes from many people - -2014-09-13: Tormod Volden - -0.7: - o Support for TI Stellaris devices (Tommi Keisala) - o Fix libusb detection on MacOSX (Marc Singer) - o Fix libusb detection on FreeBSD (Tormod Volden) - o Improved DfuSe support (Tormod Volden) - o Support all special commands (leave, unprotect, mass-erase) - o Arbitrary upload lengths - o "force" option for various possible (dangerous) overrides - -2012-10-07: Tormod Volden - -0.6: - o Add detach mode (Stefan Schmidt) - o Check return value on all libusb calls (Tormod Volden) - o Fix segmentation fault with -s option (Tormod Volden) - o Add DFU suffix manipulation tool (Stefan Schmidt) - o Port to Windows: (Tormod Volden, some parts based on work from Satz - Klauer) - o Port file handling to stdio streams - o Sleep() macros - o C99 types - o Pack structs - o Detect DfuSe device correctly on big-endian architectures (Tormod - Volden) - o Add dfuse progress indication on download (Tormod Volden) - o Cleanup: gcc pedantic, gcc extension, ... (Tormod Volden) - o Rely on page size from functional descriptor. Please report if you get - an error about it. (Tormod Volden) - o Add quirk for Maple since it reports wrong DFU version (Tormod Volden) - -2012-04-22: Stefan Schmidt - -0.5: - o DfuSe extension support for ST devices (Tormod Volden) - o Add initial support for bitWillDetach flag from DFU 1.1 (Tormod - Volden) - o Internal cleanup and some manual page fixes (Tormod Volden) - -2011-11-02: Stefan Schmidt - -0.4: - o Rework to use libusb-1.0 (Stefan Schmidt) - o DFU suffix support (Tormod Volden, Stefan Schmidt) - o Sspeed up DFU downloads directly into memory (Bernard Blackham) - o More flexible -d vid:pid parsing (Tormod Volden) - o Many bug fixes and cleanups - -2011-07-20: Stefan Schmidt - -0.3: - o quirks: Add OpenOCD to the poll timeout quirk table. - -2010-12-22: Stefan Schmidt - -0.2: - o Fix some typos on the website and the README (Antonio Ospite, Uwe - Hermann) - o Remove build rule for a static binary. We can use autotools for this. - (Mike Frysinger) - o Fix infinite loop in download error path (C. Scott Ananian) - o Break out to show the 'finished' in upload (C. Scott Ananian) - o Add GPLv2+ headers (Harald Welte) - o Remove dead code (commands.[ch]) remnescent of dfu-programmer (Harald - Welte) - o Simple quirk system with Openmoko quirk for missing bwPollTimeout (Tormod Volden) - o New default (1024) and clamping of transfer size (Tormod Volden) - o Verify sending of completion packet (Tormod Volden) - o Look for DFU functional descriptor among all descriptors (Tormod - Volden) - o Print out in which direction we are transferring data - o Abort in upload if the file already exists - -2010-11-17 Stefan Schmidt - -0.1: - Initial release - -2010-05-23 Stefan Schmidt diff --git a/linux/src/dfu-util/DEVICES.txt b/linux/src/dfu-util/DEVICES.txt deleted file mode 100644 index bdd9f1f2e..000000000 --- a/linux/src/dfu-util/DEVICES.txt +++ /dev/null @@ -1,20 +0,0 @@ -List of supported software and hardware products: - -Software user (bootloader, etc) -------------------------------- -- Sam7DFU: http://www.openpcd.org/Sam7dfu -- U-boot: DFU patches -- Barebox: http://www.barebox.org/ -- Leaflabs: http://code.google.com/p/leaflabs/ -- Blackmagic DFU - -Products using DFU ------------------- -- OpenPCD (sam7dfu) -- Openmoko Neo 1973 and Freerunner (u-boot with DFU patches) -- Leaflabs Maple -- ATUSB from Qi Hardware -- STM32F105/7, STM32F2/F3/F4 in System Bootloader -- Blackmagic debug probe -- NXP LPC31xx/LPC43XX, e.g. LPC-Link and LPC-Link2, need binaries - with LPC prefix and encoding (LPC-Link) diff --git a/linux/src/dfu-util/Makefile.am b/linux/src/dfu-util/Makefile.am deleted file mode 100644 index 641dda58a..000000000 --- a/linux/src/dfu-util/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -SUBDIRS = src doc - -EXTRA_DIST = autogen.sh TODO DEVICES.txt dfuse-pack.py diff --git a/linux/src/dfu-util/README b/linux/src/dfu-util/README deleted file mode 100644 index 0f8f2621a..000000000 --- a/linux/src/dfu-util/README +++ /dev/null @@ -1,20 +0,0 @@ -Dfu-util - Device Firmware Upgrade Utilities - -Dfu-util is the host side implementation of the DFU 1.0 [1] and DFU 1.1 [2] -specification of the USB forum. - -DFU is intended to download and upload firmware to devices connected over -USB. It ranges from small devices like micro-controller boards up to mobile -phones. With dfu-util you are able to download firmware to your device or -upload firmware from it. - -dfu-util has been tested with Openmoko Neo1973 and Freerunner and many -other devices. - -[1] DFU 1.0 spec: http://www.usb.org/developers/devclass_docs/usbdfu10.pdf -[2] DFU 1.1 spec: http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf - -The official website is: - - http://dfu-util.gnumonks.org/ - diff --git a/linux/src/dfu-util/TODO b/linux/src/dfu-util/TODO deleted file mode 100644 index 900c30c29..000000000 --- a/linux/src/dfu-util/TODO +++ /dev/null @@ -1,14 +0,0 @@ -DfuSe: -- Do erase and write in two separate passes when downloading -- Skip "Set Address" command when downloading contiguous blocks -- Implement "Get Commands" command - -Devices: -- Research iPhone/iPod/iPad support - Heavily modified dfu-util fork here: - https://github.com/planetbeing/xpwn/tree/master/dfu-util -- Test against Niftylights - -Non-Code: -- Logo -- Re-License as LGPL for usage as library? diff --git a/linux/src/dfu-util/autogen.sh b/linux/src/dfu-util/autogen.sh deleted file mode 100644 index e67aed39a..000000000 --- a/linux/src/dfu-util/autogen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -autoreconf -v -i diff --git a/linux/src/dfu-util/configure.ac b/linux/src/dfu-util/configure.ac deleted file mode 100644 index 86221143f..000000000 --- a/linux/src/dfu-util/configure.ac +++ /dev/null @@ -1,41 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.59) -AC_INIT([dfu-util],[0.8],[dfu-util@lists.gnumonks.org],,[http://dfu-util.gnumonks.org]) -AC_CONFIG_AUX_DIR(m4) -AM_INIT_AUTOMAKE([foreign]) -AC_CONFIG_HEADERS([config.h]) - -# Test for new silent rules and enable only if they are available -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -# Checks for programs. -AC_PROG_CC - -# Checks for libraries. -# On FreeBSD the libusb-1.0 is called libusb and resides in system location -AC_CHECK_LIB([usb], [libusb_init],, [native_libusb=no],) -AS_IF([test x$native_libusb = xno], [ - PKG_CHECK_MODULES([USB], [libusb-1.0 >= 1.0.0],, - AC_MSG_ERROR([*** Required libusb-1.0 >= 1.0.0 not installed ***])) -]) -AC_CHECK_LIB([usbpath],[usb_path2devnum],,,-lusb) - -LIBS="$LIBS $USB_LIBS" -CFLAGS="$CFLAGS $USB_CFLAGS" - -# Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS([usbpath.h windows.h sysexits.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_TYPE_SIZE_T - -# Checks for library functions. -AC_FUNC_MEMCMP -AC_CHECK_FUNCS([ftruncate getpagesize nanosleep err]) - -AC_CONFIG_FILES(Makefile src/Makefile doc/Makefile) -AC_OUTPUT diff --git a/linux/src/dfu-util/device-logs/README b/linux/src/dfu-util/device-logs/README deleted file mode 100644 index 00d3d1a96..000000000 --- a/linux/src/dfu-util/device-logs/README +++ /dev/null @@ -1,77 +0,0 @@ -Device: -------- -qi-hardware-atusb: -- Qi Hardware ben-wpan -- DFU implementation: - http://projects.qi-hardware.com/index.php/p/ben-wpan/source/tree/master/atusb/fw/usb -- Tester: Stefan Schmidt - -openpcd: -- OpenPCD RFID reader -- DFU implementation: SAM7DFU - http://www.openpcd.org/Sam7dfu, git://git.gnumonks.org/openpcd.git -- Tester: Stefan Schmidt - -simtrace: -- Sysmocom SimTrace -- DFU implementation: SAM7DFU - http://www.openpcd.org/Sam7dfu, git://git.gnumonks.org/openpcd.git -- Tester: Stefan Schmidt - -openmoko-freerunner: -- Openmoko Freerunner -- DFU implementation: Old U-Boot - http://git.openmoko.org/?p=u-boot.git;a=shortlog;h=refs/heads/mokopatches -- Tester: Stefan Schmidt - -openmoko-neo1973: -- Openmoko Neo1073 -- DFU implementation: Old U-Boot - http://git.openmoko.org/?p=u-boot.git;a=shortlog;h=refs/heads/mokopatches -- Tester: Stefan Schmidt - -tdk-bluetooth: -- TDK Corp. Bluetooth Adapter -- DFU implementation: closed soure -- Only upload has been tested -- Tester: Stefan Schmidt - -stm32f107: -- STM32 microcontrollers with built-in (ROM) DFU loader -- DFU implementation: Closed source but probably similar to the one - in their USB device libraries. Some relevant application notes: - http://www.st.com -> AN3156 and AN2606 -- Tested by Uwe Bonnes - -stm32f4discovery: -- STM32 microcontroller board with built-in (ROM) DFU loader -- DFU implementation: Closed source, probably similar to stm32f107. -- Tested by Joe Rothweiler - -dso-nano: -- DSO Nano pocket oscilloscope -- DFU implementation: Based on ST Microelectronics USB FS Library 1.0 - http://dsonano.googlecode.com/files/DS0201_OpenSource.rar -- Tester: Tormod Volden - -opc-20: -- Custom devices based on STM32F1xx -- DFU implementation: ST Microelectronics USB FS Device Library 3.1.0 - http://www.st.com -> um0424.zip -- Tester: Tormod Volden - -lpc-link, lpclink2: -- NXP LPCXpresso debug adapters -- Proprietary DFU implementation, uses special download files with - LPC prefix and encoding of the target firmware code -- Tested by Uwe Bonnes - -Adding the lsusb output and a download log of your device here helps -us to avoid regressions for hardware we cannot test while working on -the code. To extract the lsusb output use this command: -sudo lsusb -v -d $USBID > $DEVICE.lsusb -Prepare a description snippet as above, and send it to us. A log -(copy-paste of the command window) of a firmware download is also -nice, please use the double verbose option -v -v and include the -command line in the log file. - diff --git a/linux/src/dfu-util/device-logs/dsonano.lsusb b/linux/src/dfu-util/device-logs/dsonano.lsusb deleted file mode 100644 index 140a7bc6c..000000000 --- a/linux/src/dfu-util/device-logs/dsonano.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 002 Device 004: ID 0483:df11 SGS Thomson Microelectronics -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 - bcdDevice 1.1a - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 DFU - iSerial 3 001 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 64mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 4 @Internal Flash /0x08000000/12*001Ka,116*001Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 5 @SPI Flash : M25P64/0x00000000/64*064Kg,64*064Kg - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 1024 bytes - bcdDFUVersion 1.1a -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/lpclink.log b/linux/src/dfu-util/device-logs/lpclink.log deleted file mode 100644 index 7de4dd3e6..000000000 --- a/linux/src/dfu-util/device-logs/lpclink.log +++ /dev/null @@ -1,59 +0,0 @@ -(The on-board LPC3154 has some encryption key set and LPCXpressoWIN.enc -is encrypted.) - -$ lsusb | grep NXP -Bus 003 Device 011: ID 0471:df55 Philips (or NXP) LPCXpresso LPC-Link - -$ dfu-util -v -v -v -R -D /opt/lpc/lpcxpresso/bin/LPCXpressoWIN.enc - -dfu-util 0.7 - -Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc. -Copyright 2010-2012 Tormod Volden and Stefan Schmidt -This program is Free Software and has ABSOLUTELY NO WARRANTY -Please report bugs to dfu-util@lists.gnumonks.org - -dfu-util: Invalid DFU suffix signature -dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! -Deducing device DFU version from functional descriptor length -Opening DFU capable USB device... -ID 0471:df55 -Run-time device DFU version 0100 -Claiming USB DFU Runtime Interface... -Determining device status: -state = dfuIDLE, status = 0 -dfu-util: WARNING: Runtime device already in DFU state ?!? -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: -state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 0100 -Device returned transfer size 2048 -Copying data from PC to DFU device -Download [ ] 0% 0 bytes -Download [= ] 6% 2048 bytes -Download [=== ] 13% 4096 bytes -Download [==== ] 19% 6144 bytes -Download [====== ] 26% 8192 bytes -Download [======== ] 32% 10240 bytes -Download [========= ] 39% 12288 bytes -Download [=========== ] 45% 14336 bytes -Download [============= ] 52% 16384 bytes -Download [============== ] 59% 18432 bytes -Download [================ ] 65% 20480 bytes -Download [================== ] 72% 22528 bytes -Download [=================== ] 78% 24576 bytes -Download [===================== ] 85% 26624 bytes -Download [====================== ] 91% 28672 bytes -Download [======================== ] 98% 29192 bytes -Download [=========================] 100% 29192 bytes -Download done. -Sent a total of 29192 bytes -state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present -Done! -dfu-util: can't detach -Resetting USB to switch back to runtime mode - -$ lsusb | grep NXP -Bus 003 Device 012: ID 1fc9:0009 NXP Semiconductors diff --git a/linux/src/dfu-util/device-logs/lpclink.lsusb b/linux/src/dfu-util/device-logs/lpclink.lsusb deleted file mode 100644 index 867b2a2c5..000000000 --- a/linux/src/dfu-util/device-logs/lpclink.lsusb +++ /dev/null @@ -1,58 +0,0 @@ - -Bus 003 Device 008: ID 0471:df55 Philips (or NXP) LPCXpresso LPC-Link -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0471 Philips (or NXP) - idProduct 0xdf55 LPCXpresso LPC-Link - bcdDevice 0.01 - iManufacturer 0 - iProduct 0 - iSerial 0 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 25 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 0 - Device Firmware Upgrade Interface Descriptor: - bLength 7 - bDescriptorType 33 - bmAttributes 1 - Will Not Detach - Manifestation Intolerant - Upload Unsupported - Download Supported - wDetachTimeout 65535 milliseconds - wTransferSize 2048 bytes -Device Qualifier (for other device speed): - bLength 10 - bDescriptorType 6 - bcdUSB 2.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - bNumConfigurations 1 -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/lpclink2.log b/linux/src/dfu-util/device-logs/lpclink2.log deleted file mode 100644 index 4681eff7d..000000000 --- a/linux/src/dfu-util/device-logs/lpclink2.log +++ /dev/null @@ -1,59 +0,0 @@ -$ lsusb | grep NXP -Bus 003 Device 013: ID 1fc9:000c NXP Semiconductors - -$ dfu-util -D ~/devel/dfu-util/firmware.bin.qthdr - -dfu-util 0.7 - -Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc. -Copyright 2010-2012 Tormod Volden and Stefan Schmidt -This program is Free Software and has ABSOLUTELY NO WARRANTY -Please report bugs to dfu-util@lists.gnumonks.org - -dfu-util: Invalid DFU suffix signature -dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! -Possible unencryptes NXP LPC DFU prefix with the following properties -Payload length: 39 kiByte -Opening DFU capable USB device... -ID 1fc9:000c -Run-time device DFU version 0100 -Claiming USB DFU Runtime Interface... -Determining device status: -state = dfuIDLE, status = 0 -dfu-util: WARNING: Runtime device already in DFU state ?!? -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: -state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 0100 -Device returned transfer size 2048 -Copying data from PC to DFU device -Download [ ] 0% 0 bytes -Download [= ] 4% 2048 bytes -Download [== ] 9% 4096 bytes -Download [=== ] 14% 6144 bytes -Download [==== ] 19% 8192 bytes -Download [====== ] 24% 10240 bytes -Download [======= ] 28% 12288 bytes -Download [======== ] 33% 14336 bytes -Download [========= ] 38% 16384 bytes -Download [========== ] 43% 18432 bytes -Download [============ ] 48% 20480 bytes -Download [============= ] 53% 22528 bytes -Download [============== ] 57% 24576 bytes -Download [=============== ] 62% 26624 bytes -Download [================ ] 67% 28672 bytes -Download [================== ] 72% 30720 bytes -Download [=================== ] 77% 32768 bytes -Download [==================== ] 82% 34816 bytes -Download [===================== ] 86% 36864 bytes -Download [====================== ] 91% 38912 bytes -Download [======================== ] 96% 40356 bytes -Download [=========================] 100% 40356 bytes -Download done. -Sent a total of 40356 bytes -dfu-util: unable to read DFU status - -$ lsusb | grep NXP -Bus 003 Device 014: ID 1fc9:0018 NXP Semiconductors diff --git a/linux/src/dfu-util/device-logs/lpclink2.lsusb b/linux/src/dfu-util/device-logs/lpclink2.lsusb deleted file mode 100644 index b833fca77..000000000 --- a/linux/src/dfu-util/device-logs/lpclink2.lsusb +++ /dev/null @@ -1,203 +0,0 @@ - -Bus 003 Device 007: ID 0c72:000c PEAK System PCAN-USB -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x0c72 PEAK System - idProduct 0x000c PCAN-USB - bcdDevice 1c.ff - iManufacturer 0 - iProduct 3 VER1:PEAK -VER2:02.8.01 -DAT :06.05.2004 -TIME:09:35:37 - ... - iSerial 0 - bNumConfigurations 3 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 46 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 4 - bInterfaceClass 0 (Defined at Interface level) - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x01 EP 1 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 46 - bNumInterfaces 1 - bConfigurationValue 2 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 394mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 4 - bInterfaceClass 0 (Defined at Interface level) - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x01 EP 1 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 46 - bNumInterfaces 1 - bConfigurationValue 3 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 4 - bInterfaceClass 0 (Defined at Interface level) - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x01 EP 1 OUT - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 -Device Status: 0x0001 - Self Powered diff --git a/linux/src/dfu-util/device-logs/opc-20.lsusb b/linux/src/dfu-util/device-logs/opc-20.lsusb deleted file mode 100644 index 580df90e5..000000000 --- a/linux/src/dfu-util/device-logs/opc-20.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 001 Device 004: ID 0483:df11 SGS Thomson Microelectronics -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 - bcdDevice 2.00 - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 DFU - iSerial 3 ������������ - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/12*001Ka,116*001Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @SPI Flash : M25P64/0x00000000/128*64Kg - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 1024 bytes - bcdDFUVersion 1a.01 -Device Status: 0x0001 - Self Powered diff --git a/linux/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb b/linux/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb deleted file mode 100644 index 4c0abfb06..000000000 --- a/linux/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb +++ /dev/null @@ -1,109 +0,0 @@ -Bus 003 Device 017: ID 1d50:5119 OpenMoko, Inc. GTA01/GTA02 U-Boot Bootloader -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x1d50 OpenMoko, Inc. - idProduct 0x5119 GTA01/GTA02 U-Boot Bootloader - bcdDevice 0.00 - iManufacturer 1 OpenMoko, Inc - iProduct 2 Neo1973 Bootloader U-Boot 1.3.2-moko12 - iSerial 3 0000000 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 81 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 7 USB Device Firmware Upgrade - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 8 RAM 0x32000000 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 9 u-boot - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 2 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 10 u-boot_env - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 3 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 11 kernel - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 4 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 12 splash - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 5 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 13 factory - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 6 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 14 rootfs - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 4096 bytes - bcdDFUVersion 1.00 -Device Status: 0x0a00 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/openmoko-freerunner.lsusb b/linux/src/dfu-util/device-logs/openmoko-freerunner.lsusb deleted file mode 100644 index 835708dd8..000000000 --- a/linux/src/dfu-util/device-logs/openmoko-freerunner.lsusb +++ /dev/null @@ -1,179 +0,0 @@ -Bus 005 Device 033: ID 1d50:5119 OpenMoko, Inc. GTA01/GTA02 U-Boot Bootloader -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.10 - bDeviceClass 2 Communications - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x1d50 OpenMoko, Inc. - idProduct 0x5119 GTA01/GTA02 U-Boot Bootloader - bcdDevice 0.00 - iManufacturer 1 OpenMoko, Inc - iProduct 2 Neo1973 Bootloader U-Boot 1.3.2-moko12 - iSerial 3 0000000 - bNumConfigurations 2 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 85 - bNumInterfaces 3 - bConfigurationValue 1 - iConfiguration 4 TTY via USB - bmAttributes 0x80 - (Bus Powered) - MaxPower 500mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 Control Interface - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 Bulk Data Interface - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 2 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 1 - iInterface 7 USB Device Firmware Upgrade - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 4096 bytes - bcdDFUVersion 1.00 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 67 - bNumInterfaces 2 - bConfigurationValue 2 - iConfiguration 4 TTY via USB - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 Control Interface - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 Bulk Data Interface - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 -Device Status: 0x9a00 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/openmoko-neo1973.lsusb b/linux/src/dfu-util/device-logs/openmoko-neo1973.lsusb deleted file mode 100644 index 07789506a..000000000 --- a/linux/src/dfu-util/device-logs/openmoko-neo1973.lsusb +++ /dev/null @@ -1,182 +0,0 @@ - -Bus 006 Device 020: ID 1457:5119 First International Computer, Inc. OpenMoko Neo1973 u-boot cdc_acm serial port -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.10 - bDeviceClass 2 Communications - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x1457 First International Computer, Inc. - idProduct 0x5119 OpenMoko Neo1973 u-boot cdc_acm serial port - bcdDevice 0.00 - iManufacturer 1 - iProduct 2 - iSerial 3 - bNumConfigurations 2 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 85 - bNumInterfaces 3 - bConfigurationValue 1 - iConfiguration 4 - bmAttributes 0x80 - (Bus Powered) - MaxPower 500mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 2 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 1 - iInterface 7 - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 4096 bytes - bcdDFUVersion 1.00 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 67 - bNumInterfaces 2 - bConfigurationValue 2 - iConfiguration 4 - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 -Device Status: 0x0006 - (Bus Powered) - Remote Wakeup Enabled - Test Mode diff --git a/linux/src/dfu-util/device-logs/openpcd.lsusb b/linux/src/dfu-util/device-logs/openpcd.lsusb deleted file mode 100644 index f6255a943..000000000 --- a/linux/src/dfu-util/device-logs/openpcd.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 006 Device 016: ID 16c0:076b VOTI OpenPCD 13.56MHz RFID Reader -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 8 - idVendor 0x16c0 VOTI - idProduct 0x076b OpenPCD 13.56MHz RFID Reader - bcdDevice 0.00 - iManufacturer 1 - iProduct 2 OpenPCD RFID Simulator - DFU Mode - iSerial 0 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 0 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 0 - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 3 - Will Not Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 256 bytes - bcdDFUVersion 1.00 -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/qi-hardware-atusb.lsusb b/linux/src/dfu-util/device-logs/qi-hardware-atusb.lsusb deleted file mode 100644 index bfc1701e1..000000000 --- a/linux/src/dfu-util/device-logs/qi-hardware-atusb.lsusb +++ /dev/null @@ -1,59 +0,0 @@ - -Bus 006 Device 013: ID 20b7:1540 Qi Hardware ben-wpan, AT86RF230-based -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 255 Vendor Specific Class - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x20b7 Qi Hardware - idProduct 0x1540 ben-wpan, AT86RF230-based - bcdDevice 0.01 - iManufacturer 0 - iProduct 0 - iSerial 1 4630333438371508231a - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 34 - bNumInterfaces 2 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 40mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 255 Vendor Specific Class - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 0 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 1 - iInterface 0 -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/simtrace.lsusb b/linux/src/dfu-util/device-logs/simtrace.lsusb deleted file mode 100644 index 578ddf0e1..000000000 --- a/linux/src/dfu-util/device-logs/simtrace.lsusb +++ /dev/null @@ -1,70 +0,0 @@ - -Bus 006 Device 017: ID 16c0:0762 VOTI -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 8 - idVendor 0x16c0 VOTI - idProduct 0x0762 - bcdDevice 0.00 - iManufacturer 1 sysmocom - systems for mobile communications GmbH - iProduct 2 SimTrace SIM Sniffer - DFU Mode - iSerial 0 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 45 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 3 SimTrace DFU Configuration - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 SimTrace DFU Interface - Application Partition - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 SimTrace DFU Interface - Bootloader Partition - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 2 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 6 SimTrace DFU Interface - RAM - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 3 - Will Not Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 256 bytes - bcdDFUVersion 1.00 -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/sparkcore.lsusb b/linux/src/dfu-util/device-logs/sparkcore.lsusb deleted file mode 100644 index b6029ffa5..000000000 --- a/linux/src/dfu-util/device-logs/sparkcore.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 001 Device 008: ID 1d50:607f OpenMoko, Inc. -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x1d50 OpenMoko, Inc. - idProduct 0x607f - bcdDevice 2.00 - iManufacturer 1 Spark Devices - iProduct 2 CORE DFU - iSerial 3 8D80527B5055 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/20*001Ka,108*001Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @SPI Flash : SST25x/0x00000000/512*04Kg - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 1024 bytes - bcdDFUVersion 1.1a -Device Status: 0x0001 - Self Powered diff --git a/linux/src/dfu-util/device-logs/stm32f107.bin-download b/linux/src/dfu-util/device-logs/stm32f107.bin-download deleted file mode 100644 index 45b714f83..000000000 --- a/linux/src/dfu-util/device-logs/stm32f107.bin-download +++ /dev/null @@ -1,48 +0,0 @@ -> src/dfu-util --intf 0 --alt 0 -v -v -v -s 0x8000000 -D test3 -dfu-util 0.4 - -(C) 2005-2008 by Weston Schmidt, Harald Welte and OpenMoko Inc. -(C) 2010-2011 Tormod Volden (DfuSe support) -This program is Free Software and has ABSOLUTELY NO WARRANTY - -dfu-util does currently only support DFU version 1.0 - -Opening DFU USB device... ID 0483:df11 -Run-time device DFU version 011a -Found DFU: [0483:df11] devnum=0, cfg=1, intf=0, alt=0, name="@Internal Flash /0x08000000/128*002Kg" -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 011a -Device returned transfer size 2048 -No valid DFU suffix signature -Warning: File has no DFU suffix -DfuSe interface name: "Internal Flash " -Memory segment at 0x08000000 128 x 2048 = 262144 (rew) -Uploading to address = 0x08000000, size = 16384 -Erasing page size 2048 at address 0x08000000, page starting at 0x08000000 - Download from image offset 00000000 to memory 08000000-080007ff, size 2048 - Setting address pointer to 0x08000000 -Erasing page size 2048 at address 0x08000800, page starting at 0x08000800 - Download from image offset 00000800 to memory 08000800-08000fff, size 2048 - Setting address pointer to 0x08000800 -Erasing page size 2048 at address 0x08001000, page starting at 0x08001000 - Download from image offset 00001000 to memory 08001000-080017ff, size 2048 - Setting address pointer to 0x08001000 -Erasing page size 2048 at address 0x08001800, page starting at 0x08001800 - Download from image offset 00001800 to memory 08001800-08001fff, size 2048 - Setting address pointer to 0x08001800 -Erasing page size 2048 at address 0x08002000, page starting at 0x08002000 - Download from image offset 00002000 to memory 08002000-080027ff, size 2048 - Setting address pointer to 0x08002000 -Erasing page size 2048 at address 0x08002800, page starting at 0x08002800 - Download from image offset 00002800 to memory 08002800-08002fff, size 2048 - Setting address pointer to 0x08002800 -Erasing page size 2048 at address 0x08003000, page starting at 0x08003000 - Download from image offset 00003000 to memory 08003000-080037ff, size 2048 - Setting address pointer to 0x08003000 -Erasing page size 2048 at address 0x08003800, page starting at 0x08003800 - Download from image offset 00003800 to memory 08003800-08003fff, size 2048 - Setting address pointer to 0x08003800 - diff --git a/linux/src/dfu-util/device-logs/stm32f107.lsusb b/linux/src/dfu-util/device-logs/stm32f107.lsusb deleted file mode 100644 index 14b45cda0..000000000 --- a/linux/src/dfu-util/device-logs/stm32f107.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 001 Device 028: ID 0483:df11 SGS Thomson Microelectronics STM Device in DFU Mode -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 STM Device in DFU Mode - bcdDevice 20.00 - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 0x418 DFU Bootloader - iSerial 3 STM32 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/128*002Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @Option Bytes /0x1FFFF800/01*016 g - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 2048 bytes - bcdDFUVersion 1.1a -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/device-logs/stm32f4discovery.bin-download b/linux/src/dfu-util/device-logs/stm32f4discovery.bin-download deleted file mode 100644 index 96e172216..000000000 --- a/linux/src/dfu-util/device-logs/stm32f4discovery.bin-download +++ /dev/null @@ -1,36 +0,0 @@ -dfu-util --device 0483:df11 --alt 0 \ - --dfuse-address 0x08000000 \ - -v -v -v \ - --download arm/iotoggle.bin -No valid DFU suffix signature -Warning: File has no DFU suffix -dfu-util 0.5 - -(C) 2005-2008 by Weston Schmidt, Harald Welte and OpenMoko Inc. -(C) 2010-2011 Tormod Volden (DfuSe support) -This program is Free Software and has ABSOLUTELY NO WARRANTY - -dfu-util does currently only support DFU version 1.0 - -Filter on vendor = 0x0483 product = 0xdf11 -Opening DFU capable USB device... ID 0483:df11 -Run-time device DFU version 011a -Found DFU: [0483:df11] devnum=0, cfg=1, intf=0, alt=0, name="@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: state = dfuERROR, status = 10 -dfuERROR, clearing status -Determining device status: state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 011a -Device returned transfer size 2048 -DfuSe interface name: "Internal Flash " -Memory segment at 0x08000000 4 x 16384 = 65536 (rew) -Memory segment at 0x08010000 1 x 65536 = 65536 (rew) -Memory segment at 0x08020000 7 x 131072 = 917504 (rew) -Uploading to address = 0x08000000, size = 2308 -Erasing page size 16384 at address 0x08000000, page starting at 0x08000000 - Download from image offset 00000000 to memory 08000000-080007ff, size 2048 - Setting address pointer to 0x08000000 - Download from image offset 00000800 to memory 08000800-08000903, size 260 - Setting address pointer to 0x08000800 diff --git a/linux/src/dfu-util/device-logs/stm32f4discovery.lsusb b/linux/src/dfu-util/device-logs/stm32f4discovery.lsusb deleted file mode 100644 index 0b870de91..000000000 --- a/linux/src/dfu-util/device-logs/stm32f4discovery.lsusb +++ /dev/null @@ -1,80 +0,0 @@ - -Bus 001 Device 010: ID 0483:df11 SGS Thomson Microelectronics STM Device in DFU Mode -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 STM Device in DFU Mode - bcdDevice 21.00 - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 BOOTLOADER - iSerial 3 315A28A0B956 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 54 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @Option Bytes /0x1FFFC000/01*016 g - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 2 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 6 @OTP Memory /0x1FFF7800/01*512 g,01*016 g - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 3 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 7 @Device Feature/0xFFFF0000/01*004 g - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 2048 bytes - bcdDFUVersion 1.1a -Device Status: 0x0001 - Self Powered diff --git a/linux/src/dfu-util/device-logs/tdk-bluetooth.lsusb b/linux/src/dfu-util/device-logs/tdk-bluetooth.lsusb deleted file mode 100644 index c0cfaceb6..000000000 --- a/linux/src/dfu-util/device-logs/tdk-bluetooth.lsusb +++ /dev/null @@ -1,269 +0,0 @@ - -Bus 006 Device 014: ID 04bf:0320 TDK Corp. Bluetooth Adapter -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 224 Wireless - bDeviceSubClass 1 Radio Frequency - bDeviceProtocol 1 Bluetooth - bMaxPacketSize0 64 - idVendor 0x04bf TDK Corp. - idProduct 0x0320 Bluetooth Adapter - bcdDevice 26.52 - iManufacturer 1 Ezurio - iProduct 2 Turbo Bluetooth Adapter - iSerial 3 008098D4FFBD - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 193 - bNumInterfaces 3 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 64mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 3 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0000 1x 0 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0000 1x 0 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 1 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0009 1x 9 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0009 1x 9 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 2 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0011 1x 17 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0011 1x 17 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 3 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0019 1x 25 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0019 1x 25 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 4 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0021 1x 33 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0021 1x 33 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 5 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0031 1x 49 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0031 1x 49 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 2 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 0 - Device Firmware Upgrade Interface Descriptor: - bLength 7 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 5000 milliseconds - wTransferSize 1023 bytes -Device Status: 0x0000 - (Bus Powered) diff --git a/linux/src/dfu-util/dfuse-pack.py b/linux/src/dfu-util/dfuse-pack.py deleted file mode 100644 index 875cc5c6e..000000000 --- a/linux/src/dfu-util/dfuse-pack.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/python - -# Written by Antonio Galea - 2010/11/18 -# Distributed under Gnu LGPL 3.0 -# see http://www.gnu.org/licenses/lgpl-3.0.txt - -import sys,struct,zlib,os -from optparse import OptionParser - -DEFAULT_DEVICE="0x0483:0xdf11" - -def named(tuple,names): - return dict(zip(names.split(),tuple)) -def consume(fmt,data,names): - n = struct.calcsize(fmt) - return named(struct.unpack(fmt,data[:n]),names),data[n:] -def cstring(string): - return string.split('\0',1)[0] -def compute_crc(data): - return 0xFFFFFFFF & -zlib.crc32(data) -1 - -def parse(file,dump_images=False): - print 'File: "%s"' % file - data = open(file,'rb').read() - crc = compute_crc(data[:-4]) - prefix, data = consume('<5sBIB',data,'signature version size targets') - print '%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix - for t in range(prefix['targets']): - tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') - tprefix['num'] = t - if tprefix['named']: - tprefix['name'] = cstring(tprefix['name']) - else: - tprefix['name'] = '' - print '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix - tsize = tprefix['size'] - target, data = data[:tsize], data[tsize:] - for e in range(tprefix['elements']): - eprefix, target = consume('<2I',target,'address size') - eprefix['num'] = e - print ' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix - esize = eprefix['size'] - image, target = target[:esize], target[esize:] - if dump_images: - out = '%s.target%d.image%d.bin' % (file,t,e) - open(out,'wb').write(image) - print ' DUMPED IMAGE TO "%s"' % out - if len(target): - print "target %d: PARSE ERROR" % t - suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') - print 'usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix - if crc != suffix['crc']: - print "CRC ERROR: computed crc32 is 0x%08x" % crc - data = data[16:] - if data: - print "PARSE ERROR" - -def build(file,targets,device=DEFAULT_DEVICE): - data = '' - for t,target in enumerate(targets): - tdata = '' - for image in target: - tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] - tdata = struct.pack('<6sBI255s2I','Target',0,1,'ST...',len(tdata),len(target)) + tdata - data += tdata - data = struct.pack('<5sBIB','DfuSe',1,len(data)+11,len(targets)) + data - v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) - data += struct.pack('<4H3sB',0,d,v,0x011a,'UFD',16) - crc = compute_crc(data) - data += struct.pack(' and -Harald Welte . Over time, nearly complete -support of DFU 1.0, DFU 1.1 and DfuSe ("1.1a") has been added. -.SH LICENCE -.B dfu-util -is covered by the GNU General Public License (GPL), version 2 or later. -.SH COPYRIGHT -This manual page was originally written by Uwe Hermann , -and is now part of the dfu-util project. diff --git a/linux/src/dfu-util/msvc/README_msvc.txt b/linux/src/dfu-util/msvc/README_msvc.txt deleted file mode 100644 index 6e68ec6ff..000000000 --- a/linux/src/dfu-util/msvc/README_msvc.txt +++ /dev/null @@ -1,10 +0,0 @@ -# (C) Roger Meier -# (C) Pascal Schweizer -# msvc folder is GPL-2.0+, LGPL-2.1+, BSD-3-Clause or MIT license(SPDX) - -Building dfu-util native on Windows with Visual Studio - -3rd party dependencies: -- libusbx ( git clone https://github.com/libusbx/libusbx.git ) - - getopt (part of libusbx: libusbx/examples/getopt) - diff --git a/linux/src/dfu-util/msvc/dfu-suffix_2010.vcxproj b/linux/src/dfu-util/msvc/dfu-suffix_2010.vcxproj deleted file mode 100644 index 0c316c2e5..000000000 --- a/linux/src/dfu-util/msvc/dfu-suffix_2010.vcxproj +++ /dev/null @@ -1,100 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA} - dfusuffix - dfu-suffix - - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\dll;$(LibraryPath) - $(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib - $(ExecutablePath) - - - $(ExecutablePath) - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\dll;$(LibraryPath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - - - Level3 - MaxSpeed - true - true - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - - - - - - - - - - - {a2169bc8-cf99-40bf-83f3-b0e38f7067bd} - - - {349ee8f9-7d25-4909-aaf5-ff3fade72187} - - - - - - \ No newline at end of file diff --git a/linux/src/dfu-util/msvc/dfu-util_2010.sln b/linux/src/dfu-util/msvc/dfu-util_2010.sln deleted file mode 100644 index ef797239b..000000000 --- a/linux/src/dfu-util/msvc/dfu-util_2010.sln +++ /dev/null @@ -1,54 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfu-util", "dfu-util_2010.vcxproj", "{0E071A60-7EF2-4427-BAA8-9143CACB5BCB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C4F8746D-B27E-4806-95E5-2052174E923B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfu-suffix", "dfu-suffix_2010.vcxproj", "{8F7600A2-3B37-4956-B39B-A1D43EF29EDA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt_2010", "..\..\libusbx\msvc\getopt_2010.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "..\..\libusbx\msvc\libusb_static_2010.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|Win32.ActiveCfg = Debug|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|Win32.Build.0 = Debug|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|x64.ActiveCfg = Debug|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|Win32.ActiveCfg = Release|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|Win32.Build.0 = Release|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|x64.ActiveCfg = Release|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|Win32.ActiveCfg = Debug|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|Win32.Build.0 = Debug|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|x64.ActiveCfg = Debug|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|Win32.ActiveCfg = Release|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|Win32.Build.0 = Release|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|x64.ActiveCfg = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.ActiveCfg = Debug|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.Build.0 = Debug|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.ActiveCfg = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.Build.0 = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/linux/src/dfu-util/msvc/dfu-util_2010.vcxproj b/linux/src/dfu-util/msvc/dfu-util_2010.vcxproj deleted file mode 100644 index 17a8bee1b..000000000 --- a/linux/src/dfu-util/msvc/dfu-util_2010.vcxproj +++ /dev/null @@ -1,120 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB} - dfuutil - dfu-util - - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\getopt\$(Configuration);$(LibraryPath) - $(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib - $(ExecutablePath) - - - $(ExecutablePath) - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\getopt\$(Configuration);$(LibraryPath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - - - - - - - Level3 - MaxSpeed - true - true - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - copy $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0.dll $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - - - - - - - - - - - - - - - - - - - - - - - - - - {a2169bc8-cf99-40bf-83f3-b0e38f7067bd} - - - {349ee8f9-7d25-4909-aaf5-ff3fade72187} - - - - - - \ No newline at end of file diff --git a/linux/src/dfu-util/src/Makefile.am b/linux/src/dfu-util/src/Makefile.am deleted file mode 100644 index 70179c411..000000000 --- a/linux/src/dfu-util/src/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -AM_CFLAGS = -Wall -Wextra - -bin_PROGRAMS = dfu-util dfu-suffix dfu-prefix -dfu_util_SOURCES = main.c \ - portable.h \ - dfu_load.c \ - dfu_load.h \ - dfu_util.c \ - dfu_util.h \ - dfuse.c \ - dfuse.h \ - dfuse_mem.c \ - dfuse_mem.h \ - dfu.c \ - dfu.h \ - usb_dfu.h \ - dfu_file.c \ - dfu_file.h \ - quirks.c \ - quirks.h - -dfu_suffix_SOURCES = suffix.c \ - dfu_file.h \ - dfu_file.c - -dfu_prefix_SOURCES = prefix.c \ - dfu_file.h \ - dfu_file.c diff --git a/linux/src/dfu-util/src/dfu.c b/linux/src/dfu-util/src/dfu.c deleted file mode 100644 index 14d7673d1..000000000 --- a/linux/src/dfu-util/src/dfu.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Low-level DFU communication routines, originally taken from - * $Id: dfu.c,v 1.3 2006/06/20 06:28:04 schmidtw Exp $ - * (part of dfu-programmer). - * - * Copyright 2005-2006 Weston Schmidt - * Copyright 2011-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include - -#include "portable.h" -#include "dfu.h" -#include "quirks.h" - -static int dfu_timeout = 5000; /* 5 seconds - default */ - -/* - * DFU_DETACH Request (DFU Spec 1.0, Section 5.1) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * timeout - the timeout in ms the USB device should wait for a pending - * USB reset before giving up and terminating the operation - * - * returns 0 or < 0 on error - */ -int dfu_detach( libusb_device_handle *device, - const unsigned short interface, - const unsigned short timeout ) -{ - return libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_DETACH, - /* wValue */ timeout, - /* wIndex */ interface, - /* Data */ NULL, - /* wLength */ 0, - dfu_timeout ); -} - - -/* - * DFU_DNLOAD Request (DFU Spec 1.0, Section 6.1.1) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * length - the total number of bytes to transfer to the USB - * device - must be less than wTransferSize - * data - the data to transfer - * - * returns the number of bytes written or < 0 on error - */ -int dfu_download( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ) -{ - int status; - - status = libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_DNLOAD, - /* wValue */ transaction, - /* wIndex */ interface, - /* Data */ data, - /* wLength */ length, - dfu_timeout ); - return status; -} - - -/* - * DFU_UPLOAD Request (DFU Spec 1.0, Section 6.2) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * length - the maximum number of bytes to receive from the USB - * device - must be less than wTransferSize - * data - the buffer to put the received data in - * - * returns the number of bytes received or < 0 on error - */ -int dfu_upload( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ) -{ - int status; - - status = libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_UPLOAD, - /* wValue */ transaction, - /* wIndex */ interface, - /* Data */ data, - /* wLength */ length, - dfu_timeout ); - return status; -} - - -/* - * DFU_GETSTATUS Request (DFU Spec 1.0, Section 6.1.2) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * status - the data structure to be populated with the results - * - * return the number of bytes read in or < 0 on an error - */ -int dfu_get_status( struct dfu_if *dif, struct dfu_status *status ) -{ - unsigned char buffer[6]; - int result; - - /* Initialize the status data structure */ - status->bStatus = DFU_STATUS_ERROR_UNKNOWN; - status->bwPollTimeout = 0; - status->bState = STATE_DFU_ERROR; - status->iString = 0; - - result = libusb_control_transfer( dif->dev_handle, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_GETSTATUS, - /* wValue */ 0, - /* wIndex */ dif->interface, - /* Data */ buffer, - /* wLength */ 6, - dfu_timeout ); - - if( 6 == result ) { - status->bStatus = buffer[0]; - if (dif->quirks & QUIRK_POLLTIMEOUT) - status->bwPollTimeout = DEFAULT_POLLTIMEOUT; - else - status->bwPollTimeout = ((0xff & buffer[3]) << 16) | - ((0xff & buffer[2]) << 8) | - (0xff & buffer[1]); - status->bState = buffer[4]; - status->iString = buffer[5]; - } - - return result; -} - - -/* - * DFU_CLRSTATUS Request (DFU Spec 1.0, Section 6.1.3) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * - * return 0 or < 0 on an error - */ -int dfu_clear_status( libusb_device_handle *device, - const unsigned short interface ) -{ - return libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT| LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_CLRSTATUS, - /* wValue */ 0, - /* wIndex */ interface, - /* Data */ NULL, - /* wLength */ 0, - dfu_timeout ); -} - - -/* - * DFU_GETSTATE Request (DFU Spec 1.0, Section 6.1.5) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * length - the maximum number of bytes to receive from the USB - * device - must be less than wTransferSize - * data - the buffer to put the received data in - * - * returns the state or < 0 on error - */ -int dfu_get_state( libusb_device_handle *device, - const unsigned short interface ) -{ - int result; - unsigned char buffer[1]; - - result = libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_GETSTATE, - /* wValue */ 0, - /* wIndex */ interface, - /* Data */ buffer, - /* wLength */ 1, - dfu_timeout ); - - /* Return the error if there is one. */ - if (result < 1) - return -1; - - /* Return the state. */ - return buffer[0]; -} - - -/* - * DFU_ABORT Request (DFU Spec 1.0, Section 6.1.4) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * - * returns 0 or < 0 on an error - */ -int dfu_abort( libusb_device_handle *device, - const unsigned short interface ) -{ - return libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_ABORT, - /* wValue */ 0, - /* wIndex */ interface, - /* Data */ NULL, - /* wLength */ 0, - dfu_timeout ); -} - - -const char* dfu_state_to_string( int state ) -{ - const char *message; - - switch (state) { - case STATE_APP_IDLE: - message = "appIDLE"; - break; - case STATE_APP_DETACH: - message = "appDETACH"; - break; - case STATE_DFU_IDLE: - message = "dfuIDLE"; - break; - case STATE_DFU_DOWNLOAD_SYNC: - message = "dfuDNLOAD-SYNC"; - break; - case STATE_DFU_DOWNLOAD_BUSY: - message = "dfuDNBUSY"; - break; - case STATE_DFU_DOWNLOAD_IDLE: - message = "dfuDNLOAD-IDLE"; - break; - case STATE_DFU_MANIFEST_SYNC: - message = "dfuMANIFEST-SYNC"; - break; - case STATE_DFU_MANIFEST: - message = "dfuMANIFEST"; - break; - case STATE_DFU_MANIFEST_WAIT_RESET: - message = "dfuMANIFEST-WAIT-RESET"; - break; - case STATE_DFU_UPLOAD_IDLE: - message = "dfuUPLOAD-IDLE"; - break; - case STATE_DFU_ERROR: - message = "dfuERROR"; - break; - default: - message = NULL; - break; - } - - return message; -} - -/* Chapter 6.1.2 */ -static const char *dfu_status_names[] = { - /* DFU_STATUS_OK */ - "No error condition is present", - /* DFU_STATUS_errTARGET */ - "File is not targeted for use by this device", - /* DFU_STATUS_errFILE */ - "File is for this device but fails some vendor-specific test", - /* DFU_STATUS_errWRITE */ - "Device is unable to write memory", - /* DFU_STATUS_errERASE */ - "Memory erase function failed", - /* DFU_STATUS_errCHECK_ERASED */ - "Memory erase check failed", - /* DFU_STATUS_errPROG */ - "Program memory function failed", - /* DFU_STATUS_errVERIFY */ - "Programmed memory failed verification", - /* DFU_STATUS_errADDRESS */ - "Cannot program memory due to received address that is out of range", - /* DFU_STATUS_errNOTDONE */ - "Received DFU_DNLOAD with wLength = 0, but device does not think that it has all data yet", - /* DFU_STATUS_errFIRMWARE */ - "Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations", - /* DFU_STATUS_errVENDOR */ - "iString indicates a vendor specific error", - /* DFU_STATUS_errUSBR */ - "Device detected unexpected USB reset signalling", - /* DFU_STATUS_errPOR */ - "Device detected unexpected power on reset", - /* DFU_STATUS_errUNKNOWN */ - "Something went wrong, but the device does not know what it was", - /* DFU_STATUS_errSTALLEDPKT */ - "Device stalled an unexpected request" -}; - - -const char *dfu_status_to_string(int status) -{ - if (status > DFU_STATUS_errSTALLEDPKT) - return "INVALID"; - return dfu_status_names[status]; -} - -int dfu_abort_to_idle(struct dfu_if *dif) -{ - int ret; - struct dfu_status dst; - - ret = dfu_abort(dif->dev_handle, dif->interface); - if (ret < 0) { - errx(EX_IOERR, "Error sending dfu abort request"); - exit(1); - } - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during abort get_status"); - exit(1); - } - if (dst.bState != DFU_STATE_dfuIDLE) { - errx(EX_IOERR, "Failed to enter idle state on abort"); - exit(1); - } - milli_sleep(dst.bwPollTimeout); - return ret; -} diff --git a/linux/src/dfu-util/src/dfu.h b/linux/src/dfu-util/src/dfu.h deleted file mode 100644 index 8e3caeb7b..000000000 --- a/linux/src/dfu-util/src/dfu.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * dfu-programmer - * - * $Id: dfu.h,v 1.2 2005/09/25 01:27:42 schmidtw Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DFU_H -#define DFU_H - -#include -#include "usb_dfu.h" - -/* DFU states */ -#define STATE_APP_IDLE 0x00 -#define STATE_APP_DETACH 0x01 -#define STATE_DFU_IDLE 0x02 -#define STATE_DFU_DOWNLOAD_SYNC 0x03 -#define STATE_DFU_DOWNLOAD_BUSY 0x04 -#define STATE_DFU_DOWNLOAD_IDLE 0x05 -#define STATE_DFU_MANIFEST_SYNC 0x06 -#define STATE_DFU_MANIFEST 0x07 -#define STATE_DFU_MANIFEST_WAIT_RESET 0x08 -#define STATE_DFU_UPLOAD_IDLE 0x09 -#define STATE_DFU_ERROR 0x0a - - -/* DFU status */ -#define DFU_STATUS_OK 0x00 -#define DFU_STATUS_ERROR_TARGET 0x01 -#define DFU_STATUS_ERROR_FILE 0x02 -#define DFU_STATUS_ERROR_WRITE 0x03 -#define DFU_STATUS_ERROR_ERASE 0x04 -#define DFU_STATUS_ERROR_CHECK_ERASED 0x05 -#define DFU_STATUS_ERROR_PROG 0x06 -#define DFU_STATUS_ERROR_VERIFY 0x07 -#define DFU_STATUS_ERROR_ADDRESS 0x08 -#define DFU_STATUS_ERROR_NOTDONE 0x09 -#define DFU_STATUS_ERROR_FIRMWARE 0x0a -#define DFU_STATUS_ERROR_VENDOR 0x0b -#define DFU_STATUS_ERROR_USBR 0x0c -#define DFU_STATUS_ERROR_POR 0x0d -#define DFU_STATUS_ERROR_UNKNOWN 0x0e -#define DFU_STATUS_ERROR_STALLEDPKT 0x0f - -/* DFU commands */ -#define DFU_DETACH 0 -#define DFU_DNLOAD 1 -#define DFU_UPLOAD 2 -#define DFU_GETSTATUS 3 -#define DFU_CLRSTATUS 4 -#define DFU_GETSTATE 5 -#define DFU_ABORT 6 - -/* DFU interface */ -#define DFU_IFF_DFU 0x0001 /* DFU Mode, (not Runtime) */ - -/* This is based off of DFU_GETSTATUS - * - * 1 unsigned byte bStatus - * 3 unsigned byte bwPollTimeout - * 1 unsigned byte bState - * 1 unsigned byte iString -*/ - -struct dfu_status { - unsigned char bStatus; - unsigned int bwPollTimeout; - unsigned char bState; - unsigned char iString; -}; - -struct dfu_if { - struct usb_dfu_func_descriptor func_dfu; - uint16_t quirks; - uint16_t busnum; - uint16_t devnum; - uint16_t vendor; - uint16_t product; - uint16_t bcdDevice; - uint8_t configuration; - uint8_t interface; - uint8_t altsetting; - uint8_t flags; - uint8_t bMaxPacketSize0; - char *alt_name; - char *serial_name; - libusb_device *dev; - libusb_device_handle *dev_handle; - struct dfu_if *next; -}; - -int dfu_detach( libusb_device_handle *device, - const unsigned short interface, - const unsigned short timeout ); -int dfu_download( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ); -int dfu_upload( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ); -int dfu_get_status( struct dfu_if *dif, - struct dfu_status *status ); -int dfu_clear_status( libusb_device_handle *device, - const unsigned short interface ); -int dfu_get_state( libusb_device_handle *device, - const unsigned short interface ); -int dfu_abort( libusb_device_handle *device, - const unsigned short interface ); -int dfu_abort_to_idle( struct dfu_if *dif); - -const char *dfu_state_to_string( int state ); - -const char *dfu_status_to_string( int status ); - -#endif /* DFU_H */ diff --git a/linux/src/dfu-util/src/dfu_file.c b/linux/src/dfu-util/src/dfu_file.c deleted file mode 100644 index 7c897d4f6..000000000 --- a/linux/src/dfu-util/src/dfu_file.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Load or store DFU files including suffix and prefix - * - * Copyright 2014 Tormod Volden - * Copyright 2012 Stefan Schmidt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" - -#define DFU_SUFFIX_LENGTH 16 -#define LMDFU_PREFIX_LENGTH 8 -#define LPCDFU_PREFIX_LENGTH 16 -#define PROGRESS_BAR_WIDTH 25 -#define STDIN_CHUNK_SIZE 65536 - -static const unsigned long crc32_table[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; - -static uint32_t crc32_byte(uint32_t accum, uint8_t delta) -{ - return crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8); -} - -static int probe_prefix(struct dfu_file *file) -{ - uint8_t *prefix = file->firmware; - - if (file->size.total < LMDFU_PREFIX_LENGTH) - return 1; - if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) { - file->prefix_type = LMDFU_PREFIX; - file->size.prefix = LMDFU_PREFIX_LENGTH; - file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]); - } - else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f)== 0x3f)) { - file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX; - file->size.prefix = LPCDFU_PREFIX_LENGTH; - } - - if (file->size.prefix + file->size.suffix > file->size.total) - return 1; - return 0; -} - -void dfu_progress_bar(const char *desc, unsigned long long curr, - unsigned long long max) -{ - static char buf[PROGRESS_BAR_WIDTH + 1]; - static unsigned long long last_progress = -1; - static time_t last_time; - time_t curr_time = time(NULL); - unsigned long long progress; - unsigned long long x; - - /* check for not known maximum */ - if (max < curr) - max = curr + 1; - /* make none out of none give zero */ - if (max == 0 && curr == 0) - max = 1; - - /* compute completion */ - progress = (PROGRESS_BAR_WIDTH * curr) / max; - if (progress > PROGRESS_BAR_WIDTH) - progress = PROGRESS_BAR_WIDTH; - if (progress == last_progress && - curr_time == last_time) - return; - last_progress = progress; - last_time = curr_time; - - for (x = 0; x != PROGRESS_BAR_WIDTH; x++) { - if (x < progress) - buf[x] = '='; - else - buf[x] = ' '; - } - buf[x] = 0; - - printf("\r%s\t[%s] %3lld%% %12lld bytes", desc, buf, - (100ULL * curr) / max, curr); - - if (progress == PROGRESS_BAR_WIDTH) - printf("\n%s done.\n", desc); -} - -void *dfu_malloc(size_t size) -{ - void *ptr = malloc(size); - if (ptr == NULL) - errx(EX_SOFTWARE, "Cannot allocate memory of size %d bytes", (int)size); - return (ptr); -} - -uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size) -{ - int x; - - /* compute CRC */ - for (x = 0; x != size; x++) - crc = crc32_byte(crc, ((uint8_t *)buf)[x]); - - /* write data */ - if (write(f, buf, size) != size) - err(EX_IOERR, "Could not write %d bytes to file %d", size, f); - - return (crc); -} - -void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix) -{ - off_t offset; - int f; - int i; - int res; - - file->size.prefix = 0; - file->size.suffix = 0; - - /* default values, if no valid suffix is found */ - file->bcdDFU = 0; - file->idVendor = 0xffff; /* wildcard value */ - file->idProduct = 0xffff; /* wildcard value */ - file->bcdDevice = 0xffff; /* wildcard value */ - - /* default values, if no valid prefix is found */ - file->lmdfu_address = 0; - - free(file->firmware); - - if (!strcmp(file->name, "-")) { - int read_bytes; - -#ifdef WIN32 - _setmode( _fileno( stdin ), _O_BINARY ); -#endif - file->firmware = (uint8_t*) dfu_malloc(STDIN_CHUNK_SIZE); - read_bytes = fread(file->firmware, 1, STDIN_CHUNK_SIZE, stdin); - file->size.total = read_bytes; - while (read_bytes == STDIN_CHUNK_SIZE) { - file->firmware = (uint8_t*) realloc(file->firmware, file->size.total + STDIN_CHUNK_SIZE); - if (!file->firmware) - err(EX_IOERR, "Could not allocate firmware buffer"); - read_bytes = fread(file->firmware + file->size.total, 1, STDIN_CHUNK_SIZE, stdin); - file->size.total += read_bytes; - } - if (verbose) - printf("Read %i bytes from stdin\n", file->size.total); - /* Never require suffix when reading from stdin */ - check_suffix = MAYBE_SUFFIX; - } else { - f = open(file->name, O_RDONLY | O_BINARY); - if (f < 0) - err(EX_IOERR, "Could not open file %s for reading", file->name); - - offset = lseek(f, 0, SEEK_END); - - if ((int)offset < 0 || (int)offset != offset) - err(EX_IOERR, "File size is too big"); - - if (lseek(f, 0, SEEK_SET) != 0) - err(EX_IOERR, "Could not seek to beginning"); - - file->size.total = offset; - file->firmware = dfu_malloc(file->size.total); - - if (read(f, file->firmware, file->size.total) != file->size.total) { - err(EX_IOERR, "Could not read %d bytes from %s", - file->size.total, file->name); - } - close(f); - } - - /* Check for possible DFU file suffix by trying to parse one */ - { - uint32_t crc = 0xffffffff; - const uint8_t *dfusuffix; - int missing_suffix = 0; - const char *reason; - - if (file->size.total < DFU_SUFFIX_LENGTH) { - reason = "File too short for DFU suffix"; - missing_suffix = 1; - goto checked; - } - - dfusuffix = file->firmware + file->size.total - - DFU_SUFFIX_LENGTH; - - for (i = 0; i < file->size.total - 4; i++) - crc = crc32_byte(crc, file->firmware[i]); - - if (dfusuffix[10] != 'D' || - dfusuffix[9] != 'F' || - dfusuffix[8] != 'U') { - reason = "Invalid DFU suffix signature"; - missing_suffix = 1; - goto checked; - } - - file->dwCRC = (dfusuffix[15] << 24) + - (dfusuffix[14] << 16) + - (dfusuffix[13] << 8) + - dfusuffix[12]; - - if (file->dwCRC != crc) { - reason = "DFU suffix CRC does not match"; - missing_suffix = 1; - goto checked; - } - - /* At this point we believe we have a DFU suffix - so we require further checks to succeed */ - - file->bcdDFU = (dfusuffix[7] << 8) + dfusuffix[6]; - - if (verbose) - printf("DFU suffix version %x\n", file->bcdDFU); - - file->size.suffix = dfusuffix[11]; - - if (file->size.suffix < DFU_SUFFIX_LENGTH) { - errx(EX_IOERR, "Unsupported DFU suffix length %d", - file->size.suffix); - } - - if (file->size.suffix > file->size.total) { - errx(EX_IOERR, "Invalid DFU suffix length %d", - file->size.suffix); - } - - file->idVendor = (dfusuffix[5] << 8) + dfusuffix[4]; - file->idProduct = (dfusuffix[3] << 8) + dfusuffix[2]; - file->bcdDevice = (dfusuffix[1] << 8) + dfusuffix[0]; - -checked: - if (missing_suffix) { - if (check_suffix == NEEDS_SUFFIX) { - warnx("%s", reason); - errx(EX_IOERR, "Valid DFU suffix needed"); - } else if (check_suffix == MAYBE_SUFFIX) { - warnx("%s", reason); - warnx("A valid DFU suffix will be required in " - "a future dfu-util release!!!"); - } - } else { - if (check_suffix == NO_SUFFIX) { - errx(EX_SOFTWARE, "Please remove existing DFU suffix before adding a new one.\n"); - } - } - } - res = probe_prefix(file); - if ((res || file->size.prefix == 0) && check_prefix == NEEDS_PREFIX) - errx(EX_IOERR, "Valid DFU prefix needed"); - if (file->size.prefix && check_prefix == NO_PREFIX) - errx(EX_IOERR, "A prefix already exists, please delete it first"); - if (file->size.prefix && verbose) { - uint8_t *data = file->firmware; - if (file->prefix_type == LMDFU_PREFIX) - printf("Possible TI Stellaris DFU prefix with " - "the following properties\n" - "Address: 0x%08x\n" - "Payload length: %d\n", - file->lmdfu_address, - data[4] | (data[5] << 8) | - (data[6] << 16) | (data[7] << 14)); - else if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) - printf("Possible unencrypted NXP LPC DFU prefix with " - "the following properties\n" - "Payload length: %d kiByte\n", - data[2] >>1 | (data[3] << 7) ); - else - errx(EX_IOERR, "Unknown DFU prefix type"); - } -} - -void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix) -{ - uint32_t crc = 0xffffffff; - int f; - - f = open(file->name, O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, 0666); - if (f < 0) - err(EX_IOERR, "Could not open file %s for writing", file->name); - - /* write prefix, if any */ - if (write_prefix) { - if (file->prefix_type == LMDFU_PREFIX) { - uint8_t lmdfu_prefix[LMDFU_PREFIX_LENGTH]; - uint32_t addr = file->lmdfu_address / 1024; - - /* lmdfu_dfu_prefix payload length excludes prefix and suffix */ - uint32_t len = file->size.total - - file->size.prefix - file->size.suffix; - - lmdfu_prefix[0] = 0x01; /* STELLARIS_DFU_PROG */ - lmdfu_prefix[1] = 0x00; /* Reserved */ - lmdfu_prefix[2] = (uint8_t)(addr & 0xff); - lmdfu_prefix[3] = (uint8_t)(addr >> 8); - lmdfu_prefix[4] = (uint8_t)(len & 0xff); - lmdfu_prefix[5] = (uint8_t)(len >> 8) & 0xff; - lmdfu_prefix[6] = (uint8_t)(len >> 16) & 0xff; - lmdfu_prefix[7] = (uint8_t)(len >> 24); - - crc = dfu_file_write_crc(f, crc, lmdfu_prefix, LMDFU_PREFIX_LENGTH); - } - if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) { - uint8_t lpcdfu_prefix[LPCDFU_PREFIX_LENGTH] = {0}; - int i; - - /* Payload is firmware and prefix rounded to 512 bytes */ - uint32_t len = (file->size.total - file->size.suffix + 511) /512; - - lpcdfu_prefix[0] = 0x1a; /* Unencypted*/ - lpcdfu_prefix[1] = 0x3f; /* Reserved */ - lpcdfu_prefix[2] = (uint8_t)(len & 0xff); - lpcdfu_prefix[3] = (uint8_t)((len >> 8) & 0xff); - for (i = 12; i < LPCDFU_PREFIX_LENGTH; i++) - lpcdfu_prefix[i] = 0xff; - - crc = dfu_file_write_crc(f, crc, lpcdfu_prefix, LPCDFU_PREFIX_LENGTH); - } - } - /* write firmware binary */ - crc = dfu_file_write_crc(f, crc, file->firmware + file->size.prefix, - file->size.total - file->size.prefix - file->size.suffix); - - /* write suffix, if any */ - if (write_suffix) { - uint8_t dfusuffix[DFU_SUFFIX_LENGTH]; - - dfusuffix[0] = file->bcdDevice & 0xff; - dfusuffix[1] = file->bcdDevice >> 8; - dfusuffix[2] = file->idProduct & 0xff; - dfusuffix[3] = file->idProduct >> 8; - dfusuffix[4] = file->idVendor & 0xff; - dfusuffix[5] = file->idVendor >> 8; - dfusuffix[6] = file->bcdDFU & 0xff; - dfusuffix[7] = file->bcdDFU >> 8; - dfusuffix[8] = 'U'; - dfusuffix[9] = 'F'; - dfusuffix[10] = 'D'; - dfusuffix[11] = DFU_SUFFIX_LENGTH; - - crc = dfu_file_write_crc(f, crc, dfusuffix, - DFU_SUFFIX_LENGTH - 4); - - dfusuffix[12] = crc; - dfusuffix[13] = crc >> 8; - dfusuffix[14] = crc >> 16; - dfusuffix[15] = crc >> 24; - - crc = dfu_file_write_crc(f, crc, dfusuffix + 12, 4); - } - close(f); -} - -void show_suffix_and_prefix(struct dfu_file *file) -{ - if (file->size.prefix == LMDFU_PREFIX_LENGTH) { - printf("The file %s contains a TI Stellaris DFU prefix with the following properties:\n", file->name); - printf("Address:\t0x%08x\n", file->lmdfu_address); - } else if (file->size.prefix == LPCDFU_PREFIX_LENGTH) { - uint8_t * prefix = file->firmware; - printf("The file %s contains a NXP unencrypted LPC DFU prefix with the following properties:\n", file->name); - printf("Size:\t%5d kiB\n", prefix[2]>>1|prefix[3]<<7); - } else if (file->size.prefix != 0) { - printf("The file %s contains an unknown prefix\n", file->name); - } - if (file->size.suffix > 0) { - printf("The file %s contains a DFU suffix with the following properties:\n", file->name); - printf("BCD device:\t0x%04X\n", file->bcdDevice); - printf("Product ID:\t0x%04X\n",file->idProduct); - printf("Vendor ID:\t0x%04X\n", file->idVendor); - printf("BCD DFU:\t0x%04X\n", file->bcdDFU); - printf("Length:\t\t%i\n", file->size.suffix); - printf("CRC:\t\t0x%08X\n", file->dwCRC); - } -} diff --git a/linux/src/dfu-util/src/dfu_file.h b/linux/src/dfu-util/src/dfu_file.h deleted file mode 100644 index abebd44f4..000000000 --- a/linux/src/dfu-util/src/dfu_file.h +++ /dev/null @@ -1,60 +0,0 @@ - -#ifndef DFU_FILE_H -#define DFU_FILE_H - -#include - -struct dfu_file { - /* File name */ - const char *name; - /* Pointer to file loaded into memory */ - uint8_t *firmware; - /* Different sizes */ - struct { - int total; - int prefix; - int suffix; - } size; - /* From prefix fields */ - uint32_t lmdfu_address; - /* From prefix fields */ - uint32_t prefix_type; - - /* From DFU suffix fields */ - uint32_t dwCRC; - uint16_t bcdDFU; - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; -}; - -enum suffix_req { - NO_SUFFIX, - NEEDS_SUFFIX, - MAYBE_SUFFIX -}; - -enum prefix_req { - NO_PREFIX, - NEEDS_PREFIX, - MAYBE_PREFIX -}; - -enum prefix_type { - ZERO_PREFIX, - LMDFU_PREFIX, - LPCDFU_UNENCRYPTED_PREFIX -}; - -extern int verbose; - -void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix); -void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix); - -void dfu_progress_bar(const char *desc, unsigned long long curr, - unsigned long long max); -void *dfu_malloc(size_t size); -uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size); -void show_suffix_and_prefix(struct dfu_file *file); - -#endif /* DFU_FILE_H */ diff --git a/linux/src/dfu-util/src/dfu_load.c b/linux/src/dfu-util/src/dfu_load.c deleted file mode 100644 index 64f7009df..000000000 --- a/linux/src/dfu-util/src/dfu_load.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * DFU transfer routines - * - * This is supposed to be a general DFU implementation, as specified in the - * USB DFU 1.0 and 1.1 specification. - * - * The code was originally intended to interface with a USB device running the - * "sam7dfu" firmware (see http://www.openpcd.org/) on an AT91SAM7 processor. - * - * Copyright 2007-2008 Harald Welte - * Copyright 2013 Hans Petter Selasky - * Copyright 2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfu_load.h" -#include "quirks.h" - -int dfuload_do_upload(struct dfu_if *dif, int xfer_size, - int expected_size, int fd) -{ - int total_bytes = 0; - unsigned short transaction = 0; - unsigned char *buf; - int ret; - - buf = dfu_malloc(xfer_size); - - printf("Copying data from DFU device to PC\n"); - dfu_progress_bar("Upload", 0, 1); - - while (1) { - int rc; - rc = dfu_upload(dif->dev_handle, dif->interface, - xfer_size, transaction++, buf); - if (rc < 0) { - warnx("Error during upload"); - ret = rc; - goto out_free; - } - - dfu_file_write_crc(fd, 0, buf, rc); - total_bytes += rc; - - if (total_bytes < 0) - errx(EX_SOFTWARE, "Received too many bytes (wraparound)"); - - if (rc < xfer_size) { - /* last block, return */ - ret = total_bytes; - break; - } - dfu_progress_bar("Upload", total_bytes, expected_size); - } - ret = 0; - -out_free: - dfu_progress_bar("Upload", total_bytes, total_bytes); - if (total_bytes == 0) - printf("\nFailed.\n"); - free(buf); - if (verbose) - printf("Received a total of %i bytes\n", total_bytes); - if (expected_size != 0 && total_bytes != expected_size) - errx(EX_SOFTWARE, "Unexpected number of bytes uploaded from device"); - return ret; -} - -int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file) -{ - int bytes_sent; - int expected_size; - unsigned char *buf; - unsigned short transaction = 0; - struct dfu_status dst; - int ret; - - printf("Copying data from PC to DFU device\n"); - - buf = file->firmware; - expected_size = file->size.total - file->size.suffix; - bytes_sent = 0; - - dfu_progress_bar("Download", 0, 1); - while (bytes_sent < expected_size) { - int bytes_left; - int chunk_size; - - bytes_left = expected_size - bytes_sent; - if (bytes_left < xfer_size) - chunk_size = bytes_left; - else - chunk_size = xfer_size; - - ret = dfu_download(dif->dev_handle, dif->interface, - chunk_size, transaction++, chunk_size ? buf : NULL); - if (ret < 0) { - warnx("Error during download"); - goto out; - } - bytes_sent += chunk_size; - buf += chunk_size; - - do { - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during download get_status"); - goto out; - } - - if (dst.bState == DFU_STATE_dfuDNLOAD_IDLE || - dst.bState == DFU_STATE_dfuERROR) - break; - - /* Wait while device executes flashing */ - milli_sleep(dst.bwPollTimeout); - - } while (1); - if (dst.bStatus != DFU_STATUS_OK) { - printf(" failed!\n"); - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - ret = -1; - goto out; - } - dfu_progress_bar("Download", bytes_sent, bytes_sent + bytes_left); - } - - /* send one zero sized download request to signalize end */ - ret = dfu_download(dif->dev_handle, dif->interface, - 0, transaction, NULL); - if (ret < 0) { - errx(EX_IOERR, "Error sending completion packet"); - goto out; - } - - dfu_progress_bar("Download", bytes_sent, bytes_sent); - - if (verbose) - printf("Sent a total of %i bytes\n", bytes_sent); - -get_status: - /* Transition to MANIFEST_SYNC state */ - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - warnx("unable to read DFU status after completion"); - goto out; - } - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - - milli_sleep(dst.bwPollTimeout); - - /* FIXME: deal correctly with ManifestationTolerant=0 / WillDetach bits */ - switch (dst.bState) { - case DFU_STATE_dfuMANIFEST_SYNC: - case DFU_STATE_dfuMANIFEST: - /* some devices (e.g. TAS1020b) need some time before we - * can obtain the status */ - milli_sleep(1000); - goto get_status; - break; - case DFU_STATE_dfuIDLE: - break; - } - printf("Done!\n"); - -out: - return bytes_sent; -} diff --git a/linux/src/dfu-util/src/dfu_load.h b/linux/src/dfu-util/src/dfu_load.h deleted file mode 100644 index be23e9b4f..000000000 --- a/linux/src/dfu-util/src/dfu_load.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef DFU_LOAD_H -#define DFU_LOAD_H - -int dfuload_do_upload(struct dfu_if *dif, int xfer_size, int expected_size, int fd); -int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file); - -#endif /* DFU_LOAD_H */ diff --git a/linux/src/dfu-util/src/dfu_util.c b/linux/src/dfu-util/src/dfu_util.c deleted file mode 100644 index b94c7ccd3..000000000 --- a/linux/src/dfu-util/src/dfu_util.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Functions for detecting DFU USB entities - * - * Written by Harald Welte - * Copyright 2007-2008 by OpenMoko, Inc. - * Copyright 2013 Hans Petter Selasky - * - * Based on existing code of dfu-programmer-0.4 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfu_load.h" -#include "dfu_util.h" -#include "dfuse.h" -#include "quirks.h" - -#ifdef HAVE_USBPATH_H -#include -#endif - -/* - * Look for a descriptor in a concatenated descriptor list. Will - * return upon the first match of the given descriptor type. Returns length of - * found descriptor, limited to res_size - */ -static int find_descriptor(const uint8_t *desc_list, int list_len, - uint8_t desc_type, void *res_buf, int res_size) -{ - int p = 0; - - if (list_len < 2) - return (-1); - - while (p + 1 < list_len) { - int desclen; - - desclen = (int) desc_list[p]; - if (desclen == 0) { - warnx("Invalid descriptor list"); - return -1; - } - if (desc_list[p + 1] == desc_type) { - if (desclen > res_size) - desclen = res_size; - if (p + desclen > list_len) - desclen = list_len - p; - memcpy(res_buf, &desc_list[p], desclen); - return desclen; - } - p += (int) desc_list[p]; - } - return -1; -} - -static void probe_configuration(libusb_device *dev, struct libusb_device_descriptor *desc) -{ - struct usb_dfu_func_descriptor func_dfu; - libusb_device_handle *devh; - struct dfu_if *pdfu; - struct libusb_config_descriptor *cfg; - const struct libusb_interface_descriptor *intf; - const struct libusb_interface *uif; - char alt_name[MAX_DESC_STR_LEN + 1]; - char serial_name[MAX_DESC_STR_LEN + 1]; - int cfg_idx; - int intf_idx; - int alt_idx; - int ret; - int has_dfu; - - for (cfg_idx = 0; cfg_idx != desc->bNumConfigurations; cfg_idx++) { - memset(&func_dfu, 0, sizeof(func_dfu)); - has_dfu = 0; - - ret = libusb_get_config_descriptor(dev, cfg_idx, &cfg); - if (ret != 0) - return; - if (match_config_index > -1 && match_config_index != cfg->bConfigurationValue) { - libusb_free_config_descriptor(cfg); - continue; - } - - /* - * In some cases, noticably FreeBSD if uid != 0, - * the configuration descriptors are empty - */ - if (!cfg) - return; - - ret = find_descriptor(cfg->extra, cfg->extra_length, - USB_DT_DFU, &func_dfu, sizeof(func_dfu)); - if (ret > -1) - goto found_dfu; - - for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; - intf_idx++) { - uif = &cfg->interface[intf_idx]; - if (!uif) - break; - - for (alt_idx = 0; alt_idx < cfg->interface[intf_idx].num_altsetting; - alt_idx++) { - intf = &uif->altsetting[alt_idx]; - - ret = find_descriptor(intf->extra, intf->extra_length, USB_DT_DFU, - &func_dfu, sizeof(func_dfu)); - if (ret > -1) - goto found_dfu; - - if (intf->bInterfaceClass != 0xfe || - intf->bInterfaceSubClass != 1) - continue; - - has_dfu = 1; - } - } - if (has_dfu) { - /* - * Finally try to retrieve it requesting the - * device directly This is not supported on - * all devices for non-standard types - */ - if (libusb_open(dev, &devh) == 0) { - ret = libusb_get_descriptor(devh, USB_DT_DFU, 0, - (void *)&func_dfu, sizeof(func_dfu)); - libusb_close(devh); - if (ret > -1) - goto found_dfu; - } - warnx("Device has DFU interface, " - "but has no DFU functional descriptor"); - - /* fake version 1.0 */ - func_dfu.bLength = 7; - func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); - goto found_dfu; - } - libusb_free_config_descriptor(cfg); - continue; - -found_dfu: - if (func_dfu.bLength == 7) { - printf("Deducing device DFU version from functional descriptor " - "length\n"); - func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); - } else if (func_dfu.bLength < 9) { - printf("Error obtaining DFU functional descriptor\n"); - printf("Please report this as a bug!\n"); - printf("Warning: Assuming DFU version 1.0\n"); - func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); - printf("Warning: Transfer size can not be detected\n"); - func_dfu.wTransferSize = 0; - } - - for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; - intf_idx++) { - if (match_iface_index > -1 && match_iface_index != intf_idx) - continue; - - uif = &cfg->interface[intf_idx]; - if (!uif) - break; - - for (alt_idx = 0; - alt_idx < uif->num_altsetting; alt_idx++) { - int dfu_mode; - - intf = &uif->altsetting[alt_idx]; - - if (intf->bInterfaceClass != 0xfe || - intf->bInterfaceSubClass != 1) - continue; - - dfu_mode = (intf->bInterfaceProtocol == 2); - /* e.g. DSO Nano has bInterfaceProtocol 0 instead of 2 */ - if (func_dfu.bcdDFUVersion == 0x011a && intf->bInterfaceProtocol == 0) - dfu_mode = 1; - - if (dfu_mode && - match_iface_alt_index > -1 && match_iface_alt_index != alt_idx) - continue; - - if (dfu_mode) { - if ((match_vendor_dfu >= 0 && match_vendor_dfu != desc->idVendor) || - (match_product_dfu >= 0 && match_product_dfu != desc->idProduct)) { - continue; - } - } else { - if ((match_vendor >= 0 && match_vendor != desc->idVendor) || - (match_product >= 0 && match_product != desc->idProduct)) { - continue; - } - } - - if (libusb_open(dev, &devh)) { - warnx("Cannot open DFU device %04x:%04x", desc->idVendor, desc->idProduct); - break; - } - if (intf->iInterface != 0) - ret = libusb_get_string_descriptor_ascii(devh, - intf->iInterface, (void *)alt_name, MAX_DESC_STR_LEN); - else - ret = -1; - if (ret < 1) - strcpy(alt_name, "UNKNOWN"); - if (desc->iSerialNumber != 0) - ret = libusb_get_string_descriptor_ascii(devh, - desc->iSerialNumber, (void *)serial_name, MAX_DESC_STR_LEN); - else - ret = -1; - if (ret < 1) - strcpy(serial_name, "UNKNOWN"); - libusb_close(devh); - - if (dfu_mode && - match_iface_alt_name != NULL && strcmp(alt_name, match_iface_alt_name)) - continue; - - if (dfu_mode) { - if (match_serial_dfu != NULL && strcmp(match_serial_dfu, serial_name)) - continue; - } else { - if (match_serial != NULL && strcmp(match_serial, serial_name)) - continue; - } - - pdfu = dfu_malloc(sizeof(*pdfu)); - - memset(pdfu, 0, sizeof(*pdfu)); - - pdfu->func_dfu = func_dfu; - pdfu->dev = libusb_ref_device(dev); - pdfu->quirks = get_quirks(desc->idVendor, - desc->idProduct, desc->bcdDevice); - pdfu->vendor = desc->idVendor; - pdfu->product = desc->idProduct; - pdfu->bcdDevice = desc->bcdDevice; - pdfu->configuration = cfg->bConfigurationValue; - pdfu->interface = intf->bInterfaceNumber; - pdfu->altsetting = intf->bAlternateSetting; - pdfu->devnum = libusb_get_device_address(dev); - pdfu->busnum = libusb_get_bus_number(dev); - pdfu->alt_name = strdup(alt_name); - if (pdfu->alt_name == NULL) - errx(EX_SOFTWARE, "Out of memory"); - pdfu->serial_name = strdup(serial_name); - if (pdfu->serial_name == NULL) - errx(EX_SOFTWARE, "Out of memory"); - if (dfu_mode) - pdfu->flags |= DFU_IFF_DFU; - if (pdfu->quirks & QUIRK_FORCE_DFU11) { - pdfu->func_dfu.bcdDFUVersion = - libusb_cpu_to_le16(0x0110); - } - pdfu->bMaxPacketSize0 = desc->bMaxPacketSize0; - - /* queue into list */ - pdfu->next = dfu_root; - dfu_root = pdfu; - } - } - libusb_free_config_descriptor(cfg); - } -} - -void probe_devices(libusb_context *ctx) -{ - libusb_device **list; - ssize_t num_devs; - ssize_t i; - - num_devs = libusb_get_device_list(ctx, &list); - for (i = 0; i < num_devs; ++i) { - struct libusb_device_descriptor desc; - struct libusb_device *dev = list[i]; - - if (match_bus > -1 && match_bus != libusb_get_bus_number(dev)) - continue; - if (match_device > -1 && match_device != libusb_get_device_address(dev)) - continue; - if (libusb_get_device_descriptor(dev, &desc)) - continue; - probe_configuration(dev, &desc); - } - libusb_free_device_list(list, 0); -} - -void disconnect_devices(void) -{ - struct dfu_if *pdfu; - struct dfu_if *prev = NULL; - - for (pdfu = dfu_root; pdfu != NULL; pdfu = pdfu->next) { - free(prev); - libusb_unref_device(pdfu->dev); - free(pdfu->alt_name); - free(pdfu->serial_name); - prev = pdfu; - } - free(prev); - dfu_root = NULL; -} - -void print_dfu_if(struct dfu_if *dfu_if) -{ - printf("Found %s: [%04x:%04x] ver=%04x, devnum=%u, cfg=%u, intf=%u, " - "alt=%u, name=\"%s\", serial=\"%s\"\n", - dfu_if->flags & DFU_IFF_DFU ? "DFU" : "Runtime", - dfu_if->vendor, dfu_if->product, - dfu_if->bcdDevice, dfu_if->devnum, - dfu_if->configuration, dfu_if->interface, - dfu_if->altsetting, dfu_if->alt_name, - dfu_if->serial_name); -} - -/* Walk the device tree and print out DFU devices */ -void list_dfu_interfaces(void) -{ - struct dfu_if *pdfu; - - for (pdfu = dfu_root; pdfu != NULL; pdfu = pdfu->next) - print_dfu_if(pdfu); -} diff --git a/linux/src/dfu-util/src/dfu_util.h b/linux/src/dfu-util/src/dfu_util.h deleted file mode 100644 index fc0c19dca..000000000 --- a/linux/src/dfu-util/src/dfu_util.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef DFU_UTIL_H -#define DFU_UTIL_H - -/* USB string descriptor should contain max 126 UTF-16 characters - * but 253 would even accomodate any UTF-8 encoding */ -#define MAX_DESC_STR_LEN 253 - -enum mode { - MODE_NONE, - MODE_VERSION, - MODE_LIST, - MODE_DETACH, - MODE_UPLOAD, - MODE_DOWNLOAD -}; - -extern struct dfu_if *dfu_root; -extern int match_bus; -extern int match_device; -extern int match_vendor; -extern int match_product; -extern int match_vendor_dfu; -extern int match_product_dfu; -extern int match_config_index; -extern int match_iface_index; -extern int match_iface_alt_index; -extern const char *match_iface_alt_name; -extern const char *match_serial; -extern const char *match_serial_dfu; - -void probe_devices(libusb_context *); -void disconnect_devices(void); -void print_dfu_if(struct dfu_if *); -void list_dfu_interfaces(void); - -#endif /* DFU_UTIL_H */ diff --git a/linux/src/dfu-util/src/dfuse.c b/linux/src/dfu-util/src/dfuse.c deleted file mode 100644 index fce29fed6..000000000 --- a/linux/src/dfu-util/src/dfuse.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * DfuSe specific functions - * - * This implements the ST Microsystems DFU extensions (DfuSe) - * as per the DfuSe 1.1a specification (ST documents AN3156, AN2606) - * The DfuSe file format is described in ST document UM0391. - * - * Copyright 2010-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfuse.h" -#include "dfuse_mem.h" - -#define DFU_TIMEOUT 5000 - -extern int verbose; -static unsigned int last_erased_page = 1; /* non-aligned value, won't match */ -static struct memsegment *mem_layout; -static unsigned int dfuse_address = 0; -static unsigned int dfuse_length = 0; -static int dfuse_force = 0; -static int dfuse_leave = 0; -static int dfuse_unprotect = 0; -static int dfuse_mass_erase = 0; - -unsigned int quad2uint(unsigned char *p) -{ - return (*p + (*(p + 1) << 8) + (*(p + 2) << 16) + (*(p + 3) << 24)); -} - -void dfuse_parse_options(const char *options) -{ - char *end; - const char *endword; - unsigned int number; - - /* address, possibly empty, must be first */ - if (*options != ':') { - endword = strchr(options, ':'); - if (!endword) - endword = options + strlen(options); /* GNU strchrnul */ - - number = strtoul(options, &end, 0); - if (end == endword) { - dfuse_address = number; - } else { - errx(EX_IOERR, "Invalid dfuse address: %s", options); - } - options = endword; - } - - while (*options) { - if (*options == ':') { - options++; - continue; - } - endword = strchr(options, ':'); - if (!endword) - endword = options + strlen(options); - - if (!strncmp(options, "force", endword - options)) { - dfuse_force++; - options += 5; - continue; - } - if (!strncmp(options, "leave", endword - options)) { - dfuse_leave = 1; - options += 5; - continue; - } - if (!strncmp(options, "unprotect", endword - options)) { - dfuse_unprotect = 1; - options += 9; - continue; - } - if (!strncmp(options, "mass-erase", endword - options)) { - dfuse_mass_erase = 1; - options += 10; - continue; - } - - /* any valid number is interpreted as upload length */ - number = strtoul(options, &end, 0); - if (end == endword) { - dfuse_length = number; - } else { - errx(EX_IOERR, "Invalid dfuse modifier: %s", options); - } - options = endword; - } -} - -/* DFU_UPLOAD request for DfuSe 1.1a */ -int dfuse_upload(struct dfu_if *dif, const unsigned short length, - unsigned char *data, unsigned short transaction) -{ - int status; - - status = libusb_control_transfer(dif->dev_handle, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | - LIBUSB_REQUEST_TYPE_CLASS | - LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_UPLOAD, - /* wValue */ transaction, - /* wIndex */ dif->interface, - /* Data */ data, - /* wLength */ length, - DFU_TIMEOUT); - if (status < 0) { - errx(EX_IOERR, "%s: libusb_control_msg returned %d", - __FUNCTION__, status); - } - return status; -} - -/* DFU_DNLOAD request for DfuSe 1.1a */ -int dfuse_download(struct dfu_if *dif, const unsigned short length, - unsigned char *data, unsigned short transaction) -{ - int status; - - status = libusb_control_transfer(dif->dev_handle, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_CLASS | - LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_DNLOAD, - /* wValue */ transaction, - /* wIndex */ dif->interface, - /* Data */ data, - /* wLength */ length, - DFU_TIMEOUT); - if (status < 0) { - errx(EX_IOERR, "%s: libusb_control_transfer returned %d", - __FUNCTION__, status); - } - return status; -} - -/* DfuSe only commands */ -/* Leaves the device in dfuDNLOAD-IDLE state */ -int dfuse_special_command(struct dfu_if *dif, unsigned int address, - enum dfuse_command command) -{ - const char* dfuse_command_name[] = { "SET_ADDRESS" , "ERASE_PAGE", - "MASS_ERASE", "READ_UNPROTECT"}; - unsigned char buf[5]; - int length; - int ret; - struct dfu_status dst; - int firstpoll = 1; - - if (command == ERASE_PAGE) { - struct memsegment *segment; - int page_size; - - segment = find_segment(mem_layout, address); - if (!segment || !(segment->memtype & DFUSE_ERASABLE)) { - errx(EX_IOERR, "Page at 0x%08x can not be erased", - address); - } - page_size = segment->pagesize; - if (verbose > 1) - printf("Erasing page size %i at address 0x%08x, page " - "starting at 0x%08x\n", page_size, address, - address & ~(page_size - 1)); - buf[0] = 0x41; /* Erase command */ - length = 5; - last_erased_page = address & ~(page_size - 1); - } else if (command == SET_ADDRESS) { - if (verbose > 2) - printf(" Setting address pointer to 0x%08x\n", - address); - buf[0] = 0x21; /* Set Address Pointer command */ - length = 5; - } else if (command == MASS_ERASE) { - buf[0] = 0x41; /* Mass erase command when length = 1 */ - length = 1; - } else if (command == READ_UNPROTECT) { - buf[0] = 0x92; - length = 1; - } else { - errx(EX_IOERR, "Non-supported special command %d", command); - } - buf[1] = address & 0xff; - buf[2] = (address >> 8) & 0xff; - buf[3] = (address >> 16) & 0xff; - buf[4] = (address >> 24) & 0xff; - - ret = dfuse_download(dif, length, buf, 0); - if (ret < 0) { - errx(EX_IOERR, "Error during special command \"%s\" download", - dfuse_command_name[command]); - } - do { - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during special command \"%s\" get_status", - dfuse_command_name[command]); - } - if (firstpoll) { - firstpoll = 0; - if (dst.bState != DFU_STATE_dfuDNBUSY) { - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - errx(EX_IOERR, "Wrong state after command \"%s\" download", - dfuse_command_name[command]); - } - } - /* wait while command is executed */ - if (verbose) - printf(" Poll timeout %i ms\n", dst.bwPollTimeout); - milli_sleep(dst.bwPollTimeout); - if (command == READ_UNPROTECT) - return ret; - } while (dst.bState == DFU_STATE_dfuDNBUSY); - - if (dst.bStatus != DFU_STATUS_OK) { - errx(EX_IOERR, "%s not correctly executed", - dfuse_command_name[command]); - } - return ret; -} - -int dfuse_dnload_chunk(struct dfu_if *dif, unsigned char *data, int size, - int transaction) -{ - int bytes_sent; - struct dfu_status dst; - int ret; - - ret = dfuse_download(dif, size, size ? data : NULL, transaction); - if (ret < 0) { - errx(EX_IOERR, "Error during download"); - return ret; - } - bytes_sent = ret; - - do { - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during download get_status"); - return ret; - } - milli_sleep(dst.bwPollTimeout); - } while (dst.bState != DFU_STATE_dfuDNLOAD_IDLE && - dst.bState != DFU_STATE_dfuERROR && - dst.bState != DFU_STATE_dfuMANIFEST); - - if (dst.bState == DFU_STATE_dfuMANIFEST) - printf("Transitioning to dfuMANIFEST state\n"); - - if (dst.bStatus != DFU_STATUS_OK) { - printf(" failed!\n"); - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - return -1; - } - return bytes_sent; -} - -int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd, - const char *dfuse_options) -{ - int total_bytes = 0; - int upload_limit = 0; - unsigned char *buf; - int transaction; - int ret; - - buf = dfu_malloc(xfer_size); - - if (dfuse_options) - dfuse_parse_options(dfuse_options); - if (dfuse_length) - upload_limit = dfuse_length; - if (dfuse_address) { - struct memsegment *segment; - - mem_layout = parse_memory_layout((char *)dif->alt_name); - if (!mem_layout) - errx(EX_IOERR, "Failed to parse memory layout"); - - segment = find_segment(mem_layout, dfuse_address); - if (!dfuse_force && - (!segment || !(segment->memtype & DFUSE_READABLE))) - errx(EX_IOERR, "Page at 0x%08x is not readable", - dfuse_address); - - if (!upload_limit) { - upload_limit = segment->end - dfuse_address + 1; - printf("Limiting upload to end of memory segment, " - "%i bytes\n", upload_limit); - } - dfuse_special_command(dif, dfuse_address, SET_ADDRESS); - dfu_abort_to_idle(dif); - } else { - /* Boot loader decides the start address, unknown to us */ - /* Use a short length to lower risk of running out of bounds */ - if (!upload_limit) - upload_limit = 0x4000; - printf("Limiting default upload to %i bytes\n", upload_limit); - } - - dfu_progress_bar("Upload", 0, 1); - - transaction = 2; - while (1) { - int rc; - - /* last chunk can be smaller than original xfer_size */ - if (upload_limit - total_bytes < xfer_size) - xfer_size = upload_limit - total_bytes; - rc = dfuse_upload(dif, xfer_size, buf, transaction++); - if (rc < 0) { - ret = rc; - goto out_free; - } - - dfu_file_write_crc(fd, 0, buf, rc); - total_bytes += rc; - - if (total_bytes < 0) - errx(EX_SOFTWARE, "Received too many bytes"); - - if (rc < xfer_size || total_bytes >= upload_limit) { - /* last block, return successfully */ - ret = total_bytes; - break; - } - dfu_progress_bar("Upload", total_bytes, upload_limit); - } - - dfu_progress_bar("Upload", total_bytes, total_bytes); - - dfu_abort_to_idle(dif); - if (dfuse_leave) { - dfuse_special_command(dif, dfuse_address, SET_ADDRESS); - dfuse_dnload_chunk(dif, NULL, 0, 2); /* Zero-size */ - } - - out_free: - free(buf); - - return ret; -} - -/* Writes an element of any size to the device, taking care of page erases */ -/* returns 0 on success, otherwise -EINVAL */ -int dfuse_dnload_element(struct dfu_if *dif, unsigned int dwElementAddress, - unsigned int dwElementSize, unsigned char *data, - int xfer_size) -{ - int p; - int ret; - struct memsegment *segment; - - /* Check at least that we can write to the last address */ - segment = - find_segment(mem_layout, dwElementAddress + dwElementSize - 1); - if (!segment || !(segment->memtype & DFUSE_WRITEABLE)) { - errx(EX_IOERR, "Last page at 0x%08x is not writeable", - dwElementAddress + dwElementSize - 1); - } - - dfu_progress_bar("Download", 0, 1); - - for (p = 0; p < (int)dwElementSize; p += xfer_size) { - int page_size; - unsigned int erase_address; - unsigned int address = dwElementAddress + p; - int chunk_size = xfer_size; - - segment = find_segment(mem_layout, address); - if (!segment || !(segment->memtype & DFUSE_WRITEABLE)) { - errx(EX_IOERR, "Page at 0x%08x is not writeable", - address); - } - page_size = segment->pagesize; - - /* check if this is the last chunk */ - if (p + chunk_size > (int)dwElementSize) - chunk_size = dwElementSize - p; - - /* Erase only for flash memory downloads */ - if ((segment->memtype & DFUSE_ERASABLE) && !dfuse_mass_erase) { - /* erase all involved pages */ - for (erase_address = address; - erase_address < address + chunk_size; - erase_address += page_size) - if ((erase_address & ~(page_size - 1)) != - last_erased_page) - dfuse_special_command(dif, - erase_address, - ERASE_PAGE); - - if (((address + chunk_size - 1) & ~(page_size - 1)) != - last_erased_page) { - if (verbose > 2) - printf(" Chunk extends into next page," - " erase it as well\n"); - dfuse_special_command(dif, - address + chunk_size - 1, - ERASE_PAGE); - } - } - - if (verbose) { - printf(" Download from image offset " - "%08x to memory %08x-%08x, size %i\n", - p, address, address + chunk_size - 1, - chunk_size); - } else { - dfu_progress_bar("Download", p, dwElementSize); - } - - dfuse_special_command(dif, address, SET_ADDRESS); - - /* transaction = 2 for no address offset */ - ret = dfuse_dnload_chunk(dif, data + p, chunk_size, 2); - if (ret != chunk_size) { - errx(EX_IOERR, "Failed to write whole chunk: " - "%i of %i bytes", ret, chunk_size); - return -EINVAL; - } - } - if (!verbose) - dfu_progress_bar("Download", dwElementSize, dwElementSize); - return 0; -} - -static void -dfuse_memcpy(unsigned char *dst, unsigned char **src, int *rem, int size) -{ - if (size > *rem) { - errx(EX_IOERR, "Corrupt DfuSe file: " - "Cannot read %d bytes from %d bytes", size, *rem); - } - if (dst != NULL) - memcpy(dst, *src, size); - (*src) += size; - (*rem) -= size; -} - -/* Download raw binary file to DfuSe device */ -int dfuse_do_bin_dnload(struct dfu_if *dif, int xfer_size, - struct dfu_file *file, unsigned int start_address) -{ - unsigned int dwElementAddress; - unsigned int dwElementSize; - unsigned char *data; - int ret; - - dwElementAddress = start_address; - dwElementSize = file->size.total - - file->size.suffix - file->size.prefix; - - printf("Downloading to address = 0x%08x, size = %i\n", - dwElementAddress, dwElementSize); - - data = file->firmware + file->size.prefix; - - ret = dfuse_dnload_element(dif, dwElementAddress, dwElementSize, data, - xfer_size); - if (ret != 0) - goto out_free; - - printf("File downloaded successfully\n"); - ret = dwElementSize; - - out_free: - return ret; -} - -/* Parse a DfuSe file and download contents to device */ -int dfuse_do_dfuse_dnload(struct dfu_if *dif, int xfer_size, - struct dfu_file *file) -{ - uint8_t dfuprefix[11]; - uint8_t targetprefix[274]; - uint8_t elementheader[8]; - int image; - int element; - int bTargets; - int bAlternateSetting; - int dwNbElements; - unsigned int dwElementAddress; - unsigned int dwElementSize; - uint8_t *data; - int ret; - int rem; - int bFirstAddressSaved = 0; - - rem = file->size.total - file->size.prefix - file->size.suffix; - data = file->firmware + file->size.prefix; - - /* Must be larger than a minimal DfuSe header and suffix */ - if (rem < (int)(sizeof(dfuprefix) + - sizeof(targetprefix) + sizeof(elementheader))) { - errx(EX_SOFTWARE, "File too small for a DfuSe file"); - } - - dfuse_memcpy(dfuprefix, &data, &rem, sizeof(dfuprefix)); - - if (strncmp((char *)dfuprefix, "DfuSe", 5)) { - errx(EX_IOERR, "No valid DfuSe signature"); - return -EINVAL; - } - if (dfuprefix[5] != 0x01) { - errx(EX_IOERR, "DFU format revision %i not supported", - dfuprefix[5]); - return -EINVAL; - } - bTargets = dfuprefix[10]; - printf("file contains %i DFU images\n", bTargets); - - for (image = 1; image <= bTargets; image++) { - printf("parsing DFU image %i\n", image); - dfuse_memcpy(targetprefix, &data, &rem, sizeof(targetprefix)); - if (strncmp((char *)targetprefix, "Target", 6)) { - errx(EX_IOERR, "No valid target signature"); - return -EINVAL; - } - bAlternateSetting = targetprefix[6]; - dwNbElements = quad2uint((unsigned char *)targetprefix + 270); - printf("image for alternate setting %i, ", bAlternateSetting); - printf("(%i elements, ", dwNbElements); - printf("total size = %i)\n", - quad2uint((unsigned char *)targetprefix + 266)); - if (bAlternateSetting != dif->altsetting) - printf("Warning: Image does not match current alternate" - " setting.\n" - "Please rerun with the correct -a option setting" - " to download this image!\n"); - for (element = 1; element <= dwNbElements; element++) { - printf("parsing element %i, ", element); - dfuse_memcpy(elementheader, &data, &rem, sizeof(elementheader)); - dwElementAddress = - quad2uint((unsigned char *)elementheader); - dwElementSize = - quad2uint((unsigned char *)elementheader + 4); - printf("address = 0x%08x, ", dwElementAddress); - printf("size = %i\n", dwElementSize); - - if (!bFirstAddressSaved) { - bFirstAddressSaved = 1; - dfuse_address = dwElementAddress; - } - /* sanity check */ - if ((int)dwElementSize > rem) - errx(EX_SOFTWARE, "File too small for element size"); - - if (bAlternateSetting == dif->altsetting) { - ret = dfuse_dnload_element(dif, dwElementAddress, - dwElementSize, data, xfer_size); - } else { - ret = 0; - } - - /* advance read pointer */ - dfuse_memcpy(NULL, &data, &rem, dwElementSize); - - if (ret != 0) - return ret; - } - } - - if (rem != 0) - warnx("%d bytes leftover", rem); - - printf("done parsing DfuSe file\n"); - - return 0; -} - -int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file, - const char *dfuse_options) -{ - int ret; - - if (dfuse_options) - dfuse_parse_options(dfuse_options); - mem_layout = parse_memory_layout((char *)dif->alt_name); - if (!mem_layout) { - errx(EX_IOERR, "Failed to parse memory layout"); - } - if (dfuse_unprotect) { - if (!dfuse_force) { - errx(EX_IOERR, "The read unprotect command " - "will erase the flash memory" - "and can only be used with force\n"); - } - dfuse_special_command(dif, 0, READ_UNPROTECT); - printf("Device disconnects, erases flash and resets now\n"); - exit(0); - } - if (dfuse_mass_erase) { - if (!dfuse_force) { - errx(EX_IOERR, "The mass erase command " - "can only be used with force"); - } - printf("Performing mass erase, this can take a moment\n"); - dfuse_special_command(dif, 0, MASS_ERASE); - } - if (dfuse_address) { - if (file->bcdDFU == 0x11a) { - errx(EX_IOERR, "This is a DfuSe file, not " - "meant for raw download"); - } - ret = dfuse_do_bin_dnload(dif, xfer_size, file, dfuse_address); - } else { - if (file->bcdDFU != 0x11a) { - warnx("Only DfuSe file version 1.1a is supported"); - errx(EX_IOERR, "(for raw binary download, use the " - "--dfuse-address option)"); - } - ret = dfuse_do_dfuse_dnload(dif, xfer_size, file); - } - free_segment_list(mem_layout); - - dfu_abort_to_idle(dif); - - if (dfuse_leave) { - dfuse_special_command(dif, dfuse_address, SET_ADDRESS); - dfuse_dnload_chunk(dif, NULL, 0, 2); /* Zero-size */ - } - return ret; -} diff --git a/linux/src/dfu-util/src/dfuse.h b/linux/src/dfu-util/src/dfuse.h deleted file mode 100644 index ed1108cfc..000000000 --- a/linux/src/dfu-util/src/dfuse.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This implements the ST Microsystems DFU extensions (DfuSe) - * as per the DfuSe 1.1a specification (Document UM0391) - * - * (C) 2010-2012 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DFUSE_H -#define DFUSE_H - -#include "dfu.h" - -enum dfuse_command { SET_ADDRESS, ERASE_PAGE, MASS_ERASE, READ_UNPROTECT }; - -int dfuse_special_command(struct dfu_if *dif, unsigned int address, - enum dfuse_command command); -int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd, - const char *dfuse_options); -int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file, - const char *dfuse_options); - -#endif /* DFUSE_H */ diff --git a/linux/src/dfu-util/src/dfuse_mem.c b/linux/src/dfu-util/src/dfuse_mem.c deleted file mode 100644 index a91aacf5f..000000000 --- a/linux/src/dfu-util/src/dfuse_mem.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Helper functions for reading the memory map of a device - * following the ST DfuSe 1.1a specification. - * - * Copyright 2011-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" -#include "dfuse_mem.h" - -int add_segment(struct memsegment **segment_list, struct memsegment segment) -{ - struct memsegment *new_element; - - new_element = dfu_malloc(sizeof(struct memsegment)); - *new_element = segment; - new_element->next = NULL; - - if (*segment_list == NULL) - /* list can be empty on first call */ - *segment_list = new_element; - else { - struct memsegment *next_element; - - /* find last element in list */ - next_element = *segment_list; - while (next_element->next != NULL) - next_element = next_element->next; - next_element->next = new_element; - } - return 0; -} - -struct memsegment *find_segment(struct memsegment *segment_list, - unsigned int address) -{ - while (segment_list != NULL) { - if (segment_list->start <= address && - segment_list->end >= address) - return segment_list; - segment_list = segment_list->next; - } - return NULL; -} - -void free_segment_list(struct memsegment *segment_list) -{ - struct memsegment *next_element; - - while (segment_list->next != NULL) { - next_element = segment_list->next; - free(segment_list); - segment_list = next_element; - } - free(segment_list); -} - -/* Parse memory map from interface descriptor string - * encoded as per ST document UM0424 section 4.3.2. - */ -struct memsegment *parse_memory_layout(char *intf_desc) -{ - - char multiplier, memtype; - unsigned int address; - int sectors, size; - char *name, *typestring; - int ret; - int count = 0; - char separator; - int scanned; - struct memsegment *segment_list = NULL; - struct memsegment segment; - - name = dfu_malloc(strlen(intf_desc)); - - ret = sscanf(intf_desc, "@%[^/]%n", name, &scanned); - if (ret < 1) { - free(name); - warnx("Could not read name, sscanf returned %d", ret); - return NULL; - } - printf("DfuSe interface name: \"%s\"\n", name); - - intf_desc += scanned; - typestring = dfu_malloc(strlen(intf_desc)); - - while (ret = sscanf(intf_desc, "/0x%x/%n", &address, &scanned), - ret > 0) { - - intf_desc += scanned; - while (ret = sscanf(intf_desc, "%d*%d%c%[^,/]%n", - §ors, &size, &multiplier, typestring, - &scanned), ret > 2) { - intf_desc += scanned; - - count++; - memtype = 0; - if (ret == 4) { - if (strlen(typestring) == 1 - && typestring[0] != '/') - memtype = typestring[0]; - else { - warnx("Parsing type identifier '%s' " - "failed for segment %i", - typestring, count); - continue; - } - } - - /* Quirk for STM32F4 devices */ - if (strcmp(name, "Device Feature") == 0) - memtype = 'e'; - - switch (multiplier) { - case 'B': - break; - case 'K': - size *= 1024; - break; - case 'M': - size *= 1024 * 1024; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - if (!memtype) { - warnx("Non-valid multiplier '%c', " - "interpreted as type " - "identifier instead", - multiplier); - memtype = multiplier; - break; - } - /* fallthrough if memtype was already set */ - default: - warnx("Non-valid multiplier '%c', " - "assuming bytes", multiplier); - } - - if (!memtype) { - warnx("No valid type for segment %d\n", count); - continue; - } - - segment.start = address; - segment.end = address + sectors * size - 1; - segment.pagesize = size; - segment.memtype = memtype & 7; - add_segment(&segment_list, segment); - - if (verbose) - printf("Memory segment at 0x%08x %3d x %4d = " - "%5d (%s%s%s)\n", - address, sectors, size, sectors * size, - memtype & DFUSE_READABLE ? "r" : "", - memtype & DFUSE_ERASABLE ? "e" : "", - memtype & DFUSE_WRITEABLE ? "w" : ""); - - address += sectors * size; - - separator = *intf_desc; - if (separator == ',') - intf_desc += 1; - else - break; - } /* while per segment */ - - } /* while per address */ - free(name); - free(typestring); - - return segment_list; -} diff --git a/linux/src/dfu-util/src/dfuse_mem.h b/linux/src/dfu-util/src/dfuse_mem.h deleted file mode 100644 index 0181f0c16..000000000 --- a/linux/src/dfu-util/src/dfuse_mem.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Helper functions for reading the memory map in a device - * following the ST DfuSe 1.1a specification. - * - * (C) 2011 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DFUSE_MEM_H -#define DFUSE_MEM_H - -#define DFUSE_READABLE 1 -#define DFUSE_ERASABLE 2 -#define DFUSE_WRITEABLE 4 - -struct memsegment { - unsigned int start; - unsigned int end; - int pagesize; - int memtype; - struct memsegment *next; -}; - -int add_segment(struct memsegment **list, struct memsegment new_element); - -struct memsegment *find_segment(struct memsegment *list, unsigned int address); - -void free_segment_list(struct memsegment *list); - -struct memsegment *parse_memory_layout(char *intf_desc_str); - -#endif /* DFUSE_MEM_H */ diff --git a/linux/src/dfu-util/src/main.c b/linux/src/dfu-util/src/main.c deleted file mode 100644 index acaed2f08..000000000 --- a/linux/src/dfu-util/src/main.c +++ /dev/null @@ -1,699 +0,0 @@ -/* - * dfu-util - * - * Copyright 2007-2008 by OpenMoko, Inc. - * Copyright 2013-2014 Hans Petter Selasky - * - * Written by Harald Welte - * - * Based on existing code of dfu-programmer-0.4 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfu_load.h" -#include "dfu_util.h" -#include "dfuse.h" -#include "quirks.h" - -#ifdef HAVE_USBPATH_H -#include -#endif - -int verbose = 0; - -struct dfu_if *dfu_root = NULL; - -int match_bus = -1; -int match_device = -1; -int match_vendor = -1; -int match_product = -1; -int match_vendor_dfu = -1; -int match_product_dfu = -1; -int match_config_index = -1; -int match_iface_index = -1; -int match_iface_alt_index = -1; -const char *match_iface_alt_name = NULL; -const char *match_serial = NULL; -const char *match_serial_dfu = NULL; - -static int parse_match_value(const char *str, int default_value) -{ - char *remainder; - int value; - - if (str == NULL) { - value = default_value; - } else if (*str == '*') { - value = -1; /* Match anything */ - } else if (*str == '-') { - value = 0x10000; /* Impossible vendor/product ID */ - } else { - value = strtoul(str, &remainder, 16); - if (remainder == str) { - value = default_value; - } - } - return value; -} - -static void parse_vendprod(const char *str) -{ - const char *comma; - const char *colon; - - /* Default to match any DFU device in runtime or DFU mode */ - match_vendor = -1; - match_product = -1; - match_vendor_dfu = -1; - match_product_dfu = -1; - - comma = strchr(str, ','); - if (comma == str) { - /* DFU mode vendor/product being specified without any runtime - * vendor/product specification, so don't match any runtime device */ - match_vendor = match_product = 0x10000; - } else { - colon = strchr(str, ':'); - if (colon != NULL) { - ++colon; - if ((comma != NULL) && (colon > comma)) { - colon = NULL; - } - } - match_vendor = parse_match_value(str, match_vendor); - match_product = parse_match_value(colon, match_product); - if (comma != NULL) { - /* Both runtime and DFU mode vendor/product specifications are - * available, so default DFU mode match components to the given - * runtime match components */ - match_vendor_dfu = match_vendor; - match_product_dfu = match_product; - } - } - if (comma != NULL) { - ++comma; - colon = strchr(comma, ':'); - if (colon != NULL) { - ++colon; - } - match_vendor_dfu = parse_match_value(comma, match_vendor_dfu); - match_product_dfu = parse_match_value(colon, match_product_dfu); - } -} - -static void parse_serial(char *str) -{ - char *comma; - - match_serial = str; - comma = strchr(str, ','); - if (comma == NULL) { - match_serial_dfu = match_serial; - } else { - *comma++ = 0; - match_serial_dfu = comma; - } - if (*match_serial == 0) match_serial = NULL; - if (*match_serial_dfu == 0) match_serial_dfu = NULL; -} - -#ifdef HAVE_USBPATH_H - -static int resolve_device_path(char *path) -{ - int res; - - res = usb_path2devnum(path); - if (res < 0) - return -EINVAL; - if (!res) - return 0; - - match_bus = atoi(path); - match_device = res; - - return 0; -} - -#else /* HAVE_USBPATH_H */ - -static int resolve_device_path(char *path) -{ - (void)path; /* Eliminate unused variable warning */ - errx(EX_SOFTWARE, "USB device paths are not supported by this dfu-util.\n"); -} - -#endif /* !HAVE_USBPATH_H */ - -static void help(void) -{ - fprintf(stderr, "Usage: dfu-util [options] ...\n" - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -v --verbose\t\t\tPrint verbose debug statements\n" - " -l --list\t\t\tList currently attached DFU capable devices\n"); - fprintf(stderr, " -e --detach\t\t\tDetach currently attached DFU capable devices\n" - " -E --detach-delay seconds\tTime to wait before reopening a device after detach\n" - " -d --device :[,:]\n" - "\t\t\t\tSpecify Vendor/Product ID(s) of DFU device\n" - " -p --path \tSpecify path to DFU device\n" - " -c --cfg \t\tSpecify the Configuration of DFU device\n" - " -i --intf \t\tSpecify the DFU Interface number\n" - " -S --serial [,]\n" - "\t\t\t\tSpecify Serial String of DFU device\n" - " -a --alt \t\tSpecify the Altsetting of the DFU Interface\n" - "\t\t\t\tby name or by number\n"); - fprintf(stderr, " -t --transfer-size \tSpecify the number of bytes per USB Transfer\n" - " -U --upload \t\tRead firmware from device into \n" - " -Z --upload-size \tSpecify the expected upload size in bytes\n" - " -D --download \t\tWrite firmware from into device\n" - " -R --reset\t\t\tIssue USB Reset signalling once we're finished\n" - " -s --dfuse-address

\tST DfuSe mode, specify target address for\n" - "\t\t\t\traw file download or upload. Not applicable for\n" - "\t\t\t\tDfuSe file (.dfu) downloads\n" - ); - exit(EX_USAGE); -} - -static void print_version(void) -{ - printf(PACKAGE_STRING "\n\n"); - printf("Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.\n" - "Copyright 2010-2014 Tormod Volden and Stefan Schmidt\n" - "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" - "Please report bugs to " PACKAGE_BUGREPORT "\n\n"); -} - -static struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'V' }, - { "verbose", 0, 0, 'v' }, - { "list", 0, 0, 'l' }, - { "detach", 0, 0, 'e' }, - { "detach-delay", 1, 0, 'E' }, - { "device", 1, 0, 'd' }, - { "path", 1, 0, 'p' }, - { "configuration", 1, 0, 'c' }, - { "cfg", 1, 0, 'c' }, - { "interface", 1, 0, 'i' }, - { "intf", 1, 0, 'i' }, - { "altsetting", 1, 0, 'a' }, - { "alt", 1, 0, 'a' }, - { "serial", 1, 0, 'S' }, - { "transfer-size", 1, 0, 't' }, - { "upload", 1, 0, 'U' }, - { "upload-size", 1, 0, 'Z' }, - { "download", 1, 0, 'D' }, - { "reset", 0, 0, 'R' }, - { "dfuse-address", 1, 0, 's' }, - { 0, 0, 0, 0 } -}; - -int main(int argc, char **argv) -{ - int expected_size = 0; - unsigned int transfer_size = 0; - enum mode mode = MODE_NONE; - struct dfu_status status; - libusb_context *ctx; - struct dfu_file file; - char *end; - int final_reset = 0; - int ret; - int dfuse_device = 0; - int fd; - const char *dfuse_options = NULL; - int detach_delay = 5; - uint16_t runtime_vendor; - uint16_t runtime_product; - - memset(&file, 0, sizeof(file)); - - /* make sure all prints are flushed */ - setvbuf(stdout, NULL, _IONBF, 0); - - while (1) { - int c, option_index = 0; - c = getopt_long(argc, argv, "hVvleE:d:p:c:i:a:S:t:U:D:Rs:Z:", opts, - &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - help(); - break; - case 'V': - mode = MODE_VERSION; - break; - case 'v': - verbose++; - break; - case 'l': - mode = MODE_LIST; - break; - case 'e': - mode = MODE_DETACH; - match_iface_alt_index = 0; - match_iface_index = 0; - break; - case 'E': - detach_delay = atoi(optarg); - break; - case 'd': - parse_vendprod(optarg); - break; - case 'p': - /* Parse device path */ - ret = resolve_device_path(optarg); - if (ret < 0) - errx(EX_SOFTWARE, "Unable to parse '%s'", optarg); - if (!ret) - errx(EX_SOFTWARE, "Cannot find '%s'", optarg); - break; - case 'c': - /* Configuration */ - match_config_index = atoi(optarg); - break; - case 'i': - /* Interface */ - match_iface_index = atoi(optarg); - break; - case 'a': - /* Interface Alternate Setting */ - match_iface_alt_index = strtoul(optarg, &end, 0); - if (*end) { - match_iface_alt_name = optarg; - match_iface_alt_index = -1; - } - break; - case 'S': - parse_serial(optarg); - break; - case 't': - transfer_size = atoi(optarg); - break; - case 'U': - mode = MODE_UPLOAD; - file.name = optarg; - break; - case 'Z': - expected_size = atoi(optarg); - break; - case 'D': - mode = MODE_DOWNLOAD; - file.name = optarg; - break; - case 'R': - final_reset = 1; - break; - case 's': - dfuse_options = optarg; - break; - default: - help(); - break; - } - } - - print_version(); - if (mode == MODE_VERSION) { - exit(0); - } - - if (mode == MODE_NONE) { - fprintf(stderr, "You need to specify one of -D or -U\n"); - help(); - } - - if (match_config_index == 0) { - /* Handle "-c 0" (unconfigured device) as don't care */ - match_config_index = -1; - } - - if (mode == MODE_DOWNLOAD) { - dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); - /* If the user didn't specify product and/or vendor IDs to match, - * use any IDs from the file suffix for device matching */ - if (match_vendor < 0 && file.idVendor != 0xffff) { - match_vendor = file.idVendor; - printf("Match vendor ID from file: %04x\n", match_vendor); - } - if (match_product < 0 && file.idProduct != 0xffff) { - match_product = file.idProduct; - printf("Match product ID from file: %04x\n", match_product); - } - } - - ret = libusb_init(&ctx); - if (ret) - errx(EX_IOERR, "unable to initialize libusb: %i", ret); - - if (verbose > 2) { - libusb_set_debug(ctx, 255); - } - - probe_devices(ctx); - - if (mode == MODE_LIST) { - list_dfu_interfaces(); - exit(0); - } - - if (dfu_root == NULL) { - errx(EX_IOERR, "No DFU capable USB device available"); - } else if (dfu_root->next != NULL) { - /* We cannot safely support more than one DFU capable device - * with same vendor/product ID, since during DFU we need to do - * a USB bus reset, after which the target device will get a - * new address */ - errx(EX_IOERR, "More than one DFU capable USB device found! " - "Try `--list' and specify the serial number " - "or disconnect all but one device\n"); - } - - /* We have exactly one device. Its libusb_device is now in dfu_root->dev */ - - printf("Opening DFU capable USB device...\n"); - ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); - if (ret || !dfu_root->dev_handle) - errx(EX_IOERR, "Cannot open device"); - - printf("ID %04x:%04x\n", dfu_root->vendor, dfu_root->product); - - printf("Run-time device DFU version %04x\n", - libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); - - /* Transition from run-Time mode to DFU mode */ - if (!(dfu_root->flags & DFU_IFF_DFU)) { - int err; - /* In the 'first round' during runtime mode, there can only be one - * DFU Interface descriptor according to the DFU Spec. */ - - /* FIXME: check if the selected device really has only one */ - - runtime_vendor = dfu_root->vendor; - runtime_product = dfu_root->product; - - printf("Claiming USB DFU Runtime Interface...\n"); - if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "Cannot claim interface %d", - dfu_root->interface); - } - - if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, 0) < 0) { - errx(EX_IOERR, "Cannot set alt interface zero"); - } - - printf("Determining device status: "); - - err = dfu_get_status(dfu_root, &status); - if (err == LIBUSB_ERROR_PIPE) { - printf("Device does not implement get_status, assuming appIDLE\n"); - status.bStatus = DFU_STATUS_OK; - status.bwPollTimeout = 0; - status.bState = DFU_STATE_appIDLE; - status.iString = 0; - } else if (err < 0) { - errx(EX_IOERR, "error get_status"); - } else { - printf("state = %s, status = %d\n", - dfu_state_to_string(status.bState), status.bStatus); - } - milli_sleep(status.bwPollTimeout); - - switch (status.bState) { - case DFU_STATE_appIDLE: - case DFU_STATE_appDETACH: - printf("Device really in Runtime Mode, send DFU " - "detach request...\n"); - if (dfu_detach(dfu_root->dev_handle, - dfu_root->interface, 1000) < 0) { - warnx("error detaching"); - } - if (dfu_root->func_dfu.bmAttributes & USB_DFU_WILL_DETACH) { - printf("Device will detach and reattach...\n"); - } else { - printf("Resetting USB...\n"); - ret = libusb_reset_device(dfu_root->dev_handle); - if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) - errx(EX_IOERR, "error resetting " - "after detach"); - } - break; - case DFU_STATE_dfuERROR: - printf("dfuERROR, clearing status\n"); - if (dfu_clear_status(dfu_root->dev_handle, - dfu_root->interface) < 0) { - errx(EX_IOERR, "error clear_status"); - } - /* fall through */ - default: - warnx("WARNING: Runtime device already in DFU state ?!?"); - libusb_release_interface(dfu_root->dev_handle, - dfu_root->interface); - goto dfustate; - } - libusb_release_interface(dfu_root->dev_handle, - dfu_root->interface); - libusb_close(dfu_root->dev_handle); - dfu_root->dev_handle = NULL; - - if (mode == MODE_DETACH) { - libusb_exit(ctx); - exit(0); - } - - /* keeping handles open might prevent re-enumeration */ - disconnect_devices(); - - milli_sleep(detach_delay * 1000); - - /* Change match vendor and product to impossible values to force - * only DFU mode matches in the following probe */ - match_vendor = match_product = 0x10000; - - probe_devices(ctx); - - if (dfu_root == NULL) { - errx(EX_IOERR, "Lost device after RESET?"); - } else if (dfu_root->next != NULL) { - errx(EX_IOERR, "More than one DFU capable USB device found! " - "Try `--list' and specify the serial number " - "or disconnect all but one device"); - } - - /* Check for DFU mode device */ - if (!(dfu_root->flags | DFU_IFF_DFU)) - errx(EX_SOFTWARE, "Device is not in DFU mode"); - - printf("Opening DFU USB Device...\n"); - ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); - if (ret || !dfu_root->dev_handle) { - errx(EX_IOERR, "Cannot open device"); - } - } else { - /* we're already in DFU mode, so we can skip the detach/reset - * procedure */ - /* If a match vendor/product was specified, use that as the runtime - * vendor/product, otherwise use the DFU mode vendor/product */ - runtime_vendor = match_vendor < 0 ? dfu_root->vendor : match_vendor; - runtime_product = match_product < 0 ? dfu_root->product : match_product; - } - -dfustate: -#if 0 - printf("Setting Configuration %u...\n", dfu_root->configuration); - if (libusb_set_configuration(dfu_root->dev_handle, dfu_root->configuration) < 0) { - errx(EX_IOERR, "Cannot set configuration"); - } -#endif - printf("Claiming USB DFU Interface...\n"); - if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "Cannot claim interface"); - } - - printf("Setting Alternate Setting #%d ...\n", dfu_root->altsetting); - if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, dfu_root->altsetting) < 0) { - errx(EX_IOERR, "Cannot set alternate interface"); - } - -status_again: - printf("Determining device status: "); - if (dfu_get_status(dfu_root, &status ) < 0) { - errx(EX_IOERR, "error get_status"); - } - printf("state = %s, status = %d\n", - dfu_state_to_string(status.bState), status.bStatus); - - milli_sleep(status.bwPollTimeout); - - switch (status.bState) { - case DFU_STATE_appIDLE: - case DFU_STATE_appDETACH: - errx(EX_IOERR, "Device still in Runtime Mode!"); - break; - case DFU_STATE_dfuERROR: - printf("dfuERROR, clearing status\n"); - if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "error clear_status"); - } - goto status_again; - break; - case DFU_STATE_dfuDNLOAD_IDLE: - case DFU_STATE_dfuUPLOAD_IDLE: - printf("aborting previous incomplete transfer\n"); - if (dfu_abort(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "can't send DFU_ABORT"); - } - goto status_again; - break; - case DFU_STATE_dfuIDLE: - printf("dfuIDLE, continuing\n"); - break; - default: - break; - } - - if (DFU_STATUS_OK != status.bStatus ) { - printf("WARNING: DFU Status: '%s'\n", - dfu_status_to_string(status.bStatus)); - /* Clear our status & try again. */ - if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) - errx(EX_IOERR, "USB communication error"); - if (dfu_get_status(dfu_root, &status) < 0) - errx(EX_IOERR, "USB communication error"); - if (DFU_STATUS_OK != status.bStatus) - errx(EX_SOFTWARE, "Status is not OK: %d", status.bStatus); - - milli_sleep(status.bwPollTimeout); - } - - printf("DFU mode device DFU version %04x\n", - libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); - - if (dfu_root->func_dfu.bcdDFUVersion == libusb_cpu_to_le16(0x11a)) - dfuse_device = 1; - - /* If not overridden by the user */ - if (!transfer_size) { - transfer_size = libusb_le16_to_cpu( - dfu_root->func_dfu.wTransferSize); - if (transfer_size) { - printf("Device returned transfer size %i\n", - transfer_size); - } else { - errx(EX_IOERR, "Transfer size must be specified"); - } - } - -#ifdef HAVE_GETPAGESIZE -/* autotools lie when cross-compiling for Windows using mingw32/64 */ -#ifndef __MINGW32__ - /* limitation of Linux usbdevio */ - if ((int)transfer_size > getpagesize()) { - transfer_size = getpagesize(); - printf("Limited transfer size to %i\n", transfer_size); - } -#endif /* __MINGW32__ */ -#endif /* HAVE_GETPAGESIZE */ - - if (transfer_size < dfu_root->bMaxPacketSize0) { - transfer_size = dfu_root->bMaxPacketSize0; - printf("Adjusted transfer size to %i\n", transfer_size); - } - - switch (mode) { - case MODE_UPLOAD: - /* open for "exclusive" writing */ - fd = open(file.name, O_WRONLY | O_BINARY | O_CREAT | O_EXCL | O_TRUNC, 0666); - if (fd < 0) - err(EX_IOERR, "Cannot open file %s for writing", file.name); - - if (dfuse_device || dfuse_options) { - if (dfuse_do_upload(dfu_root, transfer_size, fd, - dfuse_options) < 0) - exit(1); - } else { - if (dfuload_do_upload(dfu_root, transfer_size, - expected_size, fd) < 0) { - exit(1); - } - } - close(fd); - break; - - case MODE_DOWNLOAD: - if (((file.idVendor != 0xffff && file.idVendor != runtime_vendor) || - (file.idProduct != 0xffff && file.idProduct != runtime_product)) && - ((file.idVendor != 0xffff && file.idVendor != dfu_root->vendor) || - (file.idProduct != 0xffff && file.idProduct != dfu_root->product))) { - errx(EX_IOERR, "Error: File ID %04x:%04x does " - "not match device (%04x:%04x or %04x:%04x)", - file.idVendor, file.idProduct, - runtime_vendor, runtime_product, - dfu_root->vendor, dfu_root->product); - } - if (dfuse_device || dfuse_options || file.bcdDFU == 0x11a) { - if (dfuse_do_dnload(dfu_root, transfer_size, &file, - dfuse_options) < 0) - exit(1); - } else { - if (dfuload_do_dnload(dfu_root, transfer_size, &file) < 0) - exit(1); - } - break; - case MODE_DETACH: - if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { - warnx("can't detach"); - } - break; - default: - errx(EX_IOERR, "Unsupported mode: %u", mode); - break; - } - - if (final_reset) { - if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { - /* Even if detach failed, just carry on to leave the - device in a known state */ - warnx("can't detach"); - } - printf("Resetting USB to switch back to runtime mode\n"); - ret = libusb_reset_device(dfu_root->dev_handle); - if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) { - errx(EX_IOERR, "error resetting after download"); - } - } - - libusb_close(dfu_root->dev_handle); - dfu_root->dev_handle = NULL; - libusb_exit(ctx); - - return (0); -} diff --git a/linux/src/dfu-util/src/portable.h b/linux/src/dfu-util/src/portable.h deleted file mode 100644 index cf8d5df38..000000000 --- a/linux/src/dfu-util/src/portable.h +++ /dev/null @@ -1,72 +0,0 @@ - -#ifndef PORTABLE_H -#define PORTABLE_H - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# define PACKAGE "dfu-util" -# define PACKAGE_VERSION "0.8-msvc" -# define PACKAGE_STRING "dfu-util 0.8-msvc" -# define PACKAGE_BUGREPORT "dfu-util@lists.gnumonks.org" -#endif /* HAVE_CONFIG_H */ - -#ifdef HAVE_FTRUNCATE -# include -#else -# include -#endif /* HAVE_FTRUNCATE */ - -#ifdef HAVE_NANOSLEEP -# include -# define milli_sleep(msec) do {\ - if (msec) {\ - struct timespec nanosleepDelay = { (msec) / 1000, ((msec) % 1000) * 1000000 };\ - nanosleep(&nanosleepDelay, NULL);\ - } } while (0) -#elif defined HAVE_WINDOWS_H -# define milli_sleep(msec) do {\ - if (msec) {\ - Sleep(msec);\ - } } while (0) -#else -# error "Can't get no sleep! Please report" -#endif /* HAVE_NANOSLEEP */ - -#ifdef HAVE_ERR -# include -#else -# include -# include -# define warnx(...) do {\ - fprintf(stderr, __VA_ARGS__);\ - fprintf(stderr, "\n"); } while (0) -# define errx(eval, ...) do {\ - warnx(__VA_ARGS__);\ - exit(eval); } while (0) -# define warn(...) do {\ - fprintf(stderr, "%s: ", strerror(errno));\ - warnx(__VA_ARGS__); } while (0) -# define err(eval, ...) do {\ - warn(__VA_ARGS__);\ - exit(eval); } while (0) -#endif /* HAVE_ERR */ - -#ifdef HAVE_SYSEXITS_H -# include -#else -# define EX_OK 0 /* successful termination */ -# define EX_USAGE 64 /* command line usage error */ -# define EX_SOFTWARE 70 /* internal software error */ -# define EX_IOERR 74 /* input/output error */ -#endif /* HAVE_SYSEXITS_H */ - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -#ifndef off_t -# define off_t long int -#endif - -#endif /* PORTABLE_H */ diff --git a/linux/src/dfu-util/src/prefix.c b/linux/src/dfu-util/src/prefix.c deleted file mode 100644 index be8e3faf3..000000000 --- a/linux/src/dfu-util/src/prefix.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * dfu-prefix - * - * Copyright 2011-2012 Stefan Schmidt - * Copyright 2013 Hans Petter Selasky - * Copyright 2014 Uwe Bonnes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" - -enum mode { - MODE_NONE, - MODE_ADD, - MODE_DEL, - MODE_CHECK -}; - -int verbose; - -static void help(void) -{ - fprintf(stderr, "Usage: dfu-prefix [options] ...\n" - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -c --check \t\tCheck DFU prefix of \n" - " -D --delete \t\tDelete DFU prefix from \n" - " -a --add \t\tAdd DFU prefix to \n" - "In combination with -a:\n" - ); - fprintf(stderr, " -s --stellaris-address
Add TI Stellaris address prefix to \n" - "In combination with -D or -c:\n" - " -T --stellaris\t\tAct on TI Stellaris address prefix of \n" - "In combination with -a or -D or -c:\n" - " -L --lpc-prefix\t\tUse NXP LPC DFU prefix format\n" - ); - exit(EX_USAGE); -} - -static void print_version(void) -{ - printf("dfu-prefix (%s) %s\n\n", PACKAGE, PACKAGE_VERSION); - printf("Copyright 2011-2012 Stefan Schmidt, 2014 Uwe Bonnes\n" - "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" - "Please report bugs to %s\n\n", PACKAGE_BUGREPORT); - -} - -static struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'V' }, - { "check", 1, 0, 'c' }, - { "add", 1, 0, 'a' }, - { "delete", 1, 0, 'D' }, - { "stellaris-address", 1, 0, 's' }, - { "stellaris", 0, 0, 'T' }, - { "LPC", 0, 0, 'L' }, -}; -int main(int argc, char **argv) -{ - struct dfu_file file; - enum mode mode = MODE_NONE; - enum prefix_type type = ZERO_PREFIX; - uint32_t lmdfu_flash_address = 0; - char *end; - - /* make sure all prints are flushed */ - setvbuf(stdout, NULL, _IONBF, 0); - - print_version(); - - memset(&file, 0, sizeof(file)); - - while (1) { - int c, option_index = 0; - c = getopt_long(argc, argv, "hVc:a:D:p:v:d:s:TL", opts, - &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - help(); - break; - case 'V': - exit(0); - break; - case 'D': - file.name = optarg; - mode = MODE_DEL; - break; - case 'c': - file.name = optarg; - mode = MODE_CHECK; - break; - case 'a': - file.name = optarg; - mode = MODE_ADD; - break; - case 's': - lmdfu_flash_address = strtoul(optarg, &end, 0); - if (*end) { - errx(EX_IOERR, "Invalid lmdfu " - "address: %s", optarg); - } - /* fall-through */ - case 'T': - type = LMDFU_PREFIX; - break; - case 'L': - type = LPCDFU_UNENCRYPTED_PREFIX; - break; - default: - help(); - break; - } - } - - if (!file.name) { - fprintf(stderr, "You need to specify a filename\n"); - help(); - } - - switch(mode) { - case MODE_ADD: - if (type == ZERO_PREFIX) - errx(EX_IOERR, "Prefix type must be specified"); - dfu_load_file(&file, MAYBE_SUFFIX, NO_PREFIX); - file.lmdfu_address = lmdfu_flash_address; - file.prefix_type = type; - printf("Adding prefix to file\n"); - dfu_store_file(&file, file.size.suffix != 0, 1); - break; - - case MODE_CHECK: - dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); - show_suffix_and_prefix(&file); - if (type > ZERO_PREFIX && file.prefix_type != type) - errx(EX_IOERR, "No prefix of requested type"); - break; - - case MODE_DEL: - dfu_load_file(&file, MAYBE_SUFFIX, NEEDS_PREFIX); - if (type > ZERO_PREFIX && file.prefix_type != type) - errx(EX_IOERR, "No prefix of requested type"); - printf("Removing prefix from file\n"); - /* if there was a suffix, rewrite it */ - dfu_store_file(&file, file.size.suffix != 0, 0); - break; - - default: - help(); - break; - } - return (0); -} diff --git a/linux/src/dfu-util/src/quirks.c b/linux/src/dfu-util/src/quirks.c deleted file mode 100644 index de394a615..000000000 --- a/linux/src/dfu-util/src/quirks.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Simple quirk system for dfu-util - * - * Copyright 2010-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "quirks.h" - -uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice) -{ - uint16_t quirks = 0; - - /* Device returns bogus bwPollTimeout values */ - if ((vendor == VENDOR_OPENMOKO || vendor == VENDOR_FIC) && - product >= PRODUCT_FREERUNNER_FIRST && - product <= PRODUCT_FREERUNNER_LAST) - quirks |= QUIRK_POLLTIMEOUT; - - if (vendor == VENDOR_VOTI && - product == PRODUCT_OPENPCD) - quirks |= QUIRK_POLLTIMEOUT; - - /* Reports wrong DFU version in DFU descriptor */ - if (vendor == VENDOR_LEAFLABS && - product == PRODUCT_MAPLE3 && - bcdDevice == 0x0200) - quirks |= QUIRK_FORCE_DFU11; - - /* old devices(bcdDevice == 0) return bogus bwPollTimeout values */ - if (vendor == VENDOR_SIEMENS && - (product == PRODUCT_PXM40 || product == PRODUCT_PXM50) && - bcdDevice == 0) - quirks |= QUIRK_POLLTIMEOUT; - - /* M-Audio Transit returns bogus bwPollTimeout values */ - if (vendor == VENDOR_MIDIMAN && - product == PRODUCT_TRANSIT) - quirks |= QUIRK_POLLTIMEOUT; - - return (quirks); -} diff --git a/linux/src/dfu-util/src/quirks.h b/linux/src/dfu-util/src/quirks.h deleted file mode 100644 index 0e4b3ec58..000000000 --- a/linux/src/dfu-util/src/quirks.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef DFU_QUIRKS_H -#define DFU_QUIRKS_H - -#define VENDOR_OPENMOKO 0x1d50 /* Openmoko Freerunner / GTA02 */ -#define VENDOR_FIC 0x1457 /* Openmoko Freerunner / GTA02 */ -#define VENDOR_VOTI 0x16c0 /* OpenPCD Reader */ -#define VENDOR_LEAFLABS 0x1eaf /* Maple */ -#define VENDOR_SIEMENS 0x0908 /* Siemens AG */ -#define VENDOR_MIDIMAN 0x0763 /* Midiman */ - -#define PRODUCT_FREERUNNER_FIRST 0x5117 -#define PRODUCT_FREERUNNER_LAST 0x5126 -#define PRODUCT_OPENPCD 0x076b -#define PRODUCT_MAPLE3 0x0003 /* rev 3 and 5 */ -#define PRODUCT_PXM40 0x02c4 /* Siemens AG, PXM 40 */ -#define PRODUCT_PXM50 0x02c5 /* Siemens AG, PXM 50 */ -#define PRODUCT_TRANSIT 0x2806 /* M-Audio Transit (Midiman) */ - -#define QUIRK_POLLTIMEOUT (1<<0) -#define QUIRK_FORCE_DFU11 (1<<1) - -/* Fallback value, works for OpenMoko */ -#define DEFAULT_POLLTIMEOUT 5 - -uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice); - -#endif /* DFU_QUIRKS_H */ diff --git a/linux/src/dfu-util/src/suffix.c b/linux/src/dfu-util/src/suffix.c deleted file mode 100644 index 0df248f51..000000000 --- a/linux/src/dfu-util/src/suffix.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * dfu-suffix - * - * Copyright 2011-2012 Stefan Schmidt - * Copyright 2013 Hans Petter Selasky - * Copyright 2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" - -enum mode { - MODE_NONE, - MODE_ADD, - MODE_DEL, - MODE_CHECK -}; - -int verbose; - -static void help(void) -{ - fprintf(stderr, "Usage: dfu-suffix [options] ...\n" - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -c --check \t\tCheck DFU suffix of \n" - " -a --add \t\tAdd DFU suffix to \n" - " -D --delete \t\tDelete DFU suffix from \n" - " -p --pid \t\tAdd product ID into DFU suffix in \n" - " -v --vid \t\tAdd vendor ID into DFU suffix in \n" - " -d --did \t\tAdd device ID into DFU suffix in \n" - " -S --spec \t\tAdd DFU specification ID into DFU suffix in \n" - ); - exit(EX_USAGE); -} - -static void print_version(void) -{ - printf("dfu-suffix (%s) %s\n\n", PACKAGE, PACKAGE_VERSION); - printf("Copyright 2011-2012 Stefan Schmidt, 2013-2014 Tormod Volden\n" - "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" - "Please report bugs to %s\n\n", PACKAGE_BUGREPORT); - -} - -static struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'V' }, - { "check", 1, 0, 'c' }, - { "add", 1, 0, 'a' }, - { "delete", 1, 0, 'D' }, - { "pid", 1, 0, 'p' }, - { "vid", 1, 0, 'v' }, - { "did", 1, 0, 'd' }, - { "spec", 1, 0, 'S' }, -}; - -int main(int argc, char **argv) -{ - struct dfu_file file; - int pid, vid, did, spec; - enum mode mode = MODE_NONE; - - /* make sure all prints are flushed */ - setvbuf(stdout, NULL, _IONBF, 0); - - print_version(); - - pid = vid = did = 0xffff; - spec = 0x0100; /* Default to bcdDFU version 1.0 */ - memset(&file, 0, sizeof(file)); - - while (1) { - int c, option_index = 0; - c = getopt_long(argc, argv, "hVc:a:D:p:v:d:S:s:T", opts, - &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - help(); - break; - case 'V': - exit(0); - break; - case 'D': - file.name = optarg; - mode = MODE_DEL; - break; - case 'p': - pid = strtol(optarg, NULL, 16); - break; - case 'v': - vid = strtol(optarg, NULL, 16); - break; - case 'd': - did = strtol(optarg, NULL, 16); - break; - case 'S': - spec = strtol(optarg, NULL, 16); - break; - case 'c': - file.name = optarg; - mode = MODE_CHECK; - break; - case 'a': - file.name = optarg; - mode = MODE_ADD; - break; - default: - help(); - break; - } - } - - if (!file.name) { - fprintf(stderr, "You need to specify a filename\n"); - help(); - } - - if (spec != 0x0100 && spec != 0x011a) { - fprintf(stderr, "Only DFU specification 0x0100 and 0x011a supported\n"); - help(); - } - - switch(mode) { - case MODE_ADD: - dfu_load_file(&file, NO_SUFFIX, MAYBE_PREFIX); - file.idVendor = vid; - file.idProduct = pid; - file.bcdDevice = did; - file.bcdDFU = spec; - /* always write suffix, rewrite prefix if there was one */ - dfu_store_file(&file, 1, file.size.prefix != 0); - printf("Suffix successfully added to file\n"); - break; - - case MODE_CHECK: - dfu_load_file(&file, NEEDS_SUFFIX, MAYBE_PREFIX); - show_suffix_and_prefix(&file); - break; - - case MODE_DEL: - dfu_load_file(&file, NEEDS_SUFFIX, MAYBE_PREFIX); - dfu_store_file(&file, 0, file.size.prefix != 0); - if (file.size.suffix) /* had a suffix */ - printf("Suffix successfully removed from file\n"); - break; - - default: - help(); - break; - } - return (0); -} diff --git a/linux/src/dfu-util/src/usb_dfu.h b/linux/src/dfu-util/src/usb_dfu.h deleted file mode 100644 index 660bedcbf..000000000 --- a/linux/src/dfu-util/src/usb_dfu.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef USB_DFU_H -#define USB_DFU_H -/* USB Device Firmware Update Implementation for OpenPCD - * (C) 2006 by Harald Welte - * - * Protocol definitions for USB DFU - * - * This ought to be compliant to the USB DFU Spec 1.0 as available from - * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#define USB_DT_DFU 0x21 - -#ifdef _MSC_VER -# pragma pack(push) -# pragma pack(1) -#endif /* _MSC_VER */ -struct usb_dfu_func_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bmAttributes; -#define USB_DFU_CAN_DOWNLOAD (1 << 0) -#define USB_DFU_CAN_UPLOAD (1 << 1) -#define USB_DFU_MANIFEST_TOL (1 << 2) -#define USB_DFU_WILL_DETACH (1 << 3) - uint16_t wDetachTimeOut; - uint16_t wTransferSize; - uint16_t bcdDFUVersion; -#ifdef _MSC_VER -}; -# pragma pack(pop) -#elif defined __GNUC__ -} __attribute__ ((packed)); -#else - #warning "No way to pack struct on this compiler? This will break!" -#endif /* _MSC_VER */ - -#define USB_DT_DFU_SIZE 9 - -#define USB_TYPE_DFU (LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE) - -/* DFU class-specific requests (Section 3, DFU Rev 1.1) */ -#define USB_REQ_DFU_DETACH 0x00 -#define USB_REQ_DFU_DNLOAD 0x01 -#define USB_REQ_DFU_UPLOAD 0x02 -#define USB_REQ_DFU_GETSTATUS 0x03 -#define USB_REQ_DFU_CLRSTATUS 0x04 -#define USB_REQ_DFU_GETSTATE 0x05 -#define USB_REQ_DFU_ABORT 0x06 - -/* DFU_GETSTATUS bStatus values (Section 6.1.2, DFU Rev 1.1) */ -#define DFU_STATUS_OK 0x00 -#define DFU_STATUS_errTARGET 0x01 -#define DFU_STATUS_errFILE 0x02 -#define DFU_STATUS_errWRITE 0x03 -#define DFU_STATUS_errERASE 0x04 -#define DFU_STATUS_errCHECK_ERASED 0x05 -#define DFU_STATUS_errPROG 0x06 -#define DFU_STATUS_errVERIFY 0x07 -#define DFU_STATUS_errADDRESS 0x08 -#define DFU_STATUS_errNOTDONE 0x09 -#define DFU_STATUS_errFIRMWARE 0x0a -#define DFU_STATUS_errVENDOR 0x0b -#define DFU_STATUS_errUSBR 0x0c -#define DFU_STATUS_errPOR 0x0d -#define DFU_STATUS_errUNKNOWN 0x0e -#define DFU_STATUS_errSTALLEDPKT 0x0f - -enum dfu_state { - DFU_STATE_appIDLE = 0, - DFU_STATE_appDETACH = 1, - DFU_STATE_dfuIDLE = 2, - DFU_STATE_dfuDNLOAD_SYNC = 3, - DFU_STATE_dfuDNBUSY = 4, - DFU_STATE_dfuDNLOAD_IDLE = 5, - DFU_STATE_dfuMANIFEST_SYNC = 6, - DFU_STATE_dfuMANIFEST = 7, - DFU_STATE_dfuMANIFEST_WAIT_RST = 8, - DFU_STATE_dfuUPLOAD_IDLE = 9, - DFU_STATE_dfuERROR = 10 -}; - -#endif /* USB_DFU_H */ diff --git a/linux/src/dfu-util/www/build.html b/linux/src/dfu-util/www/build.html deleted file mode 100644 index f3036e40c..000000000 --- a/linux/src/dfu-util/www/build.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - Building dfu-util from source - - - - - - - - - -
-

How to build dfu-util from source

- -

Prerequisites for building from git

-

Mac OS X

-

-First install MacPorts (and if you are on 10.6 or older, the Java Developer Package) and then run: -

-
-	sudo port install libusb-devel git-core
-
- -

FreeBSD

-
-	sudo pkg_add -r git pkgconf
-
- -

Ubuntu and Debian and derivatives

-
-	sudo apt-get build-dep dfu-util
-	sudo apt-get install libusb-1.0-0-dev
-
- -

Get the source code and build it

-

-The first time you will have to clone the git repository: -

-
-	git clone git://gitorious.org/dfu-util/dfu-util.git
-	cd dfu-util
-
-

-If you later want to update to latest git version, just run this: -

-
-	make maintainer-clean
-	git pull
-
-

-To build the source: -

-
-	./autogen.sh
-	./configure  # on most systems
-	make
-
- -

-If you are building on Mac OS X, replace the ./configure command with: -

-
-	./configure --libdir=/opt/local/lib --includedir=/opt/local/include  # on MacOSX only
-
- -

-Your dfu-util binary will be inside the src folder. Use it from there, or install it to /usr/local/bin by running "sudo make install". -

- -

Cross-building for Windows

- -

-Windows binaries can be built in a MinGW -environment, on a Windows computer or cross-hosted in another OS. -To build it on a Debian or Ubuntu host, first install build dependencies: -

-
-	sudo apt-get build-dep libusb-1.0-0 dfu-util
-	sudo apt-get install mingw32
-
- -

-The below example builds dfu-util 0.8 and libusb 1.0.19 from unpacked release -tarballs. If you instead build from git, you will have to run "./autogen.sh" -before running the "./configure" steps. -

- -
-mkdir -p build
-cd libusb-1.0.19
-PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure \
-    --host=i586-mingw32msvc --prefix=$PWD/../build
-# WINVER workaround needed for 1.0.19 only
-make CFLAGS="-DWINVER=0x0501"
-make install
-cd ..
-
-cd dfu-util-0.8
-PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure \
-    --host=i586-mingw32msvc --prefix=$PWD/../build
-make
-make install
-cd ..
-
-The build files will now be in build/bin. -

- -

Building on Windows using MinGW

-This assumes using release tarballs or having run ./autogen.sh on -the git sources. -
-cd libusb-1.0.19
-./configure --prefix=$HOME
-# WINVER workaround needed for 1.0.19 only
-# MKDIR_P setting should not really be needed...
-make CFLAGS="-DWINVER=0x0501" MKDIR_P="mkdir -p"
-make install
-cd ..
-
-cd dfu-util-0.8
-./configure USB_CFLAGS="-I$HOME/include/libusb-1.0" \
-            USB_LIBS="-L $HOME/lib -lusb-1.0" PKG_CONFIG=true
-make
-make install
-cd ..
-
-To link libusb statically into dfu-util.exe use instead of "make": -
-make LDFLAGS=-static
-
-The built executables (and DLL) will now be under $HOME/bin. - -

-[Back to dfu-util main page] -

- -
- - diff --git a/linux/src/dfu-util/www/dfu-util.1.html b/linux/src/dfu-util/www/dfu-util.1.html deleted file mode 100644 index 62ca40b5d..000000000 --- a/linux/src/dfu-util/www/dfu-util.1.html +++ /dev/null @@ -1,411 +0,0 @@ - - -Man page of DFU-UTIL - - -

DFU-UTIL(1)

- -  -

NAME

- -dfu-util - Device firmware update (DFU) USB programmer -  -

SYNOPSIS

- - -
-
-dfu-util - --l - -[-v] - -[-d - -vid:pid[,vid:pid]] - -[-p - -path] - -[-c - -configuration] - -[-i - -interface] - -[-a - -alt-intf] - -[-S - -serial[,serial]] - - -
-dfu-util - -[-v] - -[-d - -vid:pid[,vid:pid]] - -[-p - -path] - -[-c - -configuration] - -[-i - -interface] - -[-a - -alt-intf] - -[-S - -serial[,serial]] - -[-t - -size] - -[-Z - -size] - -[-s - -address] - -[-R] - -[-D|-U - -file] - - -
-dfu-util - -[-hV] - -
-  -

DESCRIPTION

- -dfu-util - -is a program that implements the host (computer) side of the USB DFU -(Universal Serial Bus Device Firmware Upgrade) protocol. -

-dfu-util communicates with devices that implement the device side of the -USB DFU protocol, and is often used to upgrade the firmware of such -devices. -  -

OPTIONS

- -
-
-l, --list - -
-List the currently attached DFU capable USB devices. -
-d, --device [Run-Time VENDOR]:[Run-Time PRODUCT][,[DFU Mode VENDOR]:[DFU Mode PRODUCT]] - -
-
-Specify run-time and/or DFU mode vendor and/or product IDs of the DFU device -to work with. VENDOR and PRODUCT are hexadecimal numbers (no prefix -needed), "*" (match any), or "-" (match nothing). By default, any DFU capable -device in either run-time or DFU mode will be considered. -

-If you only have one standards-compliant DFU device attached to your computer, -this parameter is optional. However, as soon as you have multiple DFU devices -connected, dfu-util will detect this and abort, asking you to specify which -device to use. -

-If only run-time IDs are specified (e.g. "--device 1457:51ab"), then in -addition to the specified run-time IDs, any DFU mode devices will also be -considered. This is beneficial to allow a DFU capable device to be found -again after a switch to DFU mode, since the vendor and/or product ID of a -device usually changes in DFU mode. -

-If only DFU mode IDs are specified (e.g. "--device ,951:26"), then all -run-time devices will be ignored, making it easy to target a specific device in -DFU mode. -

-If both run-time and DFU mode IDs are specified (e.g. "--device -1457:51ab,:2bc"), then unspecified DFU mode components will use the run-time -value specified. -

-Examples: -

-
--device 1457:51ab,951:26 - -
-
- -Work with a device in run-time mode with -vendor ID 0x1457 and product ID 0x51ab, or in DFU mode with vendor ID 0x0951 -and product ID 0x0026 -

-

--device 1457:51ab,:2bc - -
-
- -Work with a device in run-time mode with vendor ID 0x1457 and product ID -0x51ab, or in DFU mode with vendor ID 0x1457 and product ID 0x02bc -

-

--device 1457:51ab - -
-
- -Work with a device in run-time mode with vendor ID 0x1457 and product ID -0x51ab, or in DFU mode with any vendor and product ID -

-

--device ,951:26 - -
-
- -Work with a device in DFU mode with vendor ID 0x0951 and product ID 0x0026 -

-

--device *,- - -
-
- -Work with any device in run-time mode, and ignore any device in DFU mode -

-

--device , - -
-
- -Ignore any device in run-time mode, and Work with any device in DFU mode -
-
- -
-p, --path BUS-PORT. ... .PORT - -
-Specify the path to the DFU device. -
-c, --cfg CONFIG-NR - -
-Specify the configuration of the DFU device. Note that this is only used for matching, the configuration is not set by dfu-util. -
-i, --intf INTF-NR - -
-Specify the DFU interface number. -
-a, --alt ALT - -
-Specify the altsetting of the DFU interface by name or by number. -
-S, --serial [Run-Time SERIAL][,[DFU Mode SERIAL]] - -
-Specify the run-time and DFU mode serial numbers used to further restrict -device matches. If multiple, identical DFU devices are simultaneously -connected to a system then vendor and product ID will be insufficient for -targeting a single device. In this situation, it may be possible to use this -parameter to specify a serial number which also must match. -

-If only a single serial number is specified, then the same serial number is -used in both run-time and DFU mode. An empty serial number will match any -serial number in the corresponding mode. -

-t, --transfer-size SIZE - -
-Specify the number of bytes per USB transfer. The optimal value is -usually determined automatically so this option is rarely useful. If -you need to use this option for a device, please report it as a bug. -
-Z, --upload-size SIZE - -
-Specify the expected upload size, in bytes. -
-U, --upload FILE - -
-Read firmware from device into -FILE. - -
-D, --download FILE - -
-Write firmware from -FILE - -into device. -
-R, --reset - -
-Issue USB reset signalling after upload or download has finished. -
-s, --dfuse-address address - -
-Specify target address for raw binary download/upload on DfuSe devices. Do -not - -use this for downloading DfuSe (.dfu) files. Modifiers can be added -to the address, separated by a colon, to perform special DfuSE commands such -as "leave" DFU mode, "unprotect" and "mass-erase" flash memory. -
-v, --verbose - -
-Print more information about dfu-util's operation. A second --v - -will turn on verbose logging of USB requests. Repeat this option to further -increase verbosity. -
-h, --help - -
-Show a help text and exit. -
-V, --version - -
-Show version information and exit. -
-  -

EXAMPLES

- -  -

Using dfu-util in the OpenMoko project

- -(with the Neo1973 hardware) -

- -Flashing the rootfs: -
- - $ dfu-util -a rootfs -R -D /path/to/openmoko-devel-image.jffs2 - -

- -Flashing the kernel: -
- - $ dfu-util -a kernel -R -D /path/to/uImage - -

- -Flashing the bootloader: -
- - $ dfu-util -a u-boot -R -D /path/to/u-boot.bin - -

- -Copying a kernel into RAM: -
- - $ dfu-util -a 0 -R -D /path/to/uImage - -

-Once this has finished, the kernel will be available at the default load -address of 0x32000000 in Neo1973 RAM. -Note: - -You cannot transfer more than 2MB of data into RAM using this method. -

-  -

Using dfu-util with a DfuSe device

- -

- -Flashing a -.dfu - -(special DfuSe format) file to the device: -
- - $ dfu-util -a 0 -D /path/to/dfuse-image.dfu - -

- -Reading out 1 KB of flash starting at address 0x8000000: -
- - $ dfu-util -a 0 -s 0x08000000:1024 -U newfile.bin - -

- -Flashing a binary file to address 0x8004000 of device memory and -ask the device to leave DFU mode: -
- - $ dfu-util -a 0 -s 0x08004000:leave -D /path/to/image.bin - - -  -

BUGS

- -Please report any bugs to the dfu-util mailing list at -dfu-util@lists.gnumonks.org. - -Please use the ---verbose option (repeated as necessary) to provide more - -information in your bug report. -  -

SEE ALSO

- -The dfu-util home page is -http://dfu-util.gnumonks.org - -  -

HISTORY

- -dfu-util was originally written for the OpenMoko project by -Weston Schmidt <weston_schmidt@yahoo.com> and -Harald Welte <hwelte@hmw-consulting.de>. Over time, nearly complete -support of DFU 1.0, DFU 1.1 and DfuSe ("1.1a") has been added. -  -

LICENCE

- -dfu-util - -is covered by the GNU General Public License (GPL), version 2 or later. -  -

COPYRIGHT

- -This manual page was originally written by Uwe Hermann <uwe@hermann-uwe.de>, -and is now part of the dfu-util project. -

- -


- 

Index

-
-
NAME
-
SYNOPSIS
-
DESCRIPTION
-
OPTIONS
-
EXAMPLES
-
-
Using dfu-util in the OpenMoko project
-
Using dfu-util with a DfuSe device
-
-
BUGS
-
SEE ALSO
-
HISTORY
-
LICENCE
-
COPYRIGHT
-
-
-This document was created by man2html, -using the doc/dfu-util.1 manual page from dfu-util 0.8.
-Time: 14:40:57 GMT, September 13, 2014 - - diff --git a/linux/src/dfu-util/www/dfuse.html b/linux/src/dfu-util/www/dfuse.html deleted file mode 100644 index 35e4ffa9f..000000000 --- a/linux/src/dfu-util/www/dfuse.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - DfuSe and dfu-util - - - - - - - - - -
-

Using dfu-util with DfuSe devices

-

DfuSe

-

- DfuSe (DFU with ST Microsystems extensions) is a protocol based on - DFU 1.1. However, in expanding the functionality of the DFU protocol, - ST Microsystems broke all compatibility with the DFU 1.1 standard. - DfuSe devices report the DFU version as "1.1a". -

-

- DfuSe can be used to download firmware and other data - from a host computer to a conforming device (or upload in the - opposite direction) over USB similar to standard DFU. -

-

- The main difference from standard DFU is that the target address in - the device (flash) memory is specified by the host, so that a - download can be performed to parts of the device memory. The host - program is also responsible for erasing flash pages before they - are written to. -

-

.dfu files

-

- A special file format is defined by ST Microsystems to carry firmware - for DfuSe devices. The file contains target information such as address - and alternate interface information in addition to the binary data. - Several blocks of binary data can be combined in one .dfu file. -

-

Alternate interfaces

-

- Different memory locations of the device may have different - characteristics that the host program (dfu-util) has to take - into considerations, such as flash memory page size, read-only - versus read-write segments, the need to erase, and so on. - These parameters are reported by the device in the string - descriptors meant for describing the USB interfaces. - The host program decodes these strings to build a memory map of - the device. Different memory units or address spaces are listed - in separate alternate interface settings that must be selected - according to the memory unit to access. -

-

- Note that dfu-util leaves it to the user to select alternate - interface. When parsing a .dfu file it will skip file segments - not matching the selected alternate interface. Also, some - DfuSe device firmware implementations ignore the setting of - alternate interface and deduct the memory unit from the - address, since they have no address space overlap. -

-

DfuSe special commands

-

- DfuSe special commands are used by the host program during normal - downloads or uploads, such as SET_ADDRESS and ERASE_PAGE. Also - the normal DFU_DNLOAD and DFU_UPLOAD commands have special - implementations in DfuSe. - Many DfuSe devices also support commands to leave DFU mode, - read unprotect the flash memory or mass erase the flash memory. - dfu-util (from version 0.7) - supports adding "leave", "unprotect", or "mass-erase" - to the -s option argument to send such requests in combination - with a download request. These modifiers are separated with a colon. -

-

- Some DfuSe devices have their DfuSe bootloader running from flash - memory. Erasing the whole flash memory would therefore destroy - the DfuSe bootloader itself and practically brick the device - for most users. Any use of modifiers such as "unprotect" - and "mass-erase" therefore needs to be combined with the "force" - modifer. This is not included in the examples, to not encourage - ignorant users to copy and paste such instructions and shoot - themselves in the foot. -

-

- Devices based on for instance STM32F103 all run the bootloader - from flash, since there is no USB bootloader in ROM. -

-

- For instance STM32F107, STM32F2xx and STM32F4xx devices have a - DfuSe bootloader in ROM, so the flash can be erased while - keeping the device available for USB DFU transfers as long - as the device designers use this built-in bootloader and have - not implemented another DfuSe bootloader in flash that the user is - dependent upon. -

-

- Well-written bootloaders running from flash will report their - own memory region as read-only and not eraseable, but this does - not prevent dfu-util from sending a "unprotect" or "mass-erase" - request which overrides this, if the user insists. -

-

Example usage

-

- Flashing a .dfu (special DfuSe format) file to the device: -

-
-         $ dfu-util -a 0 -D /path/to/dfuse-image.dfu
-	
-

- Reading out 1 KB of flash starting at address 0x8000000: -

-
-         $ dfu-util -a 0 -s 0x08000000:1024 -U newfile.bin
-	
-

- Flashing a binary file to address 0x8004000 of device memory and ask - the device to leave DFU mode: -

-
-         $ dfu-util -a 0 -s 0x08004000:leave -D /path/to/image.bin
-	
-

- [Back to dfu-util main page] -

- -
- - diff --git a/linux/src/dfu-util/www/index.html b/linux/src/dfu-util/www/index.html deleted file mode 100644 index 108ddaf66..000000000 --- a/linux/src/dfu-util/www/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - dfu-util Homepage - - - - - - - - - -
-

dfu-util - Device Firmware Upgrade Utilities

-

Description

-

- dfu-util is a host side implementation of the DFU 1.0 and DFU 1.1 specifications of the USB forum. - - DFU is intended to download and upload firmware to/from devices connected - over USB. It ranges from small devices like micro-controller boards - to mobile phones. Using dfu-util you can download firmware to your - DFU-enabled device or upload firmware from it. dfu-util has been - tested with the Openmoko Neo1973 and Freerunner and many other devices. -

-

- See the manual page for examples of use. -

-

Supported Devices

- -

Releases

-

- Releases of the dfu-util software can be found in the - releases folder. - The current release is 0.8. -

-

- We offer binaries for Microsoft Windows and some other platforms. - dfu-util uses libusb 1.0 to access your device, so - on Windows you have to register the device with the WinUSB driver - (alternatively libusb-win32 or libusbK), please see the libusbx wiki - for more details. -

-

- Mac OS X users can also get dfu-util from Homebrew with "brew install dfu-util" or from MacPorts. -

-

- Most Linux distributions ship dfu-util in binary packages for those - who do not want to compile dfu-util from source. - On Debian, Ubuntu, Fedora and Gentoo you can install it through the - normal software package tools. For other distributions -(namely OpenSuSe, Mandriva, and CentOS) Holger Freyther was kind enough to -provide binary packages through the Open Build Service. -

-

Development

-

- Development happens in a GIT repository. Browse it via the web -interface or clone it with: -

-
-	git clone git://gitorious.org/dfu-util/dfu-util.git
-	
-

- See our build instructions for how to - build the source on different platforms. -

-

License

-

- This software is licensed under the GPL version 2. -

-

Contact

-

- If you have questions about the development or use of dfu-util please - send an e-mail to our dedicated -mailing list for dfu-util. -

-

People

-

- dfu-util was originally written by - Harald Welte partially based on code from - dfu-programmer 0.4 and is currently maintained by Stefan Schmidt and - Tormod Volden. -

- -
- - diff --git a/linux/src/dfu-util/www/simple.css b/linux/src/dfu-util/www/simple.css deleted file mode 100644 index 98100bc5c..000000000 --- a/linux/src/dfu-util/www/simple.css +++ /dev/null @@ -1,56 +0,0 @@ -body { - margin: 10px; - font-size: 0.82em; - background-color: #EEE; -} - -h1 { - clear: both; - padding: 0 0 12px 0; - margin: 0; - font-size: 2em; - font-weight: bold; -} - -h2 { - clear: both; - margin: 0; - font-size: 1.5em; - font-weight: normal; -} - -h3 { - clear: both; - margin: 15px 0 0 0; - font-size: 1.0em; - font-weight: bold; -} - -p { - line-height: 20px; - padding: 8px 0 8px 0; - margin: 0; - font-size: 1.1em; -} - -pre { - white-space: pre-wrap; - background-color: #CCC; - padding: 3px; -} - -a:hover { - background-color: #DDD; -} - -#middlebox { - width: 600px; - margin: 0px auto; - text-align: left; -} - -#footer { - height: 100px; - padding: 28px 3px 0 0; - margin: 20px 0 20px 0; -} diff --git a/macosx/src/build_dfu-util.sh b/macosx/src/build_dfu-util.sh deleted file mode 100644 index 3563f576c..000000000 --- a/macosx/src/build_dfu-util.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -sudo apt-get build-dep dfu-util -sudo apt-get install build-essentials -sudo apt-get install libusb-1.0-0-dev -sudo apt-get install autoconf automake autotools-dev - -cd dfu-util -./autogen.sh -./configure -make -cp src/dfu-util ../../linux/dfu-util -cp src/dfu-suffix ../../linux/dfu-util -cp src/dfu-prefix ../../linux/dfu-util - diff --git a/macosx/src/dfu-util/AUTHORS b/macosx/src/dfu-util/AUTHORS deleted file mode 100644 index 1b36c739c..000000000 --- a/macosx/src/dfu-util/AUTHORS +++ /dev/null @@ -1,30 +0,0 @@ -Authors ordered by first contribution. - -Harald Welte -Werner Almesberger -Michael Lauer -Jim Huang -Stefan Schmidt -Daniel Willmann -Mike Frysinger -Uwe Hermann -C. Scott Ananian -Bernard Blackham -Holger Freyther -Marc Singer -James Perkins -Tommi Keisala -Pascal Schweizer -Bradley Scott -Uwe Bonnes -Andrey Smirnov -Jussi Timperi -Hans Petter Selasky -Bo Shen -Henrique de Almeida Mendonca -Bernd Krumboeck -Dennis Meier -Veli-Pekka Peltola -Dave Hylands -Michael Grzeschik -Paul Fertser diff --git a/macosx/src/dfu-util/COPYING b/macosx/src/dfu-util/COPYING deleted file mode 100644 index d60c31a97..000000000 --- a/macosx/src/dfu-util/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/macosx/src/dfu-util/ChangeLog b/macosx/src/dfu-util/ChangeLog deleted file mode 100644 index 37f1addba..000000000 --- a/macosx/src/dfu-util/ChangeLog +++ /dev/null @@ -1,93 +0,0 @@ -0.8: - o New, separate dfu-prefix tool (Uwe Bonnes) - o Allow filtering on serial number (Uwe Bonnes) - o Improved VID/PID/serial filtering (Bradley Scott) - o Support reading firmware from stdin (Tormod Volden) - o Warn if missing DFU suffix (Tormod Volden) - o Improved progress bar (Hans Petter Selasky) - o Fix dfuse leave option (Uwe Bonnes) - o Major code rework (Hans Petter Selasky) - o MS Visual Studio build support (Henrique Mendonca) - o dfuse-pack.py tool for .dfu files (Antonio Galeo) - o Many other fixes from many people - -2014-09-13: Tormod Volden - -0.7: - o Support for TI Stellaris devices (Tommi Keisala) - o Fix libusb detection on MacOSX (Marc Singer) - o Fix libusb detection on FreeBSD (Tormod Volden) - o Improved DfuSe support (Tormod Volden) - o Support all special commands (leave, unprotect, mass-erase) - o Arbitrary upload lengths - o "force" option for various possible (dangerous) overrides - -2012-10-07: Tormod Volden - -0.6: - o Add detach mode (Stefan Schmidt) - o Check return value on all libusb calls (Tormod Volden) - o Fix segmentation fault with -s option (Tormod Volden) - o Add DFU suffix manipulation tool (Stefan Schmidt) - o Port to Windows: (Tormod Volden, some parts based on work from Satz - Klauer) - o Port file handling to stdio streams - o Sleep() macros - o C99 types - o Pack structs - o Detect DfuSe device correctly on big-endian architectures (Tormod - Volden) - o Add dfuse progress indication on download (Tormod Volden) - o Cleanup: gcc pedantic, gcc extension, ... (Tormod Volden) - o Rely on page size from functional descriptor. Please report if you get - an error about it. (Tormod Volden) - o Add quirk for Maple since it reports wrong DFU version (Tormod Volden) - -2012-04-22: Stefan Schmidt - -0.5: - o DfuSe extension support for ST devices (Tormod Volden) - o Add initial support for bitWillDetach flag from DFU 1.1 (Tormod - Volden) - o Internal cleanup and some manual page fixes (Tormod Volden) - -2011-11-02: Stefan Schmidt - -0.4: - o Rework to use libusb-1.0 (Stefan Schmidt) - o DFU suffix support (Tormod Volden, Stefan Schmidt) - o Sspeed up DFU downloads directly into memory (Bernard Blackham) - o More flexible -d vid:pid parsing (Tormod Volden) - o Many bug fixes and cleanups - -2011-07-20: Stefan Schmidt - -0.3: - o quirks: Add OpenOCD to the poll timeout quirk table. - -2010-12-22: Stefan Schmidt - -0.2: - o Fix some typos on the website and the README (Antonio Ospite, Uwe - Hermann) - o Remove build rule for a static binary. We can use autotools for this. - (Mike Frysinger) - o Fix infinite loop in download error path (C. Scott Ananian) - o Break out to show the 'finished' in upload (C. Scott Ananian) - o Add GPLv2+ headers (Harald Welte) - o Remove dead code (commands.[ch]) remnescent of dfu-programmer (Harald - Welte) - o Simple quirk system with Openmoko quirk for missing bwPollTimeout (Tormod Volden) - o New default (1024) and clamping of transfer size (Tormod Volden) - o Verify sending of completion packet (Tormod Volden) - o Look for DFU functional descriptor among all descriptors (Tormod - Volden) - o Print out in which direction we are transferring data - o Abort in upload if the file already exists - -2010-11-17 Stefan Schmidt - -0.1: - Initial release - -2010-05-23 Stefan Schmidt diff --git a/macosx/src/dfu-util/DEVICES.txt b/macosx/src/dfu-util/DEVICES.txt deleted file mode 100644 index bdd9f1f2e..000000000 --- a/macosx/src/dfu-util/DEVICES.txt +++ /dev/null @@ -1,20 +0,0 @@ -List of supported software and hardware products: - -Software user (bootloader, etc) -------------------------------- -- Sam7DFU: http://www.openpcd.org/Sam7dfu -- U-boot: DFU patches -- Barebox: http://www.barebox.org/ -- Leaflabs: http://code.google.com/p/leaflabs/ -- Blackmagic DFU - -Products using DFU ------------------- -- OpenPCD (sam7dfu) -- Openmoko Neo 1973 and Freerunner (u-boot with DFU patches) -- Leaflabs Maple -- ATUSB from Qi Hardware -- STM32F105/7, STM32F2/F3/F4 in System Bootloader -- Blackmagic debug probe -- NXP LPC31xx/LPC43XX, e.g. LPC-Link and LPC-Link2, need binaries - with LPC prefix and encoding (LPC-Link) diff --git a/macosx/src/dfu-util/Makefile.am b/macosx/src/dfu-util/Makefile.am deleted file mode 100644 index 641dda58a..000000000 --- a/macosx/src/dfu-util/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -SUBDIRS = src doc - -EXTRA_DIST = autogen.sh TODO DEVICES.txt dfuse-pack.py diff --git a/macosx/src/dfu-util/README b/macosx/src/dfu-util/README deleted file mode 100644 index 0f8f2621a..000000000 --- a/macosx/src/dfu-util/README +++ /dev/null @@ -1,20 +0,0 @@ -Dfu-util - Device Firmware Upgrade Utilities - -Dfu-util is the host side implementation of the DFU 1.0 [1] and DFU 1.1 [2] -specification of the USB forum. - -DFU is intended to download and upload firmware to devices connected over -USB. It ranges from small devices like micro-controller boards up to mobile -phones. With dfu-util you are able to download firmware to your device or -upload firmware from it. - -dfu-util has been tested with Openmoko Neo1973 and Freerunner and many -other devices. - -[1] DFU 1.0 spec: http://www.usb.org/developers/devclass_docs/usbdfu10.pdf -[2] DFU 1.1 spec: http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf - -The official website is: - - http://dfu-util.gnumonks.org/ - diff --git a/macosx/src/dfu-util/TODO b/macosx/src/dfu-util/TODO deleted file mode 100644 index 900c30c29..000000000 --- a/macosx/src/dfu-util/TODO +++ /dev/null @@ -1,14 +0,0 @@ -DfuSe: -- Do erase and write in two separate passes when downloading -- Skip "Set Address" command when downloading contiguous blocks -- Implement "Get Commands" command - -Devices: -- Research iPhone/iPod/iPad support - Heavily modified dfu-util fork here: - https://github.com/planetbeing/xpwn/tree/master/dfu-util -- Test against Niftylights - -Non-Code: -- Logo -- Re-License as LGPL for usage as library? diff --git a/macosx/src/dfu-util/autogen.sh b/macosx/src/dfu-util/autogen.sh deleted file mode 100644 index e67aed39a..000000000 --- a/macosx/src/dfu-util/autogen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -autoreconf -v -i diff --git a/macosx/src/dfu-util/configure.ac b/macosx/src/dfu-util/configure.ac deleted file mode 100644 index 86221143f..000000000 --- a/macosx/src/dfu-util/configure.ac +++ /dev/null @@ -1,41 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.59) -AC_INIT([dfu-util],[0.8],[dfu-util@lists.gnumonks.org],,[http://dfu-util.gnumonks.org]) -AC_CONFIG_AUX_DIR(m4) -AM_INIT_AUTOMAKE([foreign]) -AC_CONFIG_HEADERS([config.h]) - -# Test for new silent rules and enable only if they are available -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -# Checks for programs. -AC_PROG_CC - -# Checks for libraries. -# On FreeBSD the libusb-1.0 is called libusb and resides in system location -AC_CHECK_LIB([usb], [libusb_init],, [native_libusb=no],) -AS_IF([test x$native_libusb = xno], [ - PKG_CHECK_MODULES([USB], [libusb-1.0 >= 1.0.0],, - AC_MSG_ERROR([*** Required libusb-1.0 >= 1.0.0 not installed ***])) -]) -AC_CHECK_LIB([usbpath],[usb_path2devnum],,,-lusb) - -LIBS="$LIBS $USB_LIBS" -CFLAGS="$CFLAGS $USB_CFLAGS" - -# Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS([usbpath.h windows.h sysexits.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_TYPE_SIZE_T - -# Checks for library functions. -AC_FUNC_MEMCMP -AC_CHECK_FUNCS([ftruncate getpagesize nanosleep err]) - -AC_CONFIG_FILES(Makefile src/Makefile doc/Makefile) -AC_OUTPUT diff --git a/macosx/src/dfu-util/device-logs/README b/macosx/src/dfu-util/device-logs/README deleted file mode 100644 index 00d3d1a96..000000000 --- a/macosx/src/dfu-util/device-logs/README +++ /dev/null @@ -1,77 +0,0 @@ -Device: -------- -qi-hardware-atusb: -- Qi Hardware ben-wpan -- DFU implementation: - http://projects.qi-hardware.com/index.php/p/ben-wpan/source/tree/master/atusb/fw/usb -- Tester: Stefan Schmidt - -openpcd: -- OpenPCD RFID reader -- DFU implementation: SAM7DFU - http://www.openpcd.org/Sam7dfu, git://git.gnumonks.org/openpcd.git -- Tester: Stefan Schmidt - -simtrace: -- Sysmocom SimTrace -- DFU implementation: SAM7DFU - http://www.openpcd.org/Sam7dfu, git://git.gnumonks.org/openpcd.git -- Tester: Stefan Schmidt - -openmoko-freerunner: -- Openmoko Freerunner -- DFU implementation: Old U-Boot - http://git.openmoko.org/?p=u-boot.git;a=shortlog;h=refs/heads/mokopatches -- Tester: Stefan Schmidt - -openmoko-neo1973: -- Openmoko Neo1073 -- DFU implementation: Old U-Boot - http://git.openmoko.org/?p=u-boot.git;a=shortlog;h=refs/heads/mokopatches -- Tester: Stefan Schmidt - -tdk-bluetooth: -- TDK Corp. Bluetooth Adapter -- DFU implementation: closed soure -- Only upload has been tested -- Tester: Stefan Schmidt - -stm32f107: -- STM32 microcontrollers with built-in (ROM) DFU loader -- DFU implementation: Closed source but probably similar to the one - in their USB device libraries. Some relevant application notes: - http://www.st.com -> AN3156 and AN2606 -- Tested by Uwe Bonnes - -stm32f4discovery: -- STM32 microcontroller board with built-in (ROM) DFU loader -- DFU implementation: Closed source, probably similar to stm32f107. -- Tested by Joe Rothweiler - -dso-nano: -- DSO Nano pocket oscilloscope -- DFU implementation: Based on ST Microelectronics USB FS Library 1.0 - http://dsonano.googlecode.com/files/DS0201_OpenSource.rar -- Tester: Tormod Volden - -opc-20: -- Custom devices based on STM32F1xx -- DFU implementation: ST Microelectronics USB FS Device Library 3.1.0 - http://www.st.com -> um0424.zip -- Tester: Tormod Volden - -lpc-link, lpclink2: -- NXP LPCXpresso debug adapters -- Proprietary DFU implementation, uses special download files with - LPC prefix and encoding of the target firmware code -- Tested by Uwe Bonnes - -Adding the lsusb output and a download log of your device here helps -us to avoid regressions for hardware we cannot test while working on -the code. To extract the lsusb output use this command: -sudo lsusb -v -d $USBID > $DEVICE.lsusb -Prepare a description snippet as above, and send it to us. A log -(copy-paste of the command window) of a firmware download is also -nice, please use the double verbose option -v -v and include the -command line in the log file. - diff --git a/macosx/src/dfu-util/device-logs/dsonano.lsusb b/macosx/src/dfu-util/device-logs/dsonano.lsusb deleted file mode 100644 index 140a7bc6c..000000000 --- a/macosx/src/dfu-util/device-logs/dsonano.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 002 Device 004: ID 0483:df11 SGS Thomson Microelectronics -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 - bcdDevice 1.1a - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 DFU - iSerial 3 001 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 64mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 4 @Internal Flash /0x08000000/12*001Ka,116*001Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 5 @SPI Flash : M25P64/0x00000000/64*064Kg,64*064Kg - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 1024 bytes - bcdDFUVersion 1.1a -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/lpclink.log b/macosx/src/dfu-util/device-logs/lpclink.log deleted file mode 100644 index 7de4dd3e6..000000000 --- a/macosx/src/dfu-util/device-logs/lpclink.log +++ /dev/null @@ -1,59 +0,0 @@ -(The on-board LPC3154 has some encryption key set and LPCXpressoWIN.enc -is encrypted.) - -$ lsusb | grep NXP -Bus 003 Device 011: ID 0471:df55 Philips (or NXP) LPCXpresso LPC-Link - -$ dfu-util -v -v -v -R -D /opt/lpc/lpcxpresso/bin/LPCXpressoWIN.enc - -dfu-util 0.7 - -Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc. -Copyright 2010-2012 Tormod Volden and Stefan Schmidt -This program is Free Software and has ABSOLUTELY NO WARRANTY -Please report bugs to dfu-util@lists.gnumonks.org - -dfu-util: Invalid DFU suffix signature -dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! -Deducing device DFU version from functional descriptor length -Opening DFU capable USB device... -ID 0471:df55 -Run-time device DFU version 0100 -Claiming USB DFU Runtime Interface... -Determining device status: -state = dfuIDLE, status = 0 -dfu-util: WARNING: Runtime device already in DFU state ?!? -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: -state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 0100 -Device returned transfer size 2048 -Copying data from PC to DFU device -Download [ ] 0% 0 bytes -Download [= ] 6% 2048 bytes -Download [=== ] 13% 4096 bytes -Download [==== ] 19% 6144 bytes -Download [====== ] 26% 8192 bytes -Download [======== ] 32% 10240 bytes -Download [========= ] 39% 12288 bytes -Download [=========== ] 45% 14336 bytes -Download [============= ] 52% 16384 bytes -Download [============== ] 59% 18432 bytes -Download [================ ] 65% 20480 bytes -Download [================== ] 72% 22528 bytes -Download [=================== ] 78% 24576 bytes -Download [===================== ] 85% 26624 bytes -Download [====================== ] 91% 28672 bytes -Download [======================== ] 98% 29192 bytes -Download [=========================] 100% 29192 bytes -Download done. -Sent a total of 29192 bytes -state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present -Done! -dfu-util: can't detach -Resetting USB to switch back to runtime mode - -$ lsusb | grep NXP -Bus 003 Device 012: ID 1fc9:0009 NXP Semiconductors diff --git a/macosx/src/dfu-util/device-logs/lpclink.lsusb b/macosx/src/dfu-util/device-logs/lpclink.lsusb deleted file mode 100644 index 867b2a2c5..000000000 --- a/macosx/src/dfu-util/device-logs/lpclink.lsusb +++ /dev/null @@ -1,58 +0,0 @@ - -Bus 003 Device 008: ID 0471:df55 Philips (or NXP) LPCXpresso LPC-Link -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0471 Philips (or NXP) - idProduct 0xdf55 LPCXpresso LPC-Link - bcdDevice 0.01 - iManufacturer 0 - iProduct 0 - iSerial 0 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 25 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 0 - Device Firmware Upgrade Interface Descriptor: - bLength 7 - bDescriptorType 33 - bmAttributes 1 - Will Not Detach - Manifestation Intolerant - Upload Unsupported - Download Supported - wDetachTimeout 65535 milliseconds - wTransferSize 2048 bytes -Device Qualifier (for other device speed): - bLength 10 - bDescriptorType 6 - bcdUSB 2.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - bNumConfigurations 1 -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/lpclink2.log b/macosx/src/dfu-util/device-logs/lpclink2.log deleted file mode 100644 index 4681eff7d..000000000 --- a/macosx/src/dfu-util/device-logs/lpclink2.log +++ /dev/null @@ -1,59 +0,0 @@ -$ lsusb | grep NXP -Bus 003 Device 013: ID 1fc9:000c NXP Semiconductors - -$ dfu-util -D ~/devel/dfu-util/firmware.bin.qthdr - -dfu-util 0.7 - -Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc. -Copyright 2010-2012 Tormod Volden and Stefan Schmidt -This program is Free Software and has ABSOLUTELY NO WARRANTY -Please report bugs to dfu-util@lists.gnumonks.org - -dfu-util: Invalid DFU suffix signature -dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! -Possible unencryptes NXP LPC DFU prefix with the following properties -Payload length: 39 kiByte -Opening DFU capable USB device... -ID 1fc9:000c -Run-time device DFU version 0100 -Claiming USB DFU Runtime Interface... -Determining device status: -state = dfuIDLE, status = 0 -dfu-util: WARNING: Runtime device already in DFU state ?!? -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: -state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 0100 -Device returned transfer size 2048 -Copying data from PC to DFU device -Download [ ] 0% 0 bytes -Download [= ] 4% 2048 bytes -Download [== ] 9% 4096 bytes -Download [=== ] 14% 6144 bytes -Download [==== ] 19% 8192 bytes -Download [====== ] 24% 10240 bytes -Download [======= ] 28% 12288 bytes -Download [======== ] 33% 14336 bytes -Download [========= ] 38% 16384 bytes -Download [========== ] 43% 18432 bytes -Download [============ ] 48% 20480 bytes -Download [============= ] 53% 22528 bytes -Download [============== ] 57% 24576 bytes -Download [=============== ] 62% 26624 bytes -Download [================ ] 67% 28672 bytes -Download [================== ] 72% 30720 bytes -Download [=================== ] 77% 32768 bytes -Download [==================== ] 82% 34816 bytes -Download [===================== ] 86% 36864 bytes -Download [====================== ] 91% 38912 bytes -Download [======================== ] 96% 40356 bytes -Download [=========================] 100% 40356 bytes -Download done. -Sent a total of 40356 bytes -dfu-util: unable to read DFU status - -$ lsusb | grep NXP -Bus 003 Device 014: ID 1fc9:0018 NXP Semiconductors diff --git a/macosx/src/dfu-util/device-logs/lpclink2.lsusb b/macosx/src/dfu-util/device-logs/lpclink2.lsusb deleted file mode 100644 index b833fca77..000000000 --- a/macosx/src/dfu-util/device-logs/lpclink2.lsusb +++ /dev/null @@ -1,203 +0,0 @@ - -Bus 003 Device 007: ID 0c72:000c PEAK System PCAN-USB -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x0c72 PEAK System - idProduct 0x000c PCAN-USB - bcdDevice 1c.ff - iManufacturer 0 - iProduct 3 VER1:PEAK -VER2:02.8.01 -DAT :06.05.2004 -TIME:09:35:37 - ... - iSerial 0 - bNumConfigurations 3 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 46 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 4 - bInterfaceClass 0 (Defined at Interface level) - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x01 EP 1 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 46 - bNumInterfaces 1 - bConfigurationValue 2 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 394mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 4 - bInterfaceClass 0 (Defined at Interface level) - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x01 EP 1 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 20 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 46 - bNumInterfaces 1 - bConfigurationValue 3 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 4 - bInterfaceClass 0 (Defined at Interface level) - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x01 EP 1 OUT - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 -Device Status: 0x0001 - Self Powered diff --git a/macosx/src/dfu-util/device-logs/opc-20.lsusb b/macosx/src/dfu-util/device-logs/opc-20.lsusb deleted file mode 100644 index 580df90e5..000000000 --- a/macosx/src/dfu-util/device-logs/opc-20.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 001 Device 004: ID 0483:df11 SGS Thomson Microelectronics -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 - bcdDevice 2.00 - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 DFU - iSerial 3 ������������ - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/12*001Ka,116*001Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @SPI Flash : M25P64/0x00000000/128*64Kg - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 1024 bytes - bcdDFUVersion 1a.01 -Device Status: 0x0001 - Self Powered diff --git a/macosx/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb b/macosx/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb deleted file mode 100644 index 4c0abfb06..000000000 --- a/macosx/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb +++ /dev/null @@ -1,109 +0,0 @@ -Bus 003 Device 017: ID 1d50:5119 OpenMoko, Inc. GTA01/GTA02 U-Boot Bootloader -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x1d50 OpenMoko, Inc. - idProduct 0x5119 GTA01/GTA02 U-Boot Bootloader - bcdDevice 0.00 - iManufacturer 1 OpenMoko, Inc - iProduct 2 Neo1973 Bootloader U-Boot 1.3.2-moko12 - iSerial 3 0000000 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 81 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 7 USB Device Firmware Upgrade - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 8 RAM 0x32000000 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 9 u-boot - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 2 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 10 u-boot_env - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 3 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 11 kernel - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 4 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 12 splash - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 5 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 13 factory - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 6 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 14 rootfs - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 4096 bytes - bcdDFUVersion 1.00 -Device Status: 0x0a00 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/openmoko-freerunner.lsusb b/macosx/src/dfu-util/device-logs/openmoko-freerunner.lsusb deleted file mode 100644 index 835708dd8..000000000 --- a/macosx/src/dfu-util/device-logs/openmoko-freerunner.lsusb +++ /dev/null @@ -1,179 +0,0 @@ -Bus 005 Device 033: ID 1d50:5119 OpenMoko, Inc. GTA01/GTA02 U-Boot Bootloader -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.10 - bDeviceClass 2 Communications - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x1d50 OpenMoko, Inc. - idProduct 0x5119 GTA01/GTA02 U-Boot Bootloader - bcdDevice 0.00 - iManufacturer 1 OpenMoko, Inc - iProduct 2 Neo1973 Bootloader U-Boot 1.3.2-moko12 - iSerial 3 0000000 - bNumConfigurations 2 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 85 - bNumInterfaces 3 - bConfigurationValue 1 - iConfiguration 4 TTY via USB - bmAttributes 0x80 - (Bus Powered) - MaxPower 500mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 Control Interface - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 Bulk Data Interface - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 2 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 1 - iInterface 7 USB Device Firmware Upgrade - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 4096 bytes - bcdDFUVersion 1.00 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 67 - bNumInterfaces 2 - bConfigurationValue 2 - iConfiguration 4 TTY via USB - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 Control Interface - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 Bulk Data Interface - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 -Device Status: 0x9a00 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/openmoko-neo1973.lsusb b/macosx/src/dfu-util/device-logs/openmoko-neo1973.lsusb deleted file mode 100644 index 07789506a..000000000 --- a/macosx/src/dfu-util/device-logs/openmoko-neo1973.lsusb +++ /dev/null @@ -1,182 +0,0 @@ - -Bus 006 Device 020: ID 1457:5119 First International Computer, Inc. OpenMoko Neo1973 u-boot cdc_acm serial port -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.10 - bDeviceClass 2 Communications - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 16 - idVendor 0x1457 First International Computer, Inc. - idProduct 0x5119 OpenMoko Neo1973 u-boot cdc_acm serial port - bcdDevice 0.00 - iManufacturer 1 - iProduct 2 - iSerial 3 - bNumConfigurations 2 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 85 - bNumInterfaces 3 - bConfigurationValue 1 - iConfiguration 4 - bmAttributes 0x80 - (Bus Powered) - MaxPower 500mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 2 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 1 - iInterface 7 - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 4096 bytes - bcdDFUVersion 1.00 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 67 - bNumInterfaces 2 - bConfigurationValue 2 - iConfiguration 4 - bmAttributes 0x80 - (Bus Powered) - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 2 Communications - bInterfaceSubClass 2 Abstract (modem) - bInterfaceProtocol 1 AT-commands (v.25ter) - iInterface 6 - CDC Header: - bcdCDC 0.6e - CDC Call Management: - bmCapabilities 0x00 - bDataInterface 1 - CDC ACM: - bmCapabilities 0x00 - CDC Union: - bMasterInterface 0 - bSlaveInterface 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 10 CDC Data - bInterfaceSubClass 0 Unused - bInterfaceProtocol 0 - iInterface 5 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 255 -Device Status: 0x0006 - (Bus Powered) - Remote Wakeup Enabled - Test Mode diff --git a/macosx/src/dfu-util/device-logs/openpcd.lsusb b/macosx/src/dfu-util/device-logs/openpcd.lsusb deleted file mode 100644 index f6255a943..000000000 --- a/macosx/src/dfu-util/device-logs/openpcd.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 006 Device 016: ID 16c0:076b VOTI OpenPCD 13.56MHz RFID Reader -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 8 - idVendor 0x16c0 VOTI - idProduct 0x076b OpenPCD 13.56MHz RFID Reader - bcdDevice 0.00 - iManufacturer 1 - iProduct 2 OpenPCD RFID Simulator - DFU Mode - iSerial 0 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 0 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 0 - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 3 - Will Not Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 256 bytes - bcdDFUVersion 1.00 -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/qi-hardware-atusb.lsusb b/macosx/src/dfu-util/device-logs/qi-hardware-atusb.lsusb deleted file mode 100644 index bfc1701e1..000000000 --- a/macosx/src/dfu-util/device-logs/qi-hardware-atusb.lsusb +++ /dev/null @@ -1,59 +0,0 @@ - -Bus 006 Device 013: ID 20b7:1540 Qi Hardware ben-wpan, AT86RF230-based -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 255 Vendor Specific Class - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x20b7 Qi Hardware - idProduct 0x1540 ben-wpan, AT86RF230-based - bcdDevice 0.01 - iManufacturer 0 - iProduct 0 - iSerial 1 4630333438371508231a - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 34 - bNumInterfaces 2 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 40mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 1 - bInterfaceClass 255 Vendor Specific Class - bInterfaceSubClass 0 - bInterfaceProtocol 0 - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 0 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 1 - iInterface 0 -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/simtrace.lsusb b/macosx/src/dfu-util/device-logs/simtrace.lsusb deleted file mode 100644 index 578ddf0e1..000000000 --- a/macosx/src/dfu-util/device-logs/simtrace.lsusb +++ /dev/null @@ -1,70 +0,0 @@ - -Bus 006 Device 017: ID 16c0:0762 VOTI -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 8 - idVendor 0x16c0 VOTI - idProduct 0x0762 - bcdDevice 0.00 - iManufacturer 1 sysmocom - systems for mobile communications GmbH - iProduct 2 SimTrace SIM Sniffer - DFU Mode - iSerial 0 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 45 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 3 SimTrace DFU Configuration - bmAttributes 0x80 - (Bus Powered) - MaxPower 200mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 SimTrace DFU Interface - Application Partition - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 SimTrace DFU Interface - Bootloader Partition - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 2 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 6 SimTrace DFU Interface - RAM - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 3 - Will Not Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 65280 milliseconds - wTransferSize 256 bytes - bcdDFUVersion 1.00 -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/sparkcore.lsusb b/macosx/src/dfu-util/device-logs/sparkcore.lsusb deleted file mode 100644 index b6029ffa5..000000000 --- a/macosx/src/dfu-util/device-logs/sparkcore.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 001 Device 008: ID 1d50:607f OpenMoko, Inc. -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x1d50 OpenMoko, Inc. - idProduct 0x607f - bcdDevice 2.00 - iManufacturer 1 Spark Devices - iProduct 2 CORE DFU - iSerial 3 8D80527B5055 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/20*001Ka,108*001Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @SPI Flash : SST25x/0x00000000/512*04Kg - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 1024 bytes - bcdDFUVersion 1.1a -Device Status: 0x0001 - Self Powered diff --git a/macosx/src/dfu-util/device-logs/stm32f107.bin-download b/macosx/src/dfu-util/device-logs/stm32f107.bin-download deleted file mode 100644 index 45b714f83..000000000 --- a/macosx/src/dfu-util/device-logs/stm32f107.bin-download +++ /dev/null @@ -1,48 +0,0 @@ -> src/dfu-util --intf 0 --alt 0 -v -v -v -s 0x8000000 -D test3 -dfu-util 0.4 - -(C) 2005-2008 by Weston Schmidt, Harald Welte and OpenMoko Inc. -(C) 2010-2011 Tormod Volden (DfuSe support) -This program is Free Software and has ABSOLUTELY NO WARRANTY - -dfu-util does currently only support DFU version 1.0 - -Opening DFU USB device... ID 0483:df11 -Run-time device DFU version 011a -Found DFU: [0483:df11] devnum=0, cfg=1, intf=0, alt=0, name="@Internal Flash /0x08000000/128*002Kg" -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 011a -Device returned transfer size 2048 -No valid DFU suffix signature -Warning: File has no DFU suffix -DfuSe interface name: "Internal Flash " -Memory segment at 0x08000000 128 x 2048 = 262144 (rew) -Uploading to address = 0x08000000, size = 16384 -Erasing page size 2048 at address 0x08000000, page starting at 0x08000000 - Download from image offset 00000000 to memory 08000000-080007ff, size 2048 - Setting address pointer to 0x08000000 -Erasing page size 2048 at address 0x08000800, page starting at 0x08000800 - Download from image offset 00000800 to memory 08000800-08000fff, size 2048 - Setting address pointer to 0x08000800 -Erasing page size 2048 at address 0x08001000, page starting at 0x08001000 - Download from image offset 00001000 to memory 08001000-080017ff, size 2048 - Setting address pointer to 0x08001000 -Erasing page size 2048 at address 0x08001800, page starting at 0x08001800 - Download from image offset 00001800 to memory 08001800-08001fff, size 2048 - Setting address pointer to 0x08001800 -Erasing page size 2048 at address 0x08002000, page starting at 0x08002000 - Download from image offset 00002000 to memory 08002000-080027ff, size 2048 - Setting address pointer to 0x08002000 -Erasing page size 2048 at address 0x08002800, page starting at 0x08002800 - Download from image offset 00002800 to memory 08002800-08002fff, size 2048 - Setting address pointer to 0x08002800 -Erasing page size 2048 at address 0x08003000, page starting at 0x08003000 - Download from image offset 00003000 to memory 08003000-080037ff, size 2048 - Setting address pointer to 0x08003000 -Erasing page size 2048 at address 0x08003800, page starting at 0x08003800 - Download from image offset 00003800 to memory 08003800-08003fff, size 2048 - Setting address pointer to 0x08003800 - diff --git a/macosx/src/dfu-util/device-logs/stm32f107.lsusb b/macosx/src/dfu-util/device-logs/stm32f107.lsusb deleted file mode 100644 index 14b45cda0..000000000 --- a/macosx/src/dfu-util/device-logs/stm32f107.lsusb +++ /dev/null @@ -1,60 +0,0 @@ - -Bus 001 Device 028: ID 0483:df11 SGS Thomson Microelectronics STM Device in DFU Mode -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 STM Device in DFU Mode - bcdDevice 20.00 - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 0x418 DFU Bootloader - iSerial 3 STM32 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 36 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/128*002Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @Option Bytes /0x1FFFF800/01*016 g - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 2048 bytes - bcdDFUVersion 1.1a -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/device-logs/stm32f4discovery.bin-download b/macosx/src/dfu-util/device-logs/stm32f4discovery.bin-download deleted file mode 100644 index 96e172216..000000000 --- a/macosx/src/dfu-util/device-logs/stm32f4discovery.bin-download +++ /dev/null @@ -1,36 +0,0 @@ -dfu-util --device 0483:df11 --alt 0 \ - --dfuse-address 0x08000000 \ - -v -v -v \ - --download arm/iotoggle.bin -No valid DFU suffix signature -Warning: File has no DFU suffix -dfu-util 0.5 - -(C) 2005-2008 by Weston Schmidt, Harald Welte and OpenMoko Inc. -(C) 2010-2011 Tormod Volden (DfuSe support) -This program is Free Software and has ABSOLUTELY NO WARRANTY - -dfu-util does currently only support DFU version 1.0 - -Filter on vendor = 0x0483 product = 0xdf11 -Opening DFU capable USB device... ID 0483:df11 -Run-time device DFU version 011a -Found DFU: [0483:df11] devnum=0, cfg=1, intf=0, alt=0, name="@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" -Claiming USB DFU Interface... -Setting Alternate Setting #0 ... -Determining device status: state = dfuERROR, status = 10 -dfuERROR, clearing status -Determining device status: state = dfuIDLE, status = 0 -dfuIDLE, continuing -DFU mode device DFU version 011a -Device returned transfer size 2048 -DfuSe interface name: "Internal Flash " -Memory segment at 0x08000000 4 x 16384 = 65536 (rew) -Memory segment at 0x08010000 1 x 65536 = 65536 (rew) -Memory segment at 0x08020000 7 x 131072 = 917504 (rew) -Uploading to address = 0x08000000, size = 2308 -Erasing page size 16384 at address 0x08000000, page starting at 0x08000000 - Download from image offset 00000000 to memory 08000000-080007ff, size 2048 - Setting address pointer to 0x08000000 - Download from image offset 00000800 to memory 08000800-08000903, size 260 - Setting address pointer to 0x08000800 diff --git a/macosx/src/dfu-util/device-logs/stm32f4discovery.lsusb b/macosx/src/dfu-util/device-logs/stm32f4discovery.lsusb deleted file mode 100644 index 0b870de91..000000000 --- a/macosx/src/dfu-util/device-logs/stm32f4discovery.lsusb +++ /dev/null @@ -1,80 +0,0 @@ - -Bus 001 Device 010: ID 0483:df11 SGS Thomson Microelectronics STM Device in DFU Mode -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 1.00 - bDeviceClass 0 (Defined at Interface level) - bDeviceSubClass 0 - bDeviceProtocol 0 - bMaxPacketSize0 64 - idVendor 0x0483 SGS Thomson Microelectronics - idProduct 0xdf11 STM Device in DFU Mode - bcdDevice 21.00 - iManufacturer 1 STMicroelectronics - iProduct 2 STM32 BOOTLOADER - iSerial 3 315A28A0B956 - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 54 - bNumInterfaces 1 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0xc0 - Self Powered - MaxPower 100mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 4 @Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 1 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 5 @Option Bytes /0x1FFFC000/01*016 g - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 2 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 6 @OTP Memory /0x1FFF7800/01*512 g,01*016 g - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 3 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 2 - iInterface 7 @Device Feature/0xFFFF0000/01*004 g - Device Firmware Upgrade Interface Descriptor: - bLength 9 - bDescriptorType 33 - bmAttributes 11 - Will Detach - Manifestation Intolerant - Upload Supported - Download Supported - wDetachTimeout 255 milliseconds - wTransferSize 2048 bytes - bcdDFUVersion 1.1a -Device Status: 0x0001 - Self Powered diff --git a/macosx/src/dfu-util/device-logs/tdk-bluetooth.lsusb b/macosx/src/dfu-util/device-logs/tdk-bluetooth.lsusb deleted file mode 100644 index c0cfaceb6..000000000 --- a/macosx/src/dfu-util/device-logs/tdk-bluetooth.lsusb +++ /dev/null @@ -1,269 +0,0 @@ - -Bus 006 Device 014: ID 04bf:0320 TDK Corp. Bluetooth Adapter -Device Descriptor: - bLength 18 - bDescriptorType 1 - bcdUSB 2.00 - bDeviceClass 224 Wireless - bDeviceSubClass 1 Radio Frequency - bDeviceProtocol 1 Bluetooth - bMaxPacketSize0 64 - idVendor 0x04bf TDK Corp. - idProduct 0x0320 Bluetooth Adapter - bcdDevice 26.52 - iManufacturer 1 Ezurio - iProduct 2 Turbo Bluetooth Adapter - iSerial 3 008098D4FFBD - bNumConfigurations 1 - Configuration Descriptor: - bLength 9 - bDescriptorType 2 - wTotalLength 193 - bNumInterfaces 3 - bConfigurationValue 1 - iConfiguration 0 - bmAttributes 0x80 - (Bus Powered) - MaxPower 64mA - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 0 - bAlternateSetting 0 - bNumEndpoints 3 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x81 EP 1 IN - bmAttributes 3 - Transfer Type Interrupt - Synch Type None - Usage Type Data - wMaxPacketSize 0x0010 1x 16 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x02 EP 2 OUT - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x82 EP 2 IN - bmAttributes 2 - Transfer Type Bulk - Synch Type None - Usage Type Data - wMaxPacketSize 0x0040 1x 64 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 0 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0000 1x 0 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0000 1x 0 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 1 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0009 1x 9 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0009 1x 9 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 2 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0011 1x 17 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0011 1x 17 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 3 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0019 1x 25 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0019 1x 25 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 4 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0021 1x 33 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0021 1x 33 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 1 - bAlternateSetting 5 - bNumEndpoints 2 - bInterfaceClass 224 Wireless - bInterfaceSubClass 1 Radio Frequency - bInterfaceProtocol 1 Bluetooth - iInterface 0 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x03 EP 3 OUT - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0031 1x 49 bytes - bInterval 1 - Endpoint Descriptor: - bLength 7 - bDescriptorType 5 - bEndpointAddress 0x83 EP 3 IN - bmAttributes 1 - Transfer Type Isochronous - Synch Type None - Usage Type Data - wMaxPacketSize 0x0031 1x 49 bytes - bInterval 1 - Interface Descriptor: - bLength 9 - bDescriptorType 4 - bInterfaceNumber 2 - bAlternateSetting 0 - bNumEndpoints 0 - bInterfaceClass 254 Application Specific Interface - bInterfaceSubClass 1 Device Firmware Update - bInterfaceProtocol 0 - iInterface 0 - Device Firmware Upgrade Interface Descriptor: - bLength 7 - bDescriptorType 33 - bmAttributes 7 - Will Not Detach - Manifestation Tolerant - Upload Supported - Download Supported - wDetachTimeout 5000 milliseconds - wTransferSize 1023 bytes -Device Status: 0x0000 - (Bus Powered) diff --git a/macosx/src/dfu-util/dfuse-pack.py b/macosx/src/dfu-util/dfuse-pack.py deleted file mode 100644 index 875cc5c6e..000000000 --- a/macosx/src/dfu-util/dfuse-pack.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/python - -# Written by Antonio Galea - 2010/11/18 -# Distributed under Gnu LGPL 3.0 -# see http://www.gnu.org/licenses/lgpl-3.0.txt - -import sys,struct,zlib,os -from optparse import OptionParser - -DEFAULT_DEVICE="0x0483:0xdf11" - -def named(tuple,names): - return dict(zip(names.split(),tuple)) -def consume(fmt,data,names): - n = struct.calcsize(fmt) - return named(struct.unpack(fmt,data[:n]),names),data[n:] -def cstring(string): - return string.split('\0',1)[0] -def compute_crc(data): - return 0xFFFFFFFF & -zlib.crc32(data) -1 - -def parse(file,dump_images=False): - print 'File: "%s"' % file - data = open(file,'rb').read() - crc = compute_crc(data[:-4]) - prefix, data = consume('<5sBIB',data,'signature version size targets') - print '%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix - for t in range(prefix['targets']): - tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') - tprefix['num'] = t - if tprefix['named']: - tprefix['name'] = cstring(tprefix['name']) - else: - tprefix['name'] = '' - print '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix - tsize = tprefix['size'] - target, data = data[:tsize], data[tsize:] - for e in range(tprefix['elements']): - eprefix, target = consume('<2I',target,'address size') - eprefix['num'] = e - print ' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix - esize = eprefix['size'] - image, target = target[:esize], target[esize:] - if dump_images: - out = '%s.target%d.image%d.bin' % (file,t,e) - open(out,'wb').write(image) - print ' DUMPED IMAGE TO "%s"' % out - if len(target): - print "target %d: PARSE ERROR" % t - suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') - print 'usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix - if crc != suffix['crc']: - print "CRC ERROR: computed crc32 is 0x%08x" % crc - data = data[16:] - if data: - print "PARSE ERROR" - -def build(file,targets,device=DEFAULT_DEVICE): - data = '' - for t,target in enumerate(targets): - tdata = '' - for image in target: - tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] - tdata = struct.pack('<6sBI255s2I','Target',0,1,'ST...',len(tdata),len(target)) + tdata - data += tdata - data = struct.pack('<5sBIB','DfuSe',1,len(data)+11,len(targets)) + data - v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) - data += struct.pack('<4H3sB',0,d,v,0x011a,'UFD',16) - crc = compute_crc(data) - data += struct.pack(' and -Harald Welte . Over time, nearly complete -support of DFU 1.0, DFU 1.1 and DfuSe ("1.1a") has been added. -.SH LICENCE -.B dfu-util -is covered by the GNU General Public License (GPL), version 2 or later. -.SH COPYRIGHT -This manual page was originally written by Uwe Hermann , -and is now part of the dfu-util project. diff --git a/macosx/src/dfu-util/msvc/README_msvc.txt b/macosx/src/dfu-util/msvc/README_msvc.txt deleted file mode 100644 index 6e68ec6ff..000000000 --- a/macosx/src/dfu-util/msvc/README_msvc.txt +++ /dev/null @@ -1,10 +0,0 @@ -# (C) Roger Meier -# (C) Pascal Schweizer -# msvc folder is GPL-2.0+, LGPL-2.1+, BSD-3-Clause or MIT license(SPDX) - -Building dfu-util native on Windows with Visual Studio - -3rd party dependencies: -- libusbx ( git clone https://github.com/libusbx/libusbx.git ) - - getopt (part of libusbx: libusbx/examples/getopt) - diff --git a/macosx/src/dfu-util/msvc/dfu-suffix_2010.vcxproj b/macosx/src/dfu-util/msvc/dfu-suffix_2010.vcxproj deleted file mode 100644 index 0c316c2e5..000000000 --- a/macosx/src/dfu-util/msvc/dfu-suffix_2010.vcxproj +++ /dev/null @@ -1,100 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA} - dfusuffix - dfu-suffix - - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\dll;$(LibraryPath) - $(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib - $(ExecutablePath) - - - $(ExecutablePath) - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\dll;$(LibraryPath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - - - Level3 - MaxSpeed - true - true - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - - - - - - - - - - - {a2169bc8-cf99-40bf-83f3-b0e38f7067bd} - - - {349ee8f9-7d25-4909-aaf5-ff3fade72187} - - - - - - \ No newline at end of file diff --git a/macosx/src/dfu-util/msvc/dfu-util_2010.sln b/macosx/src/dfu-util/msvc/dfu-util_2010.sln deleted file mode 100644 index ef797239b..000000000 --- a/macosx/src/dfu-util/msvc/dfu-util_2010.sln +++ /dev/null @@ -1,54 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfu-util", "dfu-util_2010.vcxproj", "{0E071A60-7EF2-4427-BAA8-9143CACB5BCB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C4F8746D-B27E-4806-95E5-2052174E923B}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfu-suffix", "dfu-suffix_2010.vcxproj", "{8F7600A2-3B37-4956-B39B-A1D43EF29EDA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt_2010", "..\..\libusbx\msvc\getopt_2010.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "..\..\libusbx\msvc\libusb_static_2010.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|Win32.ActiveCfg = Debug|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|Win32.Build.0 = Debug|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|x64.ActiveCfg = Debug|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|Win32.ActiveCfg = Release|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|Win32.Build.0 = Release|Win32 - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|x64.ActiveCfg = Release|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|Win32.ActiveCfg = Debug|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|Win32.Build.0 = Debug|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|x64.ActiveCfg = Debug|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|Win32.ActiveCfg = Release|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|Win32.Build.0 = Release|Win32 - {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|x64.ActiveCfg = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.ActiveCfg = Debug|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.Build.0 = Debug|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.ActiveCfg = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.Build.0 = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 - {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/macosx/src/dfu-util/msvc/dfu-util_2010.vcxproj b/macosx/src/dfu-util/msvc/dfu-util_2010.vcxproj deleted file mode 100644 index 17a8bee1b..000000000 --- a/macosx/src/dfu-util/msvc/dfu-util_2010.vcxproj +++ /dev/null @@ -1,120 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {0E071A60-7EF2-4427-BAA8-9143CACB5BCB} - dfuutil - dfu-util - - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\getopt\$(Configuration);$(LibraryPath) - $(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib - $(ExecutablePath) - - - $(ExecutablePath) - $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) - $(SolutionDir)..\$(Platform)\getopt\$(Configuration);$(LibraryPath) - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - - - - Level3 - Disabled - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - true - - - - - - - - - Level3 - MaxSpeed - true - true - HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - MultiThreaded - - - true - true - true - - - copy $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0.dll $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ - - - - - - - - - - - - - - - - - - - - - - - - - - {a2169bc8-cf99-40bf-83f3-b0e38f7067bd} - - - {349ee8f9-7d25-4909-aaf5-ff3fade72187} - - - - - - \ No newline at end of file diff --git a/macosx/src/dfu-util/src/Makefile.am b/macosx/src/dfu-util/src/Makefile.am deleted file mode 100644 index 70179c411..000000000 --- a/macosx/src/dfu-util/src/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -AM_CFLAGS = -Wall -Wextra - -bin_PROGRAMS = dfu-util dfu-suffix dfu-prefix -dfu_util_SOURCES = main.c \ - portable.h \ - dfu_load.c \ - dfu_load.h \ - dfu_util.c \ - dfu_util.h \ - dfuse.c \ - dfuse.h \ - dfuse_mem.c \ - dfuse_mem.h \ - dfu.c \ - dfu.h \ - usb_dfu.h \ - dfu_file.c \ - dfu_file.h \ - quirks.c \ - quirks.h - -dfu_suffix_SOURCES = suffix.c \ - dfu_file.h \ - dfu_file.c - -dfu_prefix_SOURCES = prefix.c \ - dfu_file.h \ - dfu_file.c diff --git a/macosx/src/dfu-util/src/dfu.c b/macosx/src/dfu-util/src/dfu.c deleted file mode 100644 index 14d7673d1..000000000 --- a/macosx/src/dfu-util/src/dfu.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Low-level DFU communication routines, originally taken from - * $Id: dfu.c,v 1.3 2006/06/20 06:28:04 schmidtw Exp $ - * (part of dfu-programmer). - * - * Copyright 2005-2006 Weston Schmidt - * Copyright 2011-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include - -#include "portable.h" -#include "dfu.h" -#include "quirks.h" - -static int dfu_timeout = 5000; /* 5 seconds - default */ - -/* - * DFU_DETACH Request (DFU Spec 1.0, Section 5.1) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * timeout - the timeout in ms the USB device should wait for a pending - * USB reset before giving up and terminating the operation - * - * returns 0 or < 0 on error - */ -int dfu_detach( libusb_device_handle *device, - const unsigned short interface, - const unsigned short timeout ) -{ - return libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_DETACH, - /* wValue */ timeout, - /* wIndex */ interface, - /* Data */ NULL, - /* wLength */ 0, - dfu_timeout ); -} - - -/* - * DFU_DNLOAD Request (DFU Spec 1.0, Section 6.1.1) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * length - the total number of bytes to transfer to the USB - * device - must be less than wTransferSize - * data - the data to transfer - * - * returns the number of bytes written or < 0 on error - */ -int dfu_download( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ) -{ - int status; - - status = libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_DNLOAD, - /* wValue */ transaction, - /* wIndex */ interface, - /* Data */ data, - /* wLength */ length, - dfu_timeout ); - return status; -} - - -/* - * DFU_UPLOAD Request (DFU Spec 1.0, Section 6.2) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * length - the maximum number of bytes to receive from the USB - * device - must be less than wTransferSize - * data - the buffer to put the received data in - * - * returns the number of bytes received or < 0 on error - */ -int dfu_upload( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ) -{ - int status; - - status = libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_UPLOAD, - /* wValue */ transaction, - /* wIndex */ interface, - /* Data */ data, - /* wLength */ length, - dfu_timeout ); - return status; -} - - -/* - * DFU_GETSTATUS Request (DFU Spec 1.0, Section 6.1.2) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * status - the data structure to be populated with the results - * - * return the number of bytes read in or < 0 on an error - */ -int dfu_get_status( struct dfu_if *dif, struct dfu_status *status ) -{ - unsigned char buffer[6]; - int result; - - /* Initialize the status data structure */ - status->bStatus = DFU_STATUS_ERROR_UNKNOWN; - status->bwPollTimeout = 0; - status->bState = STATE_DFU_ERROR; - status->iString = 0; - - result = libusb_control_transfer( dif->dev_handle, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_GETSTATUS, - /* wValue */ 0, - /* wIndex */ dif->interface, - /* Data */ buffer, - /* wLength */ 6, - dfu_timeout ); - - if( 6 == result ) { - status->bStatus = buffer[0]; - if (dif->quirks & QUIRK_POLLTIMEOUT) - status->bwPollTimeout = DEFAULT_POLLTIMEOUT; - else - status->bwPollTimeout = ((0xff & buffer[3]) << 16) | - ((0xff & buffer[2]) << 8) | - (0xff & buffer[1]); - status->bState = buffer[4]; - status->iString = buffer[5]; - } - - return result; -} - - -/* - * DFU_CLRSTATUS Request (DFU Spec 1.0, Section 6.1.3) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * - * return 0 or < 0 on an error - */ -int dfu_clear_status( libusb_device_handle *device, - const unsigned short interface ) -{ - return libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT| LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_CLRSTATUS, - /* wValue */ 0, - /* wIndex */ interface, - /* Data */ NULL, - /* wLength */ 0, - dfu_timeout ); -} - - -/* - * DFU_GETSTATE Request (DFU Spec 1.0, Section 6.1.5) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * length - the maximum number of bytes to receive from the USB - * device - must be less than wTransferSize - * data - the buffer to put the received data in - * - * returns the state or < 0 on error - */ -int dfu_get_state( libusb_device_handle *device, - const unsigned short interface ) -{ - int result; - unsigned char buffer[1]; - - result = libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_GETSTATE, - /* wValue */ 0, - /* wIndex */ interface, - /* Data */ buffer, - /* wLength */ 1, - dfu_timeout ); - - /* Return the error if there is one. */ - if (result < 1) - return -1; - - /* Return the state. */ - return buffer[0]; -} - - -/* - * DFU_ABORT Request (DFU Spec 1.0, Section 6.1.4) - * - * device - the usb_dev_handle to communicate with - * interface - the interface to communicate with - * - * returns 0 or < 0 on an error - */ -int dfu_abort( libusb_device_handle *device, - const unsigned short interface ) -{ - return libusb_control_transfer( device, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_ABORT, - /* wValue */ 0, - /* wIndex */ interface, - /* Data */ NULL, - /* wLength */ 0, - dfu_timeout ); -} - - -const char* dfu_state_to_string( int state ) -{ - const char *message; - - switch (state) { - case STATE_APP_IDLE: - message = "appIDLE"; - break; - case STATE_APP_DETACH: - message = "appDETACH"; - break; - case STATE_DFU_IDLE: - message = "dfuIDLE"; - break; - case STATE_DFU_DOWNLOAD_SYNC: - message = "dfuDNLOAD-SYNC"; - break; - case STATE_DFU_DOWNLOAD_BUSY: - message = "dfuDNBUSY"; - break; - case STATE_DFU_DOWNLOAD_IDLE: - message = "dfuDNLOAD-IDLE"; - break; - case STATE_DFU_MANIFEST_SYNC: - message = "dfuMANIFEST-SYNC"; - break; - case STATE_DFU_MANIFEST: - message = "dfuMANIFEST"; - break; - case STATE_DFU_MANIFEST_WAIT_RESET: - message = "dfuMANIFEST-WAIT-RESET"; - break; - case STATE_DFU_UPLOAD_IDLE: - message = "dfuUPLOAD-IDLE"; - break; - case STATE_DFU_ERROR: - message = "dfuERROR"; - break; - default: - message = NULL; - break; - } - - return message; -} - -/* Chapter 6.1.2 */ -static const char *dfu_status_names[] = { - /* DFU_STATUS_OK */ - "No error condition is present", - /* DFU_STATUS_errTARGET */ - "File is not targeted for use by this device", - /* DFU_STATUS_errFILE */ - "File is for this device but fails some vendor-specific test", - /* DFU_STATUS_errWRITE */ - "Device is unable to write memory", - /* DFU_STATUS_errERASE */ - "Memory erase function failed", - /* DFU_STATUS_errCHECK_ERASED */ - "Memory erase check failed", - /* DFU_STATUS_errPROG */ - "Program memory function failed", - /* DFU_STATUS_errVERIFY */ - "Programmed memory failed verification", - /* DFU_STATUS_errADDRESS */ - "Cannot program memory due to received address that is out of range", - /* DFU_STATUS_errNOTDONE */ - "Received DFU_DNLOAD with wLength = 0, but device does not think that it has all data yet", - /* DFU_STATUS_errFIRMWARE */ - "Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations", - /* DFU_STATUS_errVENDOR */ - "iString indicates a vendor specific error", - /* DFU_STATUS_errUSBR */ - "Device detected unexpected USB reset signalling", - /* DFU_STATUS_errPOR */ - "Device detected unexpected power on reset", - /* DFU_STATUS_errUNKNOWN */ - "Something went wrong, but the device does not know what it was", - /* DFU_STATUS_errSTALLEDPKT */ - "Device stalled an unexpected request" -}; - - -const char *dfu_status_to_string(int status) -{ - if (status > DFU_STATUS_errSTALLEDPKT) - return "INVALID"; - return dfu_status_names[status]; -} - -int dfu_abort_to_idle(struct dfu_if *dif) -{ - int ret; - struct dfu_status dst; - - ret = dfu_abort(dif->dev_handle, dif->interface); - if (ret < 0) { - errx(EX_IOERR, "Error sending dfu abort request"); - exit(1); - } - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during abort get_status"); - exit(1); - } - if (dst.bState != DFU_STATE_dfuIDLE) { - errx(EX_IOERR, "Failed to enter idle state on abort"); - exit(1); - } - milli_sleep(dst.bwPollTimeout); - return ret; -} diff --git a/macosx/src/dfu-util/src/dfu.h b/macosx/src/dfu-util/src/dfu.h deleted file mode 100644 index 8e3caeb7b..000000000 --- a/macosx/src/dfu-util/src/dfu.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * dfu-programmer - * - * $Id: dfu.h,v 1.2 2005/09/25 01:27:42 schmidtw Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DFU_H -#define DFU_H - -#include -#include "usb_dfu.h" - -/* DFU states */ -#define STATE_APP_IDLE 0x00 -#define STATE_APP_DETACH 0x01 -#define STATE_DFU_IDLE 0x02 -#define STATE_DFU_DOWNLOAD_SYNC 0x03 -#define STATE_DFU_DOWNLOAD_BUSY 0x04 -#define STATE_DFU_DOWNLOAD_IDLE 0x05 -#define STATE_DFU_MANIFEST_SYNC 0x06 -#define STATE_DFU_MANIFEST 0x07 -#define STATE_DFU_MANIFEST_WAIT_RESET 0x08 -#define STATE_DFU_UPLOAD_IDLE 0x09 -#define STATE_DFU_ERROR 0x0a - - -/* DFU status */ -#define DFU_STATUS_OK 0x00 -#define DFU_STATUS_ERROR_TARGET 0x01 -#define DFU_STATUS_ERROR_FILE 0x02 -#define DFU_STATUS_ERROR_WRITE 0x03 -#define DFU_STATUS_ERROR_ERASE 0x04 -#define DFU_STATUS_ERROR_CHECK_ERASED 0x05 -#define DFU_STATUS_ERROR_PROG 0x06 -#define DFU_STATUS_ERROR_VERIFY 0x07 -#define DFU_STATUS_ERROR_ADDRESS 0x08 -#define DFU_STATUS_ERROR_NOTDONE 0x09 -#define DFU_STATUS_ERROR_FIRMWARE 0x0a -#define DFU_STATUS_ERROR_VENDOR 0x0b -#define DFU_STATUS_ERROR_USBR 0x0c -#define DFU_STATUS_ERROR_POR 0x0d -#define DFU_STATUS_ERROR_UNKNOWN 0x0e -#define DFU_STATUS_ERROR_STALLEDPKT 0x0f - -/* DFU commands */ -#define DFU_DETACH 0 -#define DFU_DNLOAD 1 -#define DFU_UPLOAD 2 -#define DFU_GETSTATUS 3 -#define DFU_CLRSTATUS 4 -#define DFU_GETSTATE 5 -#define DFU_ABORT 6 - -/* DFU interface */ -#define DFU_IFF_DFU 0x0001 /* DFU Mode, (not Runtime) */ - -/* This is based off of DFU_GETSTATUS - * - * 1 unsigned byte bStatus - * 3 unsigned byte bwPollTimeout - * 1 unsigned byte bState - * 1 unsigned byte iString -*/ - -struct dfu_status { - unsigned char bStatus; - unsigned int bwPollTimeout; - unsigned char bState; - unsigned char iString; -}; - -struct dfu_if { - struct usb_dfu_func_descriptor func_dfu; - uint16_t quirks; - uint16_t busnum; - uint16_t devnum; - uint16_t vendor; - uint16_t product; - uint16_t bcdDevice; - uint8_t configuration; - uint8_t interface; - uint8_t altsetting; - uint8_t flags; - uint8_t bMaxPacketSize0; - char *alt_name; - char *serial_name; - libusb_device *dev; - libusb_device_handle *dev_handle; - struct dfu_if *next; -}; - -int dfu_detach( libusb_device_handle *device, - const unsigned short interface, - const unsigned short timeout ); -int dfu_download( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ); -int dfu_upload( libusb_device_handle *device, - const unsigned short interface, - const unsigned short length, - const unsigned short transaction, - unsigned char* data ); -int dfu_get_status( struct dfu_if *dif, - struct dfu_status *status ); -int dfu_clear_status( libusb_device_handle *device, - const unsigned short interface ); -int dfu_get_state( libusb_device_handle *device, - const unsigned short interface ); -int dfu_abort( libusb_device_handle *device, - const unsigned short interface ); -int dfu_abort_to_idle( struct dfu_if *dif); - -const char *dfu_state_to_string( int state ); - -const char *dfu_status_to_string( int status ); - -#endif /* DFU_H */ diff --git a/macosx/src/dfu-util/src/dfu_file.c b/macosx/src/dfu-util/src/dfu_file.c deleted file mode 100644 index 7c897d4f6..000000000 --- a/macosx/src/dfu-util/src/dfu_file.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * Load or store DFU files including suffix and prefix - * - * Copyright 2014 Tormod Volden - * Copyright 2012 Stefan Schmidt - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" - -#define DFU_SUFFIX_LENGTH 16 -#define LMDFU_PREFIX_LENGTH 8 -#define LPCDFU_PREFIX_LENGTH 16 -#define PROGRESS_BAR_WIDTH 25 -#define STDIN_CHUNK_SIZE 65536 - -static const unsigned long crc32_table[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; - -static uint32_t crc32_byte(uint32_t accum, uint8_t delta) -{ - return crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8); -} - -static int probe_prefix(struct dfu_file *file) -{ - uint8_t *prefix = file->firmware; - - if (file->size.total < LMDFU_PREFIX_LENGTH) - return 1; - if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) { - file->prefix_type = LMDFU_PREFIX; - file->size.prefix = LMDFU_PREFIX_LENGTH; - file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]); - } - else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f)== 0x3f)) { - file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX; - file->size.prefix = LPCDFU_PREFIX_LENGTH; - } - - if (file->size.prefix + file->size.suffix > file->size.total) - return 1; - return 0; -} - -void dfu_progress_bar(const char *desc, unsigned long long curr, - unsigned long long max) -{ - static char buf[PROGRESS_BAR_WIDTH + 1]; - static unsigned long long last_progress = -1; - static time_t last_time; - time_t curr_time = time(NULL); - unsigned long long progress; - unsigned long long x; - - /* check for not known maximum */ - if (max < curr) - max = curr + 1; - /* make none out of none give zero */ - if (max == 0 && curr == 0) - max = 1; - - /* compute completion */ - progress = (PROGRESS_BAR_WIDTH * curr) / max; - if (progress > PROGRESS_BAR_WIDTH) - progress = PROGRESS_BAR_WIDTH; - if (progress == last_progress && - curr_time == last_time) - return; - last_progress = progress; - last_time = curr_time; - - for (x = 0; x != PROGRESS_BAR_WIDTH; x++) { - if (x < progress) - buf[x] = '='; - else - buf[x] = ' '; - } - buf[x] = 0; - - printf("\r%s\t[%s] %3lld%% %12lld bytes", desc, buf, - (100ULL * curr) / max, curr); - - if (progress == PROGRESS_BAR_WIDTH) - printf("\n%s done.\n", desc); -} - -void *dfu_malloc(size_t size) -{ - void *ptr = malloc(size); - if (ptr == NULL) - errx(EX_SOFTWARE, "Cannot allocate memory of size %d bytes", (int)size); - return (ptr); -} - -uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size) -{ - int x; - - /* compute CRC */ - for (x = 0; x != size; x++) - crc = crc32_byte(crc, ((uint8_t *)buf)[x]); - - /* write data */ - if (write(f, buf, size) != size) - err(EX_IOERR, "Could not write %d bytes to file %d", size, f); - - return (crc); -} - -void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix) -{ - off_t offset; - int f; - int i; - int res; - - file->size.prefix = 0; - file->size.suffix = 0; - - /* default values, if no valid suffix is found */ - file->bcdDFU = 0; - file->idVendor = 0xffff; /* wildcard value */ - file->idProduct = 0xffff; /* wildcard value */ - file->bcdDevice = 0xffff; /* wildcard value */ - - /* default values, if no valid prefix is found */ - file->lmdfu_address = 0; - - free(file->firmware); - - if (!strcmp(file->name, "-")) { - int read_bytes; - -#ifdef WIN32 - _setmode( _fileno( stdin ), _O_BINARY ); -#endif - file->firmware = (uint8_t*) dfu_malloc(STDIN_CHUNK_SIZE); - read_bytes = fread(file->firmware, 1, STDIN_CHUNK_SIZE, stdin); - file->size.total = read_bytes; - while (read_bytes == STDIN_CHUNK_SIZE) { - file->firmware = (uint8_t*) realloc(file->firmware, file->size.total + STDIN_CHUNK_SIZE); - if (!file->firmware) - err(EX_IOERR, "Could not allocate firmware buffer"); - read_bytes = fread(file->firmware + file->size.total, 1, STDIN_CHUNK_SIZE, stdin); - file->size.total += read_bytes; - } - if (verbose) - printf("Read %i bytes from stdin\n", file->size.total); - /* Never require suffix when reading from stdin */ - check_suffix = MAYBE_SUFFIX; - } else { - f = open(file->name, O_RDONLY | O_BINARY); - if (f < 0) - err(EX_IOERR, "Could not open file %s for reading", file->name); - - offset = lseek(f, 0, SEEK_END); - - if ((int)offset < 0 || (int)offset != offset) - err(EX_IOERR, "File size is too big"); - - if (lseek(f, 0, SEEK_SET) != 0) - err(EX_IOERR, "Could not seek to beginning"); - - file->size.total = offset; - file->firmware = dfu_malloc(file->size.total); - - if (read(f, file->firmware, file->size.total) != file->size.total) { - err(EX_IOERR, "Could not read %d bytes from %s", - file->size.total, file->name); - } - close(f); - } - - /* Check for possible DFU file suffix by trying to parse one */ - { - uint32_t crc = 0xffffffff; - const uint8_t *dfusuffix; - int missing_suffix = 0; - const char *reason; - - if (file->size.total < DFU_SUFFIX_LENGTH) { - reason = "File too short for DFU suffix"; - missing_suffix = 1; - goto checked; - } - - dfusuffix = file->firmware + file->size.total - - DFU_SUFFIX_LENGTH; - - for (i = 0; i < file->size.total - 4; i++) - crc = crc32_byte(crc, file->firmware[i]); - - if (dfusuffix[10] != 'D' || - dfusuffix[9] != 'F' || - dfusuffix[8] != 'U') { - reason = "Invalid DFU suffix signature"; - missing_suffix = 1; - goto checked; - } - - file->dwCRC = (dfusuffix[15] << 24) + - (dfusuffix[14] << 16) + - (dfusuffix[13] << 8) + - dfusuffix[12]; - - if (file->dwCRC != crc) { - reason = "DFU suffix CRC does not match"; - missing_suffix = 1; - goto checked; - } - - /* At this point we believe we have a DFU suffix - so we require further checks to succeed */ - - file->bcdDFU = (dfusuffix[7] << 8) + dfusuffix[6]; - - if (verbose) - printf("DFU suffix version %x\n", file->bcdDFU); - - file->size.suffix = dfusuffix[11]; - - if (file->size.suffix < DFU_SUFFIX_LENGTH) { - errx(EX_IOERR, "Unsupported DFU suffix length %d", - file->size.suffix); - } - - if (file->size.suffix > file->size.total) { - errx(EX_IOERR, "Invalid DFU suffix length %d", - file->size.suffix); - } - - file->idVendor = (dfusuffix[5] << 8) + dfusuffix[4]; - file->idProduct = (dfusuffix[3] << 8) + dfusuffix[2]; - file->bcdDevice = (dfusuffix[1] << 8) + dfusuffix[0]; - -checked: - if (missing_suffix) { - if (check_suffix == NEEDS_SUFFIX) { - warnx("%s", reason); - errx(EX_IOERR, "Valid DFU suffix needed"); - } else if (check_suffix == MAYBE_SUFFIX) { - warnx("%s", reason); - warnx("A valid DFU suffix will be required in " - "a future dfu-util release!!!"); - } - } else { - if (check_suffix == NO_SUFFIX) { - errx(EX_SOFTWARE, "Please remove existing DFU suffix before adding a new one.\n"); - } - } - } - res = probe_prefix(file); - if ((res || file->size.prefix == 0) && check_prefix == NEEDS_PREFIX) - errx(EX_IOERR, "Valid DFU prefix needed"); - if (file->size.prefix && check_prefix == NO_PREFIX) - errx(EX_IOERR, "A prefix already exists, please delete it first"); - if (file->size.prefix && verbose) { - uint8_t *data = file->firmware; - if (file->prefix_type == LMDFU_PREFIX) - printf("Possible TI Stellaris DFU prefix with " - "the following properties\n" - "Address: 0x%08x\n" - "Payload length: %d\n", - file->lmdfu_address, - data[4] | (data[5] << 8) | - (data[6] << 16) | (data[7] << 14)); - else if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) - printf("Possible unencrypted NXP LPC DFU prefix with " - "the following properties\n" - "Payload length: %d kiByte\n", - data[2] >>1 | (data[3] << 7) ); - else - errx(EX_IOERR, "Unknown DFU prefix type"); - } -} - -void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix) -{ - uint32_t crc = 0xffffffff; - int f; - - f = open(file->name, O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, 0666); - if (f < 0) - err(EX_IOERR, "Could not open file %s for writing", file->name); - - /* write prefix, if any */ - if (write_prefix) { - if (file->prefix_type == LMDFU_PREFIX) { - uint8_t lmdfu_prefix[LMDFU_PREFIX_LENGTH]; - uint32_t addr = file->lmdfu_address / 1024; - - /* lmdfu_dfu_prefix payload length excludes prefix and suffix */ - uint32_t len = file->size.total - - file->size.prefix - file->size.suffix; - - lmdfu_prefix[0] = 0x01; /* STELLARIS_DFU_PROG */ - lmdfu_prefix[1] = 0x00; /* Reserved */ - lmdfu_prefix[2] = (uint8_t)(addr & 0xff); - lmdfu_prefix[3] = (uint8_t)(addr >> 8); - lmdfu_prefix[4] = (uint8_t)(len & 0xff); - lmdfu_prefix[5] = (uint8_t)(len >> 8) & 0xff; - lmdfu_prefix[6] = (uint8_t)(len >> 16) & 0xff; - lmdfu_prefix[7] = (uint8_t)(len >> 24); - - crc = dfu_file_write_crc(f, crc, lmdfu_prefix, LMDFU_PREFIX_LENGTH); - } - if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) { - uint8_t lpcdfu_prefix[LPCDFU_PREFIX_LENGTH] = {0}; - int i; - - /* Payload is firmware and prefix rounded to 512 bytes */ - uint32_t len = (file->size.total - file->size.suffix + 511) /512; - - lpcdfu_prefix[0] = 0x1a; /* Unencypted*/ - lpcdfu_prefix[1] = 0x3f; /* Reserved */ - lpcdfu_prefix[2] = (uint8_t)(len & 0xff); - lpcdfu_prefix[3] = (uint8_t)((len >> 8) & 0xff); - for (i = 12; i < LPCDFU_PREFIX_LENGTH; i++) - lpcdfu_prefix[i] = 0xff; - - crc = dfu_file_write_crc(f, crc, lpcdfu_prefix, LPCDFU_PREFIX_LENGTH); - } - } - /* write firmware binary */ - crc = dfu_file_write_crc(f, crc, file->firmware + file->size.prefix, - file->size.total - file->size.prefix - file->size.suffix); - - /* write suffix, if any */ - if (write_suffix) { - uint8_t dfusuffix[DFU_SUFFIX_LENGTH]; - - dfusuffix[0] = file->bcdDevice & 0xff; - dfusuffix[1] = file->bcdDevice >> 8; - dfusuffix[2] = file->idProduct & 0xff; - dfusuffix[3] = file->idProduct >> 8; - dfusuffix[4] = file->idVendor & 0xff; - dfusuffix[5] = file->idVendor >> 8; - dfusuffix[6] = file->bcdDFU & 0xff; - dfusuffix[7] = file->bcdDFU >> 8; - dfusuffix[8] = 'U'; - dfusuffix[9] = 'F'; - dfusuffix[10] = 'D'; - dfusuffix[11] = DFU_SUFFIX_LENGTH; - - crc = dfu_file_write_crc(f, crc, dfusuffix, - DFU_SUFFIX_LENGTH - 4); - - dfusuffix[12] = crc; - dfusuffix[13] = crc >> 8; - dfusuffix[14] = crc >> 16; - dfusuffix[15] = crc >> 24; - - crc = dfu_file_write_crc(f, crc, dfusuffix + 12, 4); - } - close(f); -} - -void show_suffix_and_prefix(struct dfu_file *file) -{ - if (file->size.prefix == LMDFU_PREFIX_LENGTH) { - printf("The file %s contains a TI Stellaris DFU prefix with the following properties:\n", file->name); - printf("Address:\t0x%08x\n", file->lmdfu_address); - } else if (file->size.prefix == LPCDFU_PREFIX_LENGTH) { - uint8_t * prefix = file->firmware; - printf("The file %s contains a NXP unencrypted LPC DFU prefix with the following properties:\n", file->name); - printf("Size:\t%5d kiB\n", prefix[2]>>1|prefix[3]<<7); - } else if (file->size.prefix != 0) { - printf("The file %s contains an unknown prefix\n", file->name); - } - if (file->size.suffix > 0) { - printf("The file %s contains a DFU suffix with the following properties:\n", file->name); - printf("BCD device:\t0x%04X\n", file->bcdDevice); - printf("Product ID:\t0x%04X\n",file->idProduct); - printf("Vendor ID:\t0x%04X\n", file->idVendor); - printf("BCD DFU:\t0x%04X\n", file->bcdDFU); - printf("Length:\t\t%i\n", file->size.suffix); - printf("CRC:\t\t0x%08X\n", file->dwCRC); - } -} diff --git a/macosx/src/dfu-util/src/dfu_file.h b/macosx/src/dfu-util/src/dfu_file.h deleted file mode 100644 index abebd44f4..000000000 --- a/macosx/src/dfu-util/src/dfu_file.h +++ /dev/null @@ -1,60 +0,0 @@ - -#ifndef DFU_FILE_H -#define DFU_FILE_H - -#include - -struct dfu_file { - /* File name */ - const char *name; - /* Pointer to file loaded into memory */ - uint8_t *firmware; - /* Different sizes */ - struct { - int total; - int prefix; - int suffix; - } size; - /* From prefix fields */ - uint32_t lmdfu_address; - /* From prefix fields */ - uint32_t prefix_type; - - /* From DFU suffix fields */ - uint32_t dwCRC; - uint16_t bcdDFU; - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; -}; - -enum suffix_req { - NO_SUFFIX, - NEEDS_SUFFIX, - MAYBE_SUFFIX -}; - -enum prefix_req { - NO_PREFIX, - NEEDS_PREFIX, - MAYBE_PREFIX -}; - -enum prefix_type { - ZERO_PREFIX, - LMDFU_PREFIX, - LPCDFU_UNENCRYPTED_PREFIX -}; - -extern int verbose; - -void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix); -void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix); - -void dfu_progress_bar(const char *desc, unsigned long long curr, - unsigned long long max); -void *dfu_malloc(size_t size); -uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size); -void show_suffix_and_prefix(struct dfu_file *file); - -#endif /* DFU_FILE_H */ diff --git a/macosx/src/dfu-util/src/dfu_load.c b/macosx/src/dfu-util/src/dfu_load.c deleted file mode 100644 index 64f7009df..000000000 --- a/macosx/src/dfu-util/src/dfu_load.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * DFU transfer routines - * - * This is supposed to be a general DFU implementation, as specified in the - * USB DFU 1.0 and 1.1 specification. - * - * The code was originally intended to interface with a USB device running the - * "sam7dfu" firmware (see http://www.openpcd.org/) on an AT91SAM7 processor. - * - * Copyright 2007-2008 Harald Welte - * Copyright 2013 Hans Petter Selasky - * Copyright 2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfu_load.h" -#include "quirks.h" - -int dfuload_do_upload(struct dfu_if *dif, int xfer_size, - int expected_size, int fd) -{ - int total_bytes = 0; - unsigned short transaction = 0; - unsigned char *buf; - int ret; - - buf = dfu_malloc(xfer_size); - - printf("Copying data from DFU device to PC\n"); - dfu_progress_bar("Upload", 0, 1); - - while (1) { - int rc; - rc = dfu_upload(dif->dev_handle, dif->interface, - xfer_size, transaction++, buf); - if (rc < 0) { - warnx("Error during upload"); - ret = rc; - goto out_free; - } - - dfu_file_write_crc(fd, 0, buf, rc); - total_bytes += rc; - - if (total_bytes < 0) - errx(EX_SOFTWARE, "Received too many bytes (wraparound)"); - - if (rc < xfer_size) { - /* last block, return */ - ret = total_bytes; - break; - } - dfu_progress_bar("Upload", total_bytes, expected_size); - } - ret = 0; - -out_free: - dfu_progress_bar("Upload", total_bytes, total_bytes); - if (total_bytes == 0) - printf("\nFailed.\n"); - free(buf); - if (verbose) - printf("Received a total of %i bytes\n", total_bytes); - if (expected_size != 0 && total_bytes != expected_size) - errx(EX_SOFTWARE, "Unexpected number of bytes uploaded from device"); - return ret; -} - -int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file) -{ - int bytes_sent; - int expected_size; - unsigned char *buf; - unsigned short transaction = 0; - struct dfu_status dst; - int ret; - - printf("Copying data from PC to DFU device\n"); - - buf = file->firmware; - expected_size = file->size.total - file->size.suffix; - bytes_sent = 0; - - dfu_progress_bar("Download", 0, 1); - while (bytes_sent < expected_size) { - int bytes_left; - int chunk_size; - - bytes_left = expected_size - bytes_sent; - if (bytes_left < xfer_size) - chunk_size = bytes_left; - else - chunk_size = xfer_size; - - ret = dfu_download(dif->dev_handle, dif->interface, - chunk_size, transaction++, chunk_size ? buf : NULL); - if (ret < 0) { - warnx("Error during download"); - goto out; - } - bytes_sent += chunk_size; - buf += chunk_size; - - do { - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during download get_status"); - goto out; - } - - if (dst.bState == DFU_STATE_dfuDNLOAD_IDLE || - dst.bState == DFU_STATE_dfuERROR) - break; - - /* Wait while device executes flashing */ - milli_sleep(dst.bwPollTimeout); - - } while (1); - if (dst.bStatus != DFU_STATUS_OK) { - printf(" failed!\n"); - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - ret = -1; - goto out; - } - dfu_progress_bar("Download", bytes_sent, bytes_sent + bytes_left); - } - - /* send one zero sized download request to signalize end */ - ret = dfu_download(dif->dev_handle, dif->interface, - 0, transaction, NULL); - if (ret < 0) { - errx(EX_IOERR, "Error sending completion packet"); - goto out; - } - - dfu_progress_bar("Download", bytes_sent, bytes_sent); - - if (verbose) - printf("Sent a total of %i bytes\n", bytes_sent); - -get_status: - /* Transition to MANIFEST_SYNC state */ - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - warnx("unable to read DFU status after completion"); - goto out; - } - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - - milli_sleep(dst.bwPollTimeout); - - /* FIXME: deal correctly with ManifestationTolerant=0 / WillDetach bits */ - switch (dst.bState) { - case DFU_STATE_dfuMANIFEST_SYNC: - case DFU_STATE_dfuMANIFEST: - /* some devices (e.g. TAS1020b) need some time before we - * can obtain the status */ - milli_sleep(1000); - goto get_status; - break; - case DFU_STATE_dfuIDLE: - break; - } - printf("Done!\n"); - -out: - return bytes_sent; -} diff --git a/macosx/src/dfu-util/src/dfu_load.h b/macosx/src/dfu-util/src/dfu_load.h deleted file mode 100644 index be23e9b4f..000000000 --- a/macosx/src/dfu-util/src/dfu_load.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef DFU_LOAD_H -#define DFU_LOAD_H - -int dfuload_do_upload(struct dfu_if *dif, int xfer_size, int expected_size, int fd); -int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file); - -#endif /* DFU_LOAD_H */ diff --git a/macosx/src/dfu-util/src/dfu_util.c b/macosx/src/dfu-util/src/dfu_util.c deleted file mode 100644 index b94c7ccd3..000000000 --- a/macosx/src/dfu-util/src/dfu_util.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Functions for detecting DFU USB entities - * - * Written by Harald Welte - * Copyright 2007-2008 by OpenMoko, Inc. - * Copyright 2013 Hans Petter Selasky - * - * Based on existing code of dfu-programmer-0.4 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfu_load.h" -#include "dfu_util.h" -#include "dfuse.h" -#include "quirks.h" - -#ifdef HAVE_USBPATH_H -#include -#endif - -/* - * Look for a descriptor in a concatenated descriptor list. Will - * return upon the first match of the given descriptor type. Returns length of - * found descriptor, limited to res_size - */ -static int find_descriptor(const uint8_t *desc_list, int list_len, - uint8_t desc_type, void *res_buf, int res_size) -{ - int p = 0; - - if (list_len < 2) - return (-1); - - while (p + 1 < list_len) { - int desclen; - - desclen = (int) desc_list[p]; - if (desclen == 0) { - warnx("Invalid descriptor list"); - return -1; - } - if (desc_list[p + 1] == desc_type) { - if (desclen > res_size) - desclen = res_size; - if (p + desclen > list_len) - desclen = list_len - p; - memcpy(res_buf, &desc_list[p], desclen); - return desclen; - } - p += (int) desc_list[p]; - } - return -1; -} - -static void probe_configuration(libusb_device *dev, struct libusb_device_descriptor *desc) -{ - struct usb_dfu_func_descriptor func_dfu; - libusb_device_handle *devh; - struct dfu_if *pdfu; - struct libusb_config_descriptor *cfg; - const struct libusb_interface_descriptor *intf; - const struct libusb_interface *uif; - char alt_name[MAX_DESC_STR_LEN + 1]; - char serial_name[MAX_DESC_STR_LEN + 1]; - int cfg_idx; - int intf_idx; - int alt_idx; - int ret; - int has_dfu; - - for (cfg_idx = 0; cfg_idx != desc->bNumConfigurations; cfg_idx++) { - memset(&func_dfu, 0, sizeof(func_dfu)); - has_dfu = 0; - - ret = libusb_get_config_descriptor(dev, cfg_idx, &cfg); - if (ret != 0) - return; - if (match_config_index > -1 && match_config_index != cfg->bConfigurationValue) { - libusb_free_config_descriptor(cfg); - continue; - } - - /* - * In some cases, noticably FreeBSD if uid != 0, - * the configuration descriptors are empty - */ - if (!cfg) - return; - - ret = find_descriptor(cfg->extra, cfg->extra_length, - USB_DT_DFU, &func_dfu, sizeof(func_dfu)); - if (ret > -1) - goto found_dfu; - - for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; - intf_idx++) { - uif = &cfg->interface[intf_idx]; - if (!uif) - break; - - for (alt_idx = 0; alt_idx < cfg->interface[intf_idx].num_altsetting; - alt_idx++) { - intf = &uif->altsetting[alt_idx]; - - ret = find_descriptor(intf->extra, intf->extra_length, USB_DT_DFU, - &func_dfu, sizeof(func_dfu)); - if (ret > -1) - goto found_dfu; - - if (intf->bInterfaceClass != 0xfe || - intf->bInterfaceSubClass != 1) - continue; - - has_dfu = 1; - } - } - if (has_dfu) { - /* - * Finally try to retrieve it requesting the - * device directly This is not supported on - * all devices for non-standard types - */ - if (libusb_open(dev, &devh) == 0) { - ret = libusb_get_descriptor(devh, USB_DT_DFU, 0, - (void *)&func_dfu, sizeof(func_dfu)); - libusb_close(devh); - if (ret > -1) - goto found_dfu; - } - warnx("Device has DFU interface, " - "but has no DFU functional descriptor"); - - /* fake version 1.0 */ - func_dfu.bLength = 7; - func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); - goto found_dfu; - } - libusb_free_config_descriptor(cfg); - continue; - -found_dfu: - if (func_dfu.bLength == 7) { - printf("Deducing device DFU version from functional descriptor " - "length\n"); - func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); - } else if (func_dfu.bLength < 9) { - printf("Error obtaining DFU functional descriptor\n"); - printf("Please report this as a bug!\n"); - printf("Warning: Assuming DFU version 1.0\n"); - func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); - printf("Warning: Transfer size can not be detected\n"); - func_dfu.wTransferSize = 0; - } - - for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; - intf_idx++) { - if (match_iface_index > -1 && match_iface_index != intf_idx) - continue; - - uif = &cfg->interface[intf_idx]; - if (!uif) - break; - - for (alt_idx = 0; - alt_idx < uif->num_altsetting; alt_idx++) { - int dfu_mode; - - intf = &uif->altsetting[alt_idx]; - - if (intf->bInterfaceClass != 0xfe || - intf->bInterfaceSubClass != 1) - continue; - - dfu_mode = (intf->bInterfaceProtocol == 2); - /* e.g. DSO Nano has bInterfaceProtocol 0 instead of 2 */ - if (func_dfu.bcdDFUVersion == 0x011a && intf->bInterfaceProtocol == 0) - dfu_mode = 1; - - if (dfu_mode && - match_iface_alt_index > -1 && match_iface_alt_index != alt_idx) - continue; - - if (dfu_mode) { - if ((match_vendor_dfu >= 0 && match_vendor_dfu != desc->idVendor) || - (match_product_dfu >= 0 && match_product_dfu != desc->idProduct)) { - continue; - } - } else { - if ((match_vendor >= 0 && match_vendor != desc->idVendor) || - (match_product >= 0 && match_product != desc->idProduct)) { - continue; - } - } - - if (libusb_open(dev, &devh)) { - warnx("Cannot open DFU device %04x:%04x", desc->idVendor, desc->idProduct); - break; - } - if (intf->iInterface != 0) - ret = libusb_get_string_descriptor_ascii(devh, - intf->iInterface, (void *)alt_name, MAX_DESC_STR_LEN); - else - ret = -1; - if (ret < 1) - strcpy(alt_name, "UNKNOWN"); - if (desc->iSerialNumber != 0) - ret = libusb_get_string_descriptor_ascii(devh, - desc->iSerialNumber, (void *)serial_name, MAX_DESC_STR_LEN); - else - ret = -1; - if (ret < 1) - strcpy(serial_name, "UNKNOWN"); - libusb_close(devh); - - if (dfu_mode && - match_iface_alt_name != NULL && strcmp(alt_name, match_iface_alt_name)) - continue; - - if (dfu_mode) { - if (match_serial_dfu != NULL && strcmp(match_serial_dfu, serial_name)) - continue; - } else { - if (match_serial != NULL && strcmp(match_serial, serial_name)) - continue; - } - - pdfu = dfu_malloc(sizeof(*pdfu)); - - memset(pdfu, 0, sizeof(*pdfu)); - - pdfu->func_dfu = func_dfu; - pdfu->dev = libusb_ref_device(dev); - pdfu->quirks = get_quirks(desc->idVendor, - desc->idProduct, desc->bcdDevice); - pdfu->vendor = desc->idVendor; - pdfu->product = desc->idProduct; - pdfu->bcdDevice = desc->bcdDevice; - pdfu->configuration = cfg->bConfigurationValue; - pdfu->interface = intf->bInterfaceNumber; - pdfu->altsetting = intf->bAlternateSetting; - pdfu->devnum = libusb_get_device_address(dev); - pdfu->busnum = libusb_get_bus_number(dev); - pdfu->alt_name = strdup(alt_name); - if (pdfu->alt_name == NULL) - errx(EX_SOFTWARE, "Out of memory"); - pdfu->serial_name = strdup(serial_name); - if (pdfu->serial_name == NULL) - errx(EX_SOFTWARE, "Out of memory"); - if (dfu_mode) - pdfu->flags |= DFU_IFF_DFU; - if (pdfu->quirks & QUIRK_FORCE_DFU11) { - pdfu->func_dfu.bcdDFUVersion = - libusb_cpu_to_le16(0x0110); - } - pdfu->bMaxPacketSize0 = desc->bMaxPacketSize0; - - /* queue into list */ - pdfu->next = dfu_root; - dfu_root = pdfu; - } - } - libusb_free_config_descriptor(cfg); - } -} - -void probe_devices(libusb_context *ctx) -{ - libusb_device **list; - ssize_t num_devs; - ssize_t i; - - num_devs = libusb_get_device_list(ctx, &list); - for (i = 0; i < num_devs; ++i) { - struct libusb_device_descriptor desc; - struct libusb_device *dev = list[i]; - - if (match_bus > -1 && match_bus != libusb_get_bus_number(dev)) - continue; - if (match_device > -1 && match_device != libusb_get_device_address(dev)) - continue; - if (libusb_get_device_descriptor(dev, &desc)) - continue; - probe_configuration(dev, &desc); - } - libusb_free_device_list(list, 0); -} - -void disconnect_devices(void) -{ - struct dfu_if *pdfu; - struct dfu_if *prev = NULL; - - for (pdfu = dfu_root; pdfu != NULL; pdfu = pdfu->next) { - free(prev); - libusb_unref_device(pdfu->dev); - free(pdfu->alt_name); - free(pdfu->serial_name); - prev = pdfu; - } - free(prev); - dfu_root = NULL; -} - -void print_dfu_if(struct dfu_if *dfu_if) -{ - printf("Found %s: [%04x:%04x] ver=%04x, devnum=%u, cfg=%u, intf=%u, " - "alt=%u, name=\"%s\", serial=\"%s\"\n", - dfu_if->flags & DFU_IFF_DFU ? "DFU" : "Runtime", - dfu_if->vendor, dfu_if->product, - dfu_if->bcdDevice, dfu_if->devnum, - dfu_if->configuration, dfu_if->interface, - dfu_if->altsetting, dfu_if->alt_name, - dfu_if->serial_name); -} - -/* Walk the device tree and print out DFU devices */ -void list_dfu_interfaces(void) -{ - struct dfu_if *pdfu; - - for (pdfu = dfu_root; pdfu != NULL; pdfu = pdfu->next) - print_dfu_if(pdfu); -} diff --git a/macosx/src/dfu-util/src/dfu_util.h b/macosx/src/dfu-util/src/dfu_util.h deleted file mode 100644 index fc0c19dca..000000000 --- a/macosx/src/dfu-util/src/dfu_util.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef DFU_UTIL_H -#define DFU_UTIL_H - -/* USB string descriptor should contain max 126 UTF-16 characters - * but 253 would even accomodate any UTF-8 encoding */ -#define MAX_DESC_STR_LEN 253 - -enum mode { - MODE_NONE, - MODE_VERSION, - MODE_LIST, - MODE_DETACH, - MODE_UPLOAD, - MODE_DOWNLOAD -}; - -extern struct dfu_if *dfu_root; -extern int match_bus; -extern int match_device; -extern int match_vendor; -extern int match_product; -extern int match_vendor_dfu; -extern int match_product_dfu; -extern int match_config_index; -extern int match_iface_index; -extern int match_iface_alt_index; -extern const char *match_iface_alt_name; -extern const char *match_serial; -extern const char *match_serial_dfu; - -void probe_devices(libusb_context *); -void disconnect_devices(void); -void print_dfu_if(struct dfu_if *); -void list_dfu_interfaces(void); - -#endif /* DFU_UTIL_H */ diff --git a/macosx/src/dfu-util/src/dfuse.c b/macosx/src/dfu-util/src/dfuse.c deleted file mode 100644 index fce29fed6..000000000 --- a/macosx/src/dfu-util/src/dfuse.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - * DfuSe specific functions - * - * This implements the ST Microsystems DFU extensions (DfuSe) - * as per the DfuSe 1.1a specification (ST documents AN3156, AN2606) - * The DfuSe file format is described in ST document UM0391. - * - * Copyright 2010-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfuse.h" -#include "dfuse_mem.h" - -#define DFU_TIMEOUT 5000 - -extern int verbose; -static unsigned int last_erased_page = 1; /* non-aligned value, won't match */ -static struct memsegment *mem_layout; -static unsigned int dfuse_address = 0; -static unsigned int dfuse_length = 0; -static int dfuse_force = 0; -static int dfuse_leave = 0; -static int dfuse_unprotect = 0; -static int dfuse_mass_erase = 0; - -unsigned int quad2uint(unsigned char *p) -{ - return (*p + (*(p + 1) << 8) + (*(p + 2) << 16) + (*(p + 3) << 24)); -} - -void dfuse_parse_options(const char *options) -{ - char *end; - const char *endword; - unsigned int number; - - /* address, possibly empty, must be first */ - if (*options != ':') { - endword = strchr(options, ':'); - if (!endword) - endword = options + strlen(options); /* GNU strchrnul */ - - number = strtoul(options, &end, 0); - if (end == endword) { - dfuse_address = number; - } else { - errx(EX_IOERR, "Invalid dfuse address: %s", options); - } - options = endword; - } - - while (*options) { - if (*options == ':') { - options++; - continue; - } - endword = strchr(options, ':'); - if (!endword) - endword = options + strlen(options); - - if (!strncmp(options, "force", endword - options)) { - dfuse_force++; - options += 5; - continue; - } - if (!strncmp(options, "leave", endword - options)) { - dfuse_leave = 1; - options += 5; - continue; - } - if (!strncmp(options, "unprotect", endword - options)) { - dfuse_unprotect = 1; - options += 9; - continue; - } - if (!strncmp(options, "mass-erase", endword - options)) { - dfuse_mass_erase = 1; - options += 10; - continue; - } - - /* any valid number is interpreted as upload length */ - number = strtoul(options, &end, 0); - if (end == endword) { - dfuse_length = number; - } else { - errx(EX_IOERR, "Invalid dfuse modifier: %s", options); - } - options = endword; - } -} - -/* DFU_UPLOAD request for DfuSe 1.1a */ -int dfuse_upload(struct dfu_if *dif, const unsigned short length, - unsigned char *data, unsigned short transaction) -{ - int status; - - status = libusb_control_transfer(dif->dev_handle, - /* bmRequestType */ LIBUSB_ENDPOINT_IN | - LIBUSB_REQUEST_TYPE_CLASS | - LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_UPLOAD, - /* wValue */ transaction, - /* wIndex */ dif->interface, - /* Data */ data, - /* wLength */ length, - DFU_TIMEOUT); - if (status < 0) { - errx(EX_IOERR, "%s: libusb_control_msg returned %d", - __FUNCTION__, status); - } - return status; -} - -/* DFU_DNLOAD request for DfuSe 1.1a */ -int dfuse_download(struct dfu_if *dif, const unsigned short length, - unsigned char *data, unsigned short transaction) -{ - int status; - - status = libusb_control_transfer(dif->dev_handle, - /* bmRequestType */ LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_CLASS | - LIBUSB_RECIPIENT_INTERFACE, - /* bRequest */ DFU_DNLOAD, - /* wValue */ transaction, - /* wIndex */ dif->interface, - /* Data */ data, - /* wLength */ length, - DFU_TIMEOUT); - if (status < 0) { - errx(EX_IOERR, "%s: libusb_control_transfer returned %d", - __FUNCTION__, status); - } - return status; -} - -/* DfuSe only commands */ -/* Leaves the device in dfuDNLOAD-IDLE state */ -int dfuse_special_command(struct dfu_if *dif, unsigned int address, - enum dfuse_command command) -{ - const char* dfuse_command_name[] = { "SET_ADDRESS" , "ERASE_PAGE", - "MASS_ERASE", "READ_UNPROTECT"}; - unsigned char buf[5]; - int length; - int ret; - struct dfu_status dst; - int firstpoll = 1; - - if (command == ERASE_PAGE) { - struct memsegment *segment; - int page_size; - - segment = find_segment(mem_layout, address); - if (!segment || !(segment->memtype & DFUSE_ERASABLE)) { - errx(EX_IOERR, "Page at 0x%08x can not be erased", - address); - } - page_size = segment->pagesize; - if (verbose > 1) - printf("Erasing page size %i at address 0x%08x, page " - "starting at 0x%08x\n", page_size, address, - address & ~(page_size - 1)); - buf[0] = 0x41; /* Erase command */ - length = 5; - last_erased_page = address & ~(page_size - 1); - } else if (command == SET_ADDRESS) { - if (verbose > 2) - printf(" Setting address pointer to 0x%08x\n", - address); - buf[0] = 0x21; /* Set Address Pointer command */ - length = 5; - } else if (command == MASS_ERASE) { - buf[0] = 0x41; /* Mass erase command when length = 1 */ - length = 1; - } else if (command == READ_UNPROTECT) { - buf[0] = 0x92; - length = 1; - } else { - errx(EX_IOERR, "Non-supported special command %d", command); - } - buf[1] = address & 0xff; - buf[2] = (address >> 8) & 0xff; - buf[3] = (address >> 16) & 0xff; - buf[4] = (address >> 24) & 0xff; - - ret = dfuse_download(dif, length, buf, 0); - if (ret < 0) { - errx(EX_IOERR, "Error during special command \"%s\" download", - dfuse_command_name[command]); - } - do { - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during special command \"%s\" get_status", - dfuse_command_name[command]); - } - if (firstpoll) { - firstpoll = 0; - if (dst.bState != DFU_STATE_dfuDNBUSY) { - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - errx(EX_IOERR, "Wrong state after command \"%s\" download", - dfuse_command_name[command]); - } - } - /* wait while command is executed */ - if (verbose) - printf(" Poll timeout %i ms\n", dst.bwPollTimeout); - milli_sleep(dst.bwPollTimeout); - if (command == READ_UNPROTECT) - return ret; - } while (dst.bState == DFU_STATE_dfuDNBUSY); - - if (dst.bStatus != DFU_STATUS_OK) { - errx(EX_IOERR, "%s not correctly executed", - dfuse_command_name[command]); - } - return ret; -} - -int dfuse_dnload_chunk(struct dfu_if *dif, unsigned char *data, int size, - int transaction) -{ - int bytes_sent; - struct dfu_status dst; - int ret; - - ret = dfuse_download(dif, size, size ? data : NULL, transaction); - if (ret < 0) { - errx(EX_IOERR, "Error during download"); - return ret; - } - bytes_sent = ret; - - do { - ret = dfu_get_status(dif, &dst); - if (ret < 0) { - errx(EX_IOERR, "Error during download get_status"); - return ret; - } - milli_sleep(dst.bwPollTimeout); - } while (dst.bState != DFU_STATE_dfuDNLOAD_IDLE && - dst.bState != DFU_STATE_dfuERROR && - dst.bState != DFU_STATE_dfuMANIFEST); - - if (dst.bState == DFU_STATE_dfuMANIFEST) - printf("Transitioning to dfuMANIFEST state\n"); - - if (dst.bStatus != DFU_STATUS_OK) { - printf(" failed!\n"); - printf("state(%u) = %s, status(%u) = %s\n", dst.bState, - dfu_state_to_string(dst.bState), dst.bStatus, - dfu_status_to_string(dst.bStatus)); - return -1; - } - return bytes_sent; -} - -int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd, - const char *dfuse_options) -{ - int total_bytes = 0; - int upload_limit = 0; - unsigned char *buf; - int transaction; - int ret; - - buf = dfu_malloc(xfer_size); - - if (dfuse_options) - dfuse_parse_options(dfuse_options); - if (dfuse_length) - upload_limit = dfuse_length; - if (dfuse_address) { - struct memsegment *segment; - - mem_layout = parse_memory_layout((char *)dif->alt_name); - if (!mem_layout) - errx(EX_IOERR, "Failed to parse memory layout"); - - segment = find_segment(mem_layout, dfuse_address); - if (!dfuse_force && - (!segment || !(segment->memtype & DFUSE_READABLE))) - errx(EX_IOERR, "Page at 0x%08x is not readable", - dfuse_address); - - if (!upload_limit) { - upload_limit = segment->end - dfuse_address + 1; - printf("Limiting upload to end of memory segment, " - "%i bytes\n", upload_limit); - } - dfuse_special_command(dif, dfuse_address, SET_ADDRESS); - dfu_abort_to_idle(dif); - } else { - /* Boot loader decides the start address, unknown to us */ - /* Use a short length to lower risk of running out of bounds */ - if (!upload_limit) - upload_limit = 0x4000; - printf("Limiting default upload to %i bytes\n", upload_limit); - } - - dfu_progress_bar("Upload", 0, 1); - - transaction = 2; - while (1) { - int rc; - - /* last chunk can be smaller than original xfer_size */ - if (upload_limit - total_bytes < xfer_size) - xfer_size = upload_limit - total_bytes; - rc = dfuse_upload(dif, xfer_size, buf, transaction++); - if (rc < 0) { - ret = rc; - goto out_free; - } - - dfu_file_write_crc(fd, 0, buf, rc); - total_bytes += rc; - - if (total_bytes < 0) - errx(EX_SOFTWARE, "Received too many bytes"); - - if (rc < xfer_size || total_bytes >= upload_limit) { - /* last block, return successfully */ - ret = total_bytes; - break; - } - dfu_progress_bar("Upload", total_bytes, upload_limit); - } - - dfu_progress_bar("Upload", total_bytes, total_bytes); - - dfu_abort_to_idle(dif); - if (dfuse_leave) { - dfuse_special_command(dif, dfuse_address, SET_ADDRESS); - dfuse_dnload_chunk(dif, NULL, 0, 2); /* Zero-size */ - } - - out_free: - free(buf); - - return ret; -} - -/* Writes an element of any size to the device, taking care of page erases */ -/* returns 0 on success, otherwise -EINVAL */ -int dfuse_dnload_element(struct dfu_if *dif, unsigned int dwElementAddress, - unsigned int dwElementSize, unsigned char *data, - int xfer_size) -{ - int p; - int ret; - struct memsegment *segment; - - /* Check at least that we can write to the last address */ - segment = - find_segment(mem_layout, dwElementAddress + dwElementSize - 1); - if (!segment || !(segment->memtype & DFUSE_WRITEABLE)) { - errx(EX_IOERR, "Last page at 0x%08x is not writeable", - dwElementAddress + dwElementSize - 1); - } - - dfu_progress_bar("Download", 0, 1); - - for (p = 0; p < (int)dwElementSize; p += xfer_size) { - int page_size; - unsigned int erase_address; - unsigned int address = dwElementAddress + p; - int chunk_size = xfer_size; - - segment = find_segment(mem_layout, address); - if (!segment || !(segment->memtype & DFUSE_WRITEABLE)) { - errx(EX_IOERR, "Page at 0x%08x is not writeable", - address); - } - page_size = segment->pagesize; - - /* check if this is the last chunk */ - if (p + chunk_size > (int)dwElementSize) - chunk_size = dwElementSize - p; - - /* Erase only for flash memory downloads */ - if ((segment->memtype & DFUSE_ERASABLE) && !dfuse_mass_erase) { - /* erase all involved pages */ - for (erase_address = address; - erase_address < address + chunk_size; - erase_address += page_size) - if ((erase_address & ~(page_size - 1)) != - last_erased_page) - dfuse_special_command(dif, - erase_address, - ERASE_PAGE); - - if (((address + chunk_size - 1) & ~(page_size - 1)) != - last_erased_page) { - if (verbose > 2) - printf(" Chunk extends into next page," - " erase it as well\n"); - dfuse_special_command(dif, - address + chunk_size - 1, - ERASE_PAGE); - } - } - - if (verbose) { - printf(" Download from image offset " - "%08x to memory %08x-%08x, size %i\n", - p, address, address + chunk_size - 1, - chunk_size); - } else { - dfu_progress_bar("Download", p, dwElementSize); - } - - dfuse_special_command(dif, address, SET_ADDRESS); - - /* transaction = 2 for no address offset */ - ret = dfuse_dnload_chunk(dif, data + p, chunk_size, 2); - if (ret != chunk_size) { - errx(EX_IOERR, "Failed to write whole chunk: " - "%i of %i bytes", ret, chunk_size); - return -EINVAL; - } - } - if (!verbose) - dfu_progress_bar("Download", dwElementSize, dwElementSize); - return 0; -} - -static void -dfuse_memcpy(unsigned char *dst, unsigned char **src, int *rem, int size) -{ - if (size > *rem) { - errx(EX_IOERR, "Corrupt DfuSe file: " - "Cannot read %d bytes from %d bytes", size, *rem); - } - if (dst != NULL) - memcpy(dst, *src, size); - (*src) += size; - (*rem) -= size; -} - -/* Download raw binary file to DfuSe device */ -int dfuse_do_bin_dnload(struct dfu_if *dif, int xfer_size, - struct dfu_file *file, unsigned int start_address) -{ - unsigned int dwElementAddress; - unsigned int dwElementSize; - unsigned char *data; - int ret; - - dwElementAddress = start_address; - dwElementSize = file->size.total - - file->size.suffix - file->size.prefix; - - printf("Downloading to address = 0x%08x, size = %i\n", - dwElementAddress, dwElementSize); - - data = file->firmware + file->size.prefix; - - ret = dfuse_dnload_element(dif, dwElementAddress, dwElementSize, data, - xfer_size); - if (ret != 0) - goto out_free; - - printf("File downloaded successfully\n"); - ret = dwElementSize; - - out_free: - return ret; -} - -/* Parse a DfuSe file and download contents to device */ -int dfuse_do_dfuse_dnload(struct dfu_if *dif, int xfer_size, - struct dfu_file *file) -{ - uint8_t dfuprefix[11]; - uint8_t targetprefix[274]; - uint8_t elementheader[8]; - int image; - int element; - int bTargets; - int bAlternateSetting; - int dwNbElements; - unsigned int dwElementAddress; - unsigned int dwElementSize; - uint8_t *data; - int ret; - int rem; - int bFirstAddressSaved = 0; - - rem = file->size.total - file->size.prefix - file->size.suffix; - data = file->firmware + file->size.prefix; - - /* Must be larger than a minimal DfuSe header and suffix */ - if (rem < (int)(sizeof(dfuprefix) + - sizeof(targetprefix) + sizeof(elementheader))) { - errx(EX_SOFTWARE, "File too small for a DfuSe file"); - } - - dfuse_memcpy(dfuprefix, &data, &rem, sizeof(dfuprefix)); - - if (strncmp((char *)dfuprefix, "DfuSe", 5)) { - errx(EX_IOERR, "No valid DfuSe signature"); - return -EINVAL; - } - if (dfuprefix[5] != 0x01) { - errx(EX_IOERR, "DFU format revision %i not supported", - dfuprefix[5]); - return -EINVAL; - } - bTargets = dfuprefix[10]; - printf("file contains %i DFU images\n", bTargets); - - for (image = 1; image <= bTargets; image++) { - printf("parsing DFU image %i\n", image); - dfuse_memcpy(targetprefix, &data, &rem, sizeof(targetprefix)); - if (strncmp((char *)targetprefix, "Target", 6)) { - errx(EX_IOERR, "No valid target signature"); - return -EINVAL; - } - bAlternateSetting = targetprefix[6]; - dwNbElements = quad2uint((unsigned char *)targetprefix + 270); - printf("image for alternate setting %i, ", bAlternateSetting); - printf("(%i elements, ", dwNbElements); - printf("total size = %i)\n", - quad2uint((unsigned char *)targetprefix + 266)); - if (bAlternateSetting != dif->altsetting) - printf("Warning: Image does not match current alternate" - " setting.\n" - "Please rerun with the correct -a option setting" - " to download this image!\n"); - for (element = 1; element <= dwNbElements; element++) { - printf("parsing element %i, ", element); - dfuse_memcpy(elementheader, &data, &rem, sizeof(elementheader)); - dwElementAddress = - quad2uint((unsigned char *)elementheader); - dwElementSize = - quad2uint((unsigned char *)elementheader + 4); - printf("address = 0x%08x, ", dwElementAddress); - printf("size = %i\n", dwElementSize); - - if (!bFirstAddressSaved) { - bFirstAddressSaved = 1; - dfuse_address = dwElementAddress; - } - /* sanity check */ - if ((int)dwElementSize > rem) - errx(EX_SOFTWARE, "File too small for element size"); - - if (bAlternateSetting == dif->altsetting) { - ret = dfuse_dnload_element(dif, dwElementAddress, - dwElementSize, data, xfer_size); - } else { - ret = 0; - } - - /* advance read pointer */ - dfuse_memcpy(NULL, &data, &rem, dwElementSize); - - if (ret != 0) - return ret; - } - } - - if (rem != 0) - warnx("%d bytes leftover", rem); - - printf("done parsing DfuSe file\n"); - - return 0; -} - -int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file, - const char *dfuse_options) -{ - int ret; - - if (dfuse_options) - dfuse_parse_options(dfuse_options); - mem_layout = parse_memory_layout((char *)dif->alt_name); - if (!mem_layout) { - errx(EX_IOERR, "Failed to parse memory layout"); - } - if (dfuse_unprotect) { - if (!dfuse_force) { - errx(EX_IOERR, "The read unprotect command " - "will erase the flash memory" - "and can only be used with force\n"); - } - dfuse_special_command(dif, 0, READ_UNPROTECT); - printf("Device disconnects, erases flash and resets now\n"); - exit(0); - } - if (dfuse_mass_erase) { - if (!dfuse_force) { - errx(EX_IOERR, "The mass erase command " - "can only be used with force"); - } - printf("Performing mass erase, this can take a moment\n"); - dfuse_special_command(dif, 0, MASS_ERASE); - } - if (dfuse_address) { - if (file->bcdDFU == 0x11a) { - errx(EX_IOERR, "This is a DfuSe file, not " - "meant for raw download"); - } - ret = dfuse_do_bin_dnload(dif, xfer_size, file, dfuse_address); - } else { - if (file->bcdDFU != 0x11a) { - warnx("Only DfuSe file version 1.1a is supported"); - errx(EX_IOERR, "(for raw binary download, use the " - "--dfuse-address option)"); - } - ret = dfuse_do_dfuse_dnload(dif, xfer_size, file); - } - free_segment_list(mem_layout); - - dfu_abort_to_idle(dif); - - if (dfuse_leave) { - dfuse_special_command(dif, dfuse_address, SET_ADDRESS); - dfuse_dnload_chunk(dif, NULL, 0, 2); /* Zero-size */ - } - return ret; -} diff --git a/macosx/src/dfu-util/src/dfuse.h b/macosx/src/dfu-util/src/dfuse.h deleted file mode 100644 index ed1108cfc..000000000 --- a/macosx/src/dfu-util/src/dfuse.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This implements the ST Microsystems DFU extensions (DfuSe) - * as per the DfuSe 1.1a specification (Document UM0391) - * - * (C) 2010-2012 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DFUSE_H -#define DFUSE_H - -#include "dfu.h" - -enum dfuse_command { SET_ADDRESS, ERASE_PAGE, MASS_ERASE, READ_UNPROTECT }; - -int dfuse_special_command(struct dfu_if *dif, unsigned int address, - enum dfuse_command command); -int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd, - const char *dfuse_options); -int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file, - const char *dfuse_options); - -#endif /* DFUSE_H */ diff --git a/macosx/src/dfu-util/src/dfuse_mem.c b/macosx/src/dfu-util/src/dfuse_mem.c deleted file mode 100644 index a91aacf5f..000000000 --- a/macosx/src/dfu-util/src/dfuse_mem.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Helper functions for reading the memory map of a device - * following the ST DfuSe 1.1a specification. - * - * Copyright 2011-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" -#include "dfuse_mem.h" - -int add_segment(struct memsegment **segment_list, struct memsegment segment) -{ - struct memsegment *new_element; - - new_element = dfu_malloc(sizeof(struct memsegment)); - *new_element = segment; - new_element->next = NULL; - - if (*segment_list == NULL) - /* list can be empty on first call */ - *segment_list = new_element; - else { - struct memsegment *next_element; - - /* find last element in list */ - next_element = *segment_list; - while (next_element->next != NULL) - next_element = next_element->next; - next_element->next = new_element; - } - return 0; -} - -struct memsegment *find_segment(struct memsegment *segment_list, - unsigned int address) -{ - while (segment_list != NULL) { - if (segment_list->start <= address && - segment_list->end >= address) - return segment_list; - segment_list = segment_list->next; - } - return NULL; -} - -void free_segment_list(struct memsegment *segment_list) -{ - struct memsegment *next_element; - - while (segment_list->next != NULL) { - next_element = segment_list->next; - free(segment_list); - segment_list = next_element; - } - free(segment_list); -} - -/* Parse memory map from interface descriptor string - * encoded as per ST document UM0424 section 4.3.2. - */ -struct memsegment *parse_memory_layout(char *intf_desc) -{ - - char multiplier, memtype; - unsigned int address; - int sectors, size; - char *name, *typestring; - int ret; - int count = 0; - char separator; - int scanned; - struct memsegment *segment_list = NULL; - struct memsegment segment; - - name = dfu_malloc(strlen(intf_desc)); - - ret = sscanf(intf_desc, "@%[^/]%n", name, &scanned); - if (ret < 1) { - free(name); - warnx("Could not read name, sscanf returned %d", ret); - return NULL; - } - printf("DfuSe interface name: \"%s\"\n", name); - - intf_desc += scanned; - typestring = dfu_malloc(strlen(intf_desc)); - - while (ret = sscanf(intf_desc, "/0x%x/%n", &address, &scanned), - ret > 0) { - - intf_desc += scanned; - while (ret = sscanf(intf_desc, "%d*%d%c%[^,/]%n", - §ors, &size, &multiplier, typestring, - &scanned), ret > 2) { - intf_desc += scanned; - - count++; - memtype = 0; - if (ret == 4) { - if (strlen(typestring) == 1 - && typestring[0] != '/') - memtype = typestring[0]; - else { - warnx("Parsing type identifier '%s' " - "failed for segment %i", - typestring, count); - continue; - } - } - - /* Quirk for STM32F4 devices */ - if (strcmp(name, "Device Feature") == 0) - memtype = 'e'; - - switch (multiplier) { - case 'B': - break; - case 'K': - size *= 1024; - break; - case 'M': - size *= 1024 * 1024; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - if (!memtype) { - warnx("Non-valid multiplier '%c', " - "interpreted as type " - "identifier instead", - multiplier); - memtype = multiplier; - break; - } - /* fallthrough if memtype was already set */ - default: - warnx("Non-valid multiplier '%c', " - "assuming bytes", multiplier); - } - - if (!memtype) { - warnx("No valid type for segment %d\n", count); - continue; - } - - segment.start = address; - segment.end = address + sectors * size - 1; - segment.pagesize = size; - segment.memtype = memtype & 7; - add_segment(&segment_list, segment); - - if (verbose) - printf("Memory segment at 0x%08x %3d x %4d = " - "%5d (%s%s%s)\n", - address, sectors, size, sectors * size, - memtype & DFUSE_READABLE ? "r" : "", - memtype & DFUSE_ERASABLE ? "e" : "", - memtype & DFUSE_WRITEABLE ? "w" : ""); - - address += sectors * size; - - separator = *intf_desc; - if (separator == ',') - intf_desc += 1; - else - break; - } /* while per segment */ - - } /* while per address */ - free(name); - free(typestring); - - return segment_list; -} diff --git a/macosx/src/dfu-util/src/dfuse_mem.h b/macosx/src/dfu-util/src/dfuse_mem.h deleted file mode 100644 index 0181f0c16..000000000 --- a/macosx/src/dfu-util/src/dfuse_mem.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Helper functions for reading the memory map in a device - * following the ST DfuSe 1.1a specification. - * - * (C) 2011 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef DFUSE_MEM_H -#define DFUSE_MEM_H - -#define DFUSE_READABLE 1 -#define DFUSE_ERASABLE 2 -#define DFUSE_WRITEABLE 4 - -struct memsegment { - unsigned int start; - unsigned int end; - int pagesize; - int memtype; - struct memsegment *next; -}; - -int add_segment(struct memsegment **list, struct memsegment new_element); - -struct memsegment *find_segment(struct memsegment *list, unsigned int address); - -void free_segment_list(struct memsegment *list); - -struct memsegment *parse_memory_layout(char *intf_desc_str); - -#endif /* DFUSE_MEM_H */ diff --git a/macosx/src/dfu-util/src/main.c b/macosx/src/dfu-util/src/main.c deleted file mode 100644 index acaed2f08..000000000 --- a/macosx/src/dfu-util/src/main.c +++ /dev/null @@ -1,699 +0,0 @@ -/* - * dfu-util - * - * Copyright 2007-2008 by OpenMoko, Inc. - * Copyright 2013-2014 Hans Petter Selasky - * - * Written by Harald Welte - * - * Based on existing code of dfu-programmer-0.4 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu.h" -#include "usb_dfu.h" -#include "dfu_file.h" -#include "dfu_load.h" -#include "dfu_util.h" -#include "dfuse.h" -#include "quirks.h" - -#ifdef HAVE_USBPATH_H -#include -#endif - -int verbose = 0; - -struct dfu_if *dfu_root = NULL; - -int match_bus = -1; -int match_device = -1; -int match_vendor = -1; -int match_product = -1; -int match_vendor_dfu = -1; -int match_product_dfu = -1; -int match_config_index = -1; -int match_iface_index = -1; -int match_iface_alt_index = -1; -const char *match_iface_alt_name = NULL; -const char *match_serial = NULL; -const char *match_serial_dfu = NULL; - -static int parse_match_value(const char *str, int default_value) -{ - char *remainder; - int value; - - if (str == NULL) { - value = default_value; - } else if (*str == '*') { - value = -1; /* Match anything */ - } else if (*str == '-') { - value = 0x10000; /* Impossible vendor/product ID */ - } else { - value = strtoul(str, &remainder, 16); - if (remainder == str) { - value = default_value; - } - } - return value; -} - -static void parse_vendprod(const char *str) -{ - const char *comma; - const char *colon; - - /* Default to match any DFU device in runtime or DFU mode */ - match_vendor = -1; - match_product = -1; - match_vendor_dfu = -1; - match_product_dfu = -1; - - comma = strchr(str, ','); - if (comma == str) { - /* DFU mode vendor/product being specified without any runtime - * vendor/product specification, so don't match any runtime device */ - match_vendor = match_product = 0x10000; - } else { - colon = strchr(str, ':'); - if (colon != NULL) { - ++colon; - if ((comma != NULL) && (colon > comma)) { - colon = NULL; - } - } - match_vendor = parse_match_value(str, match_vendor); - match_product = parse_match_value(colon, match_product); - if (comma != NULL) { - /* Both runtime and DFU mode vendor/product specifications are - * available, so default DFU mode match components to the given - * runtime match components */ - match_vendor_dfu = match_vendor; - match_product_dfu = match_product; - } - } - if (comma != NULL) { - ++comma; - colon = strchr(comma, ':'); - if (colon != NULL) { - ++colon; - } - match_vendor_dfu = parse_match_value(comma, match_vendor_dfu); - match_product_dfu = parse_match_value(colon, match_product_dfu); - } -} - -static void parse_serial(char *str) -{ - char *comma; - - match_serial = str; - comma = strchr(str, ','); - if (comma == NULL) { - match_serial_dfu = match_serial; - } else { - *comma++ = 0; - match_serial_dfu = comma; - } - if (*match_serial == 0) match_serial = NULL; - if (*match_serial_dfu == 0) match_serial_dfu = NULL; -} - -#ifdef HAVE_USBPATH_H - -static int resolve_device_path(char *path) -{ - int res; - - res = usb_path2devnum(path); - if (res < 0) - return -EINVAL; - if (!res) - return 0; - - match_bus = atoi(path); - match_device = res; - - return 0; -} - -#else /* HAVE_USBPATH_H */ - -static int resolve_device_path(char *path) -{ - (void)path; /* Eliminate unused variable warning */ - errx(EX_SOFTWARE, "USB device paths are not supported by this dfu-util.\n"); -} - -#endif /* !HAVE_USBPATH_H */ - -static void help(void) -{ - fprintf(stderr, "Usage: dfu-util [options] ...\n" - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -v --verbose\t\t\tPrint verbose debug statements\n" - " -l --list\t\t\tList currently attached DFU capable devices\n"); - fprintf(stderr, " -e --detach\t\t\tDetach currently attached DFU capable devices\n" - " -E --detach-delay seconds\tTime to wait before reopening a device after detach\n" - " -d --device :[,:]\n" - "\t\t\t\tSpecify Vendor/Product ID(s) of DFU device\n" - " -p --path \tSpecify path to DFU device\n" - " -c --cfg \t\tSpecify the Configuration of DFU device\n" - " -i --intf \t\tSpecify the DFU Interface number\n" - " -S --serial [,]\n" - "\t\t\t\tSpecify Serial String of DFU device\n" - " -a --alt \t\tSpecify the Altsetting of the DFU Interface\n" - "\t\t\t\tby name or by number\n"); - fprintf(stderr, " -t --transfer-size \tSpecify the number of bytes per USB Transfer\n" - " -U --upload \t\tRead firmware from device into \n" - " -Z --upload-size \tSpecify the expected upload size in bytes\n" - " -D --download \t\tWrite firmware from into device\n" - " -R --reset\t\t\tIssue USB Reset signalling once we're finished\n" - " -s --dfuse-address
\tST DfuSe mode, specify target address for\n" - "\t\t\t\traw file download or upload. Not applicable for\n" - "\t\t\t\tDfuSe file (.dfu) downloads\n" - ); - exit(EX_USAGE); -} - -static void print_version(void) -{ - printf(PACKAGE_STRING "\n\n"); - printf("Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.\n" - "Copyright 2010-2014 Tormod Volden and Stefan Schmidt\n" - "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" - "Please report bugs to " PACKAGE_BUGREPORT "\n\n"); -} - -static struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'V' }, - { "verbose", 0, 0, 'v' }, - { "list", 0, 0, 'l' }, - { "detach", 0, 0, 'e' }, - { "detach-delay", 1, 0, 'E' }, - { "device", 1, 0, 'd' }, - { "path", 1, 0, 'p' }, - { "configuration", 1, 0, 'c' }, - { "cfg", 1, 0, 'c' }, - { "interface", 1, 0, 'i' }, - { "intf", 1, 0, 'i' }, - { "altsetting", 1, 0, 'a' }, - { "alt", 1, 0, 'a' }, - { "serial", 1, 0, 'S' }, - { "transfer-size", 1, 0, 't' }, - { "upload", 1, 0, 'U' }, - { "upload-size", 1, 0, 'Z' }, - { "download", 1, 0, 'D' }, - { "reset", 0, 0, 'R' }, - { "dfuse-address", 1, 0, 's' }, - { 0, 0, 0, 0 } -}; - -int main(int argc, char **argv) -{ - int expected_size = 0; - unsigned int transfer_size = 0; - enum mode mode = MODE_NONE; - struct dfu_status status; - libusb_context *ctx; - struct dfu_file file; - char *end; - int final_reset = 0; - int ret; - int dfuse_device = 0; - int fd; - const char *dfuse_options = NULL; - int detach_delay = 5; - uint16_t runtime_vendor; - uint16_t runtime_product; - - memset(&file, 0, sizeof(file)); - - /* make sure all prints are flushed */ - setvbuf(stdout, NULL, _IONBF, 0); - - while (1) { - int c, option_index = 0; - c = getopt_long(argc, argv, "hVvleE:d:p:c:i:a:S:t:U:D:Rs:Z:", opts, - &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - help(); - break; - case 'V': - mode = MODE_VERSION; - break; - case 'v': - verbose++; - break; - case 'l': - mode = MODE_LIST; - break; - case 'e': - mode = MODE_DETACH; - match_iface_alt_index = 0; - match_iface_index = 0; - break; - case 'E': - detach_delay = atoi(optarg); - break; - case 'd': - parse_vendprod(optarg); - break; - case 'p': - /* Parse device path */ - ret = resolve_device_path(optarg); - if (ret < 0) - errx(EX_SOFTWARE, "Unable to parse '%s'", optarg); - if (!ret) - errx(EX_SOFTWARE, "Cannot find '%s'", optarg); - break; - case 'c': - /* Configuration */ - match_config_index = atoi(optarg); - break; - case 'i': - /* Interface */ - match_iface_index = atoi(optarg); - break; - case 'a': - /* Interface Alternate Setting */ - match_iface_alt_index = strtoul(optarg, &end, 0); - if (*end) { - match_iface_alt_name = optarg; - match_iface_alt_index = -1; - } - break; - case 'S': - parse_serial(optarg); - break; - case 't': - transfer_size = atoi(optarg); - break; - case 'U': - mode = MODE_UPLOAD; - file.name = optarg; - break; - case 'Z': - expected_size = atoi(optarg); - break; - case 'D': - mode = MODE_DOWNLOAD; - file.name = optarg; - break; - case 'R': - final_reset = 1; - break; - case 's': - dfuse_options = optarg; - break; - default: - help(); - break; - } - } - - print_version(); - if (mode == MODE_VERSION) { - exit(0); - } - - if (mode == MODE_NONE) { - fprintf(stderr, "You need to specify one of -D or -U\n"); - help(); - } - - if (match_config_index == 0) { - /* Handle "-c 0" (unconfigured device) as don't care */ - match_config_index = -1; - } - - if (mode == MODE_DOWNLOAD) { - dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); - /* If the user didn't specify product and/or vendor IDs to match, - * use any IDs from the file suffix for device matching */ - if (match_vendor < 0 && file.idVendor != 0xffff) { - match_vendor = file.idVendor; - printf("Match vendor ID from file: %04x\n", match_vendor); - } - if (match_product < 0 && file.idProduct != 0xffff) { - match_product = file.idProduct; - printf("Match product ID from file: %04x\n", match_product); - } - } - - ret = libusb_init(&ctx); - if (ret) - errx(EX_IOERR, "unable to initialize libusb: %i", ret); - - if (verbose > 2) { - libusb_set_debug(ctx, 255); - } - - probe_devices(ctx); - - if (mode == MODE_LIST) { - list_dfu_interfaces(); - exit(0); - } - - if (dfu_root == NULL) { - errx(EX_IOERR, "No DFU capable USB device available"); - } else if (dfu_root->next != NULL) { - /* We cannot safely support more than one DFU capable device - * with same vendor/product ID, since during DFU we need to do - * a USB bus reset, after which the target device will get a - * new address */ - errx(EX_IOERR, "More than one DFU capable USB device found! " - "Try `--list' and specify the serial number " - "or disconnect all but one device\n"); - } - - /* We have exactly one device. Its libusb_device is now in dfu_root->dev */ - - printf("Opening DFU capable USB device...\n"); - ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); - if (ret || !dfu_root->dev_handle) - errx(EX_IOERR, "Cannot open device"); - - printf("ID %04x:%04x\n", dfu_root->vendor, dfu_root->product); - - printf("Run-time device DFU version %04x\n", - libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); - - /* Transition from run-Time mode to DFU mode */ - if (!(dfu_root->flags & DFU_IFF_DFU)) { - int err; - /* In the 'first round' during runtime mode, there can only be one - * DFU Interface descriptor according to the DFU Spec. */ - - /* FIXME: check if the selected device really has only one */ - - runtime_vendor = dfu_root->vendor; - runtime_product = dfu_root->product; - - printf("Claiming USB DFU Runtime Interface...\n"); - if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "Cannot claim interface %d", - dfu_root->interface); - } - - if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, 0) < 0) { - errx(EX_IOERR, "Cannot set alt interface zero"); - } - - printf("Determining device status: "); - - err = dfu_get_status(dfu_root, &status); - if (err == LIBUSB_ERROR_PIPE) { - printf("Device does not implement get_status, assuming appIDLE\n"); - status.bStatus = DFU_STATUS_OK; - status.bwPollTimeout = 0; - status.bState = DFU_STATE_appIDLE; - status.iString = 0; - } else if (err < 0) { - errx(EX_IOERR, "error get_status"); - } else { - printf("state = %s, status = %d\n", - dfu_state_to_string(status.bState), status.bStatus); - } - milli_sleep(status.bwPollTimeout); - - switch (status.bState) { - case DFU_STATE_appIDLE: - case DFU_STATE_appDETACH: - printf("Device really in Runtime Mode, send DFU " - "detach request...\n"); - if (dfu_detach(dfu_root->dev_handle, - dfu_root->interface, 1000) < 0) { - warnx("error detaching"); - } - if (dfu_root->func_dfu.bmAttributes & USB_DFU_WILL_DETACH) { - printf("Device will detach and reattach...\n"); - } else { - printf("Resetting USB...\n"); - ret = libusb_reset_device(dfu_root->dev_handle); - if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) - errx(EX_IOERR, "error resetting " - "after detach"); - } - break; - case DFU_STATE_dfuERROR: - printf("dfuERROR, clearing status\n"); - if (dfu_clear_status(dfu_root->dev_handle, - dfu_root->interface) < 0) { - errx(EX_IOERR, "error clear_status"); - } - /* fall through */ - default: - warnx("WARNING: Runtime device already in DFU state ?!?"); - libusb_release_interface(dfu_root->dev_handle, - dfu_root->interface); - goto dfustate; - } - libusb_release_interface(dfu_root->dev_handle, - dfu_root->interface); - libusb_close(dfu_root->dev_handle); - dfu_root->dev_handle = NULL; - - if (mode == MODE_DETACH) { - libusb_exit(ctx); - exit(0); - } - - /* keeping handles open might prevent re-enumeration */ - disconnect_devices(); - - milli_sleep(detach_delay * 1000); - - /* Change match vendor and product to impossible values to force - * only DFU mode matches in the following probe */ - match_vendor = match_product = 0x10000; - - probe_devices(ctx); - - if (dfu_root == NULL) { - errx(EX_IOERR, "Lost device after RESET?"); - } else if (dfu_root->next != NULL) { - errx(EX_IOERR, "More than one DFU capable USB device found! " - "Try `--list' and specify the serial number " - "or disconnect all but one device"); - } - - /* Check for DFU mode device */ - if (!(dfu_root->flags | DFU_IFF_DFU)) - errx(EX_SOFTWARE, "Device is not in DFU mode"); - - printf("Opening DFU USB Device...\n"); - ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); - if (ret || !dfu_root->dev_handle) { - errx(EX_IOERR, "Cannot open device"); - } - } else { - /* we're already in DFU mode, so we can skip the detach/reset - * procedure */ - /* If a match vendor/product was specified, use that as the runtime - * vendor/product, otherwise use the DFU mode vendor/product */ - runtime_vendor = match_vendor < 0 ? dfu_root->vendor : match_vendor; - runtime_product = match_product < 0 ? dfu_root->product : match_product; - } - -dfustate: -#if 0 - printf("Setting Configuration %u...\n", dfu_root->configuration); - if (libusb_set_configuration(dfu_root->dev_handle, dfu_root->configuration) < 0) { - errx(EX_IOERR, "Cannot set configuration"); - } -#endif - printf("Claiming USB DFU Interface...\n"); - if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "Cannot claim interface"); - } - - printf("Setting Alternate Setting #%d ...\n", dfu_root->altsetting); - if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, dfu_root->altsetting) < 0) { - errx(EX_IOERR, "Cannot set alternate interface"); - } - -status_again: - printf("Determining device status: "); - if (dfu_get_status(dfu_root, &status ) < 0) { - errx(EX_IOERR, "error get_status"); - } - printf("state = %s, status = %d\n", - dfu_state_to_string(status.bState), status.bStatus); - - milli_sleep(status.bwPollTimeout); - - switch (status.bState) { - case DFU_STATE_appIDLE: - case DFU_STATE_appDETACH: - errx(EX_IOERR, "Device still in Runtime Mode!"); - break; - case DFU_STATE_dfuERROR: - printf("dfuERROR, clearing status\n"); - if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "error clear_status"); - } - goto status_again; - break; - case DFU_STATE_dfuDNLOAD_IDLE: - case DFU_STATE_dfuUPLOAD_IDLE: - printf("aborting previous incomplete transfer\n"); - if (dfu_abort(dfu_root->dev_handle, dfu_root->interface) < 0) { - errx(EX_IOERR, "can't send DFU_ABORT"); - } - goto status_again; - break; - case DFU_STATE_dfuIDLE: - printf("dfuIDLE, continuing\n"); - break; - default: - break; - } - - if (DFU_STATUS_OK != status.bStatus ) { - printf("WARNING: DFU Status: '%s'\n", - dfu_status_to_string(status.bStatus)); - /* Clear our status & try again. */ - if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) - errx(EX_IOERR, "USB communication error"); - if (dfu_get_status(dfu_root, &status) < 0) - errx(EX_IOERR, "USB communication error"); - if (DFU_STATUS_OK != status.bStatus) - errx(EX_SOFTWARE, "Status is not OK: %d", status.bStatus); - - milli_sleep(status.bwPollTimeout); - } - - printf("DFU mode device DFU version %04x\n", - libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); - - if (dfu_root->func_dfu.bcdDFUVersion == libusb_cpu_to_le16(0x11a)) - dfuse_device = 1; - - /* If not overridden by the user */ - if (!transfer_size) { - transfer_size = libusb_le16_to_cpu( - dfu_root->func_dfu.wTransferSize); - if (transfer_size) { - printf("Device returned transfer size %i\n", - transfer_size); - } else { - errx(EX_IOERR, "Transfer size must be specified"); - } - } - -#ifdef HAVE_GETPAGESIZE -/* autotools lie when cross-compiling for Windows using mingw32/64 */ -#ifndef __MINGW32__ - /* limitation of Linux usbdevio */ - if ((int)transfer_size > getpagesize()) { - transfer_size = getpagesize(); - printf("Limited transfer size to %i\n", transfer_size); - } -#endif /* __MINGW32__ */ -#endif /* HAVE_GETPAGESIZE */ - - if (transfer_size < dfu_root->bMaxPacketSize0) { - transfer_size = dfu_root->bMaxPacketSize0; - printf("Adjusted transfer size to %i\n", transfer_size); - } - - switch (mode) { - case MODE_UPLOAD: - /* open for "exclusive" writing */ - fd = open(file.name, O_WRONLY | O_BINARY | O_CREAT | O_EXCL | O_TRUNC, 0666); - if (fd < 0) - err(EX_IOERR, "Cannot open file %s for writing", file.name); - - if (dfuse_device || dfuse_options) { - if (dfuse_do_upload(dfu_root, transfer_size, fd, - dfuse_options) < 0) - exit(1); - } else { - if (dfuload_do_upload(dfu_root, transfer_size, - expected_size, fd) < 0) { - exit(1); - } - } - close(fd); - break; - - case MODE_DOWNLOAD: - if (((file.idVendor != 0xffff && file.idVendor != runtime_vendor) || - (file.idProduct != 0xffff && file.idProduct != runtime_product)) && - ((file.idVendor != 0xffff && file.idVendor != dfu_root->vendor) || - (file.idProduct != 0xffff && file.idProduct != dfu_root->product))) { - errx(EX_IOERR, "Error: File ID %04x:%04x does " - "not match device (%04x:%04x or %04x:%04x)", - file.idVendor, file.idProduct, - runtime_vendor, runtime_product, - dfu_root->vendor, dfu_root->product); - } - if (dfuse_device || dfuse_options || file.bcdDFU == 0x11a) { - if (dfuse_do_dnload(dfu_root, transfer_size, &file, - dfuse_options) < 0) - exit(1); - } else { - if (dfuload_do_dnload(dfu_root, transfer_size, &file) < 0) - exit(1); - } - break; - case MODE_DETACH: - if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { - warnx("can't detach"); - } - break; - default: - errx(EX_IOERR, "Unsupported mode: %u", mode); - break; - } - - if (final_reset) { - if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { - /* Even if detach failed, just carry on to leave the - device in a known state */ - warnx("can't detach"); - } - printf("Resetting USB to switch back to runtime mode\n"); - ret = libusb_reset_device(dfu_root->dev_handle); - if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) { - errx(EX_IOERR, "error resetting after download"); - } - } - - libusb_close(dfu_root->dev_handle); - dfu_root->dev_handle = NULL; - libusb_exit(ctx); - - return (0); -} diff --git a/macosx/src/dfu-util/src/portable.h b/macosx/src/dfu-util/src/portable.h deleted file mode 100644 index cf8d5df38..000000000 --- a/macosx/src/dfu-util/src/portable.h +++ /dev/null @@ -1,72 +0,0 @@ - -#ifndef PORTABLE_H -#define PORTABLE_H - -#ifdef HAVE_CONFIG_H -# include "config.h" -#else -# define PACKAGE "dfu-util" -# define PACKAGE_VERSION "0.8-msvc" -# define PACKAGE_STRING "dfu-util 0.8-msvc" -# define PACKAGE_BUGREPORT "dfu-util@lists.gnumonks.org" -#endif /* HAVE_CONFIG_H */ - -#ifdef HAVE_FTRUNCATE -# include -#else -# include -#endif /* HAVE_FTRUNCATE */ - -#ifdef HAVE_NANOSLEEP -# include -# define milli_sleep(msec) do {\ - if (msec) {\ - struct timespec nanosleepDelay = { (msec) / 1000, ((msec) % 1000) * 1000000 };\ - nanosleep(&nanosleepDelay, NULL);\ - } } while (0) -#elif defined HAVE_WINDOWS_H -# define milli_sleep(msec) do {\ - if (msec) {\ - Sleep(msec);\ - } } while (0) -#else -# error "Can't get no sleep! Please report" -#endif /* HAVE_NANOSLEEP */ - -#ifdef HAVE_ERR -# include -#else -# include -# include -# define warnx(...) do {\ - fprintf(stderr, __VA_ARGS__);\ - fprintf(stderr, "\n"); } while (0) -# define errx(eval, ...) do {\ - warnx(__VA_ARGS__);\ - exit(eval); } while (0) -# define warn(...) do {\ - fprintf(stderr, "%s: ", strerror(errno));\ - warnx(__VA_ARGS__); } while (0) -# define err(eval, ...) do {\ - warn(__VA_ARGS__);\ - exit(eval); } while (0) -#endif /* HAVE_ERR */ - -#ifdef HAVE_SYSEXITS_H -# include -#else -# define EX_OK 0 /* successful termination */ -# define EX_USAGE 64 /* command line usage error */ -# define EX_SOFTWARE 70 /* internal software error */ -# define EX_IOERR 74 /* input/output error */ -#endif /* HAVE_SYSEXITS_H */ - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -#ifndef off_t -# define off_t long int -#endif - -#endif /* PORTABLE_H */ diff --git a/macosx/src/dfu-util/src/prefix.c b/macosx/src/dfu-util/src/prefix.c deleted file mode 100644 index be8e3faf3..000000000 --- a/macosx/src/dfu-util/src/prefix.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * dfu-prefix - * - * Copyright 2011-2012 Stefan Schmidt - * Copyright 2013 Hans Petter Selasky - * Copyright 2014 Uwe Bonnes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" - -enum mode { - MODE_NONE, - MODE_ADD, - MODE_DEL, - MODE_CHECK -}; - -int verbose; - -static void help(void) -{ - fprintf(stderr, "Usage: dfu-prefix [options] ...\n" - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -c --check \t\tCheck DFU prefix of \n" - " -D --delete \t\tDelete DFU prefix from \n" - " -a --add \t\tAdd DFU prefix to \n" - "In combination with -a:\n" - ); - fprintf(stderr, " -s --stellaris-address
Add TI Stellaris address prefix to \n" - "In combination with -D or -c:\n" - " -T --stellaris\t\tAct on TI Stellaris address prefix of \n" - "In combination with -a or -D or -c:\n" - " -L --lpc-prefix\t\tUse NXP LPC DFU prefix format\n" - ); - exit(EX_USAGE); -} - -static void print_version(void) -{ - printf("dfu-prefix (%s) %s\n\n", PACKAGE, PACKAGE_VERSION); - printf("Copyright 2011-2012 Stefan Schmidt, 2014 Uwe Bonnes\n" - "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" - "Please report bugs to %s\n\n", PACKAGE_BUGREPORT); - -} - -static struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'V' }, - { "check", 1, 0, 'c' }, - { "add", 1, 0, 'a' }, - { "delete", 1, 0, 'D' }, - { "stellaris-address", 1, 0, 's' }, - { "stellaris", 0, 0, 'T' }, - { "LPC", 0, 0, 'L' }, -}; -int main(int argc, char **argv) -{ - struct dfu_file file; - enum mode mode = MODE_NONE; - enum prefix_type type = ZERO_PREFIX; - uint32_t lmdfu_flash_address = 0; - char *end; - - /* make sure all prints are flushed */ - setvbuf(stdout, NULL, _IONBF, 0); - - print_version(); - - memset(&file, 0, sizeof(file)); - - while (1) { - int c, option_index = 0; - c = getopt_long(argc, argv, "hVc:a:D:p:v:d:s:TL", opts, - &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - help(); - break; - case 'V': - exit(0); - break; - case 'D': - file.name = optarg; - mode = MODE_DEL; - break; - case 'c': - file.name = optarg; - mode = MODE_CHECK; - break; - case 'a': - file.name = optarg; - mode = MODE_ADD; - break; - case 's': - lmdfu_flash_address = strtoul(optarg, &end, 0); - if (*end) { - errx(EX_IOERR, "Invalid lmdfu " - "address: %s", optarg); - } - /* fall-through */ - case 'T': - type = LMDFU_PREFIX; - break; - case 'L': - type = LPCDFU_UNENCRYPTED_PREFIX; - break; - default: - help(); - break; - } - } - - if (!file.name) { - fprintf(stderr, "You need to specify a filename\n"); - help(); - } - - switch(mode) { - case MODE_ADD: - if (type == ZERO_PREFIX) - errx(EX_IOERR, "Prefix type must be specified"); - dfu_load_file(&file, MAYBE_SUFFIX, NO_PREFIX); - file.lmdfu_address = lmdfu_flash_address; - file.prefix_type = type; - printf("Adding prefix to file\n"); - dfu_store_file(&file, file.size.suffix != 0, 1); - break; - - case MODE_CHECK: - dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); - show_suffix_and_prefix(&file); - if (type > ZERO_PREFIX && file.prefix_type != type) - errx(EX_IOERR, "No prefix of requested type"); - break; - - case MODE_DEL: - dfu_load_file(&file, MAYBE_SUFFIX, NEEDS_PREFIX); - if (type > ZERO_PREFIX && file.prefix_type != type) - errx(EX_IOERR, "No prefix of requested type"); - printf("Removing prefix from file\n"); - /* if there was a suffix, rewrite it */ - dfu_store_file(&file, file.size.suffix != 0, 0); - break; - - default: - help(); - break; - } - return (0); -} diff --git a/macosx/src/dfu-util/src/quirks.c b/macosx/src/dfu-util/src/quirks.c deleted file mode 100644 index de394a615..000000000 --- a/macosx/src/dfu-util/src/quirks.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Simple quirk system for dfu-util - * - * Copyright 2010-2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include "quirks.h" - -uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice) -{ - uint16_t quirks = 0; - - /* Device returns bogus bwPollTimeout values */ - if ((vendor == VENDOR_OPENMOKO || vendor == VENDOR_FIC) && - product >= PRODUCT_FREERUNNER_FIRST && - product <= PRODUCT_FREERUNNER_LAST) - quirks |= QUIRK_POLLTIMEOUT; - - if (vendor == VENDOR_VOTI && - product == PRODUCT_OPENPCD) - quirks |= QUIRK_POLLTIMEOUT; - - /* Reports wrong DFU version in DFU descriptor */ - if (vendor == VENDOR_LEAFLABS && - product == PRODUCT_MAPLE3 && - bcdDevice == 0x0200) - quirks |= QUIRK_FORCE_DFU11; - - /* old devices(bcdDevice == 0) return bogus bwPollTimeout values */ - if (vendor == VENDOR_SIEMENS && - (product == PRODUCT_PXM40 || product == PRODUCT_PXM50) && - bcdDevice == 0) - quirks |= QUIRK_POLLTIMEOUT; - - /* M-Audio Transit returns bogus bwPollTimeout values */ - if (vendor == VENDOR_MIDIMAN && - product == PRODUCT_TRANSIT) - quirks |= QUIRK_POLLTIMEOUT; - - return (quirks); -} diff --git a/macosx/src/dfu-util/src/quirks.h b/macosx/src/dfu-util/src/quirks.h deleted file mode 100644 index 0e4b3ec58..000000000 --- a/macosx/src/dfu-util/src/quirks.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef DFU_QUIRKS_H -#define DFU_QUIRKS_H - -#define VENDOR_OPENMOKO 0x1d50 /* Openmoko Freerunner / GTA02 */ -#define VENDOR_FIC 0x1457 /* Openmoko Freerunner / GTA02 */ -#define VENDOR_VOTI 0x16c0 /* OpenPCD Reader */ -#define VENDOR_LEAFLABS 0x1eaf /* Maple */ -#define VENDOR_SIEMENS 0x0908 /* Siemens AG */ -#define VENDOR_MIDIMAN 0x0763 /* Midiman */ - -#define PRODUCT_FREERUNNER_FIRST 0x5117 -#define PRODUCT_FREERUNNER_LAST 0x5126 -#define PRODUCT_OPENPCD 0x076b -#define PRODUCT_MAPLE3 0x0003 /* rev 3 and 5 */ -#define PRODUCT_PXM40 0x02c4 /* Siemens AG, PXM 40 */ -#define PRODUCT_PXM50 0x02c5 /* Siemens AG, PXM 50 */ -#define PRODUCT_TRANSIT 0x2806 /* M-Audio Transit (Midiman) */ - -#define QUIRK_POLLTIMEOUT (1<<0) -#define QUIRK_FORCE_DFU11 (1<<1) - -/* Fallback value, works for OpenMoko */ -#define DEFAULT_POLLTIMEOUT 5 - -uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice); - -#endif /* DFU_QUIRKS_H */ diff --git a/macosx/src/dfu-util/src/suffix.c b/macosx/src/dfu-util/src/suffix.c deleted file mode 100644 index 0df248f51..000000000 --- a/macosx/src/dfu-util/src/suffix.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * dfu-suffix - * - * Copyright 2011-2012 Stefan Schmidt - * Copyright 2013 Hans Petter Selasky - * Copyright 2014 Tormod Volden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "portable.h" -#include "dfu_file.h" - -enum mode { - MODE_NONE, - MODE_ADD, - MODE_DEL, - MODE_CHECK -}; - -int verbose; - -static void help(void) -{ - fprintf(stderr, "Usage: dfu-suffix [options] ...\n" - " -h --help\t\t\tPrint this help message\n" - " -V --version\t\t\tPrint the version number\n" - " -c --check \t\tCheck DFU suffix of \n" - " -a --add \t\tAdd DFU suffix to \n" - " -D --delete \t\tDelete DFU suffix from \n" - " -p --pid \t\tAdd product ID into DFU suffix in \n" - " -v --vid \t\tAdd vendor ID into DFU suffix in \n" - " -d --did \t\tAdd device ID into DFU suffix in \n" - " -S --spec \t\tAdd DFU specification ID into DFU suffix in \n" - ); - exit(EX_USAGE); -} - -static void print_version(void) -{ - printf("dfu-suffix (%s) %s\n\n", PACKAGE, PACKAGE_VERSION); - printf("Copyright 2011-2012 Stefan Schmidt, 2013-2014 Tormod Volden\n" - "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" - "Please report bugs to %s\n\n", PACKAGE_BUGREPORT); - -} - -static struct option opts[] = { - { "help", 0, 0, 'h' }, - { "version", 0, 0, 'V' }, - { "check", 1, 0, 'c' }, - { "add", 1, 0, 'a' }, - { "delete", 1, 0, 'D' }, - { "pid", 1, 0, 'p' }, - { "vid", 1, 0, 'v' }, - { "did", 1, 0, 'd' }, - { "spec", 1, 0, 'S' }, -}; - -int main(int argc, char **argv) -{ - struct dfu_file file; - int pid, vid, did, spec; - enum mode mode = MODE_NONE; - - /* make sure all prints are flushed */ - setvbuf(stdout, NULL, _IONBF, 0); - - print_version(); - - pid = vid = did = 0xffff; - spec = 0x0100; /* Default to bcdDFU version 1.0 */ - memset(&file, 0, sizeof(file)); - - while (1) { - int c, option_index = 0; - c = getopt_long(argc, argv, "hVc:a:D:p:v:d:S:s:T", opts, - &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - help(); - break; - case 'V': - exit(0); - break; - case 'D': - file.name = optarg; - mode = MODE_DEL; - break; - case 'p': - pid = strtol(optarg, NULL, 16); - break; - case 'v': - vid = strtol(optarg, NULL, 16); - break; - case 'd': - did = strtol(optarg, NULL, 16); - break; - case 'S': - spec = strtol(optarg, NULL, 16); - break; - case 'c': - file.name = optarg; - mode = MODE_CHECK; - break; - case 'a': - file.name = optarg; - mode = MODE_ADD; - break; - default: - help(); - break; - } - } - - if (!file.name) { - fprintf(stderr, "You need to specify a filename\n"); - help(); - } - - if (spec != 0x0100 && spec != 0x011a) { - fprintf(stderr, "Only DFU specification 0x0100 and 0x011a supported\n"); - help(); - } - - switch(mode) { - case MODE_ADD: - dfu_load_file(&file, NO_SUFFIX, MAYBE_PREFIX); - file.idVendor = vid; - file.idProduct = pid; - file.bcdDevice = did; - file.bcdDFU = spec; - /* always write suffix, rewrite prefix if there was one */ - dfu_store_file(&file, 1, file.size.prefix != 0); - printf("Suffix successfully added to file\n"); - break; - - case MODE_CHECK: - dfu_load_file(&file, NEEDS_SUFFIX, MAYBE_PREFIX); - show_suffix_and_prefix(&file); - break; - - case MODE_DEL: - dfu_load_file(&file, NEEDS_SUFFIX, MAYBE_PREFIX); - dfu_store_file(&file, 0, file.size.prefix != 0); - if (file.size.suffix) /* had a suffix */ - printf("Suffix successfully removed from file\n"); - break; - - default: - help(); - break; - } - return (0); -} diff --git a/macosx/src/dfu-util/src/usb_dfu.h b/macosx/src/dfu-util/src/usb_dfu.h deleted file mode 100644 index 660bedcbf..000000000 --- a/macosx/src/dfu-util/src/usb_dfu.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef USB_DFU_H -#define USB_DFU_H -/* USB Device Firmware Update Implementation for OpenPCD - * (C) 2006 by Harald Welte - * - * Protocol definitions for USB DFU - * - * This ought to be compliant to the USB DFU Spec 1.0 as available from - * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#define USB_DT_DFU 0x21 - -#ifdef _MSC_VER -# pragma pack(push) -# pragma pack(1) -#endif /* _MSC_VER */ -struct usb_dfu_func_descriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bmAttributes; -#define USB_DFU_CAN_DOWNLOAD (1 << 0) -#define USB_DFU_CAN_UPLOAD (1 << 1) -#define USB_DFU_MANIFEST_TOL (1 << 2) -#define USB_DFU_WILL_DETACH (1 << 3) - uint16_t wDetachTimeOut; - uint16_t wTransferSize; - uint16_t bcdDFUVersion; -#ifdef _MSC_VER -}; -# pragma pack(pop) -#elif defined __GNUC__ -} __attribute__ ((packed)); -#else - #warning "No way to pack struct on this compiler? This will break!" -#endif /* _MSC_VER */ - -#define USB_DT_DFU_SIZE 9 - -#define USB_TYPE_DFU (LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE) - -/* DFU class-specific requests (Section 3, DFU Rev 1.1) */ -#define USB_REQ_DFU_DETACH 0x00 -#define USB_REQ_DFU_DNLOAD 0x01 -#define USB_REQ_DFU_UPLOAD 0x02 -#define USB_REQ_DFU_GETSTATUS 0x03 -#define USB_REQ_DFU_CLRSTATUS 0x04 -#define USB_REQ_DFU_GETSTATE 0x05 -#define USB_REQ_DFU_ABORT 0x06 - -/* DFU_GETSTATUS bStatus values (Section 6.1.2, DFU Rev 1.1) */ -#define DFU_STATUS_OK 0x00 -#define DFU_STATUS_errTARGET 0x01 -#define DFU_STATUS_errFILE 0x02 -#define DFU_STATUS_errWRITE 0x03 -#define DFU_STATUS_errERASE 0x04 -#define DFU_STATUS_errCHECK_ERASED 0x05 -#define DFU_STATUS_errPROG 0x06 -#define DFU_STATUS_errVERIFY 0x07 -#define DFU_STATUS_errADDRESS 0x08 -#define DFU_STATUS_errNOTDONE 0x09 -#define DFU_STATUS_errFIRMWARE 0x0a -#define DFU_STATUS_errVENDOR 0x0b -#define DFU_STATUS_errUSBR 0x0c -#define DFU_STATUS_errPOR 0x0d -#define DFU_STATUS_errUNKNOWN 0x0e -#define DFU_STATUS_errSTALLEDPKT 0x0f - -enum dfu_state { - DFU_STATE_appIDLE = 0, - DFU_STATE_appDETACH = 1, - DFU_STATE_dfuIDLE = 2, - DFU_STATE_dfuDNLOAD_SYNC = 3, - DFU_STATE_dfuDNBUSY = 4, - DFU_STATE_dfuDNLOAD_IDLE = 5, - DFU_STATE_dfuMANIFEST_SYNC = 6, - DFU_STATE_dfuMANIFEST = 7, - DFU_STATE_dfuMANIFEST_WAIT_RST = 8, - DFU_STATE_dfuUPLOAD_IDLE = 9, - DFU_STATE_dfuERROR = 10 -}; - -#endif /* USB_DFU_H */ diff --git a/macosx/src/dfu-util/www/build.html b/macosx/src/dfu-util/www/build.html deleted file mode 100644 index f3036e40c..000000000 --- a/macosx/src/dfu-util/www/build.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - Building dfu-util from source - - - - - - - - - -
-

How to build dfu-util from source

- -

Prerequisites for building from git

-

Mac OS X

-

-First install MacPorts (and if you are on 10.6 or older, the Java Developer Package) and then run: -

-
-	sudo port install libusb-devel git-core
-
- -

FreeBSD

-
-	sudo pkg_add -r git pkgconf
-
- -

Ubuntu and Debian and derivatives

-
-	sudo apt-get build-dep dfu-util
-	sudo apt-get install libusb-1.0-0-dev
-
- -

Get the source code and build it

-

-The first time you will have to clone the git repository: -

-
-	git clone git://gitorious.org/dfu-util/dfu-util.git
-	cd dfu-util
-
-

-If you later want to update to latest git version, just run this: -

-
-	make maintainer-clean
-	git pull
-
-

-To build the source: -

-
-	./autogen.sh
-	./configure  # on most systems
-	make
-
- -

-If you are building on Mac OS X, replace the ./configure command with: -

-
-	./configure --libdir=/opt/local/lib --includedir=/opt/local/include  # on MacOSX only
-
- -

-Your dfu-util binary will be inside the src folder. Use it from there, or install it to /usr/local/bin by running "sudo make install". -

- -

Cross-building for Windows

- -

-Windows binaries can be built in a MinGW -environment, on a Windows computer or cross-hosted in another OS. -To build it on a Debian or Ubuntu host, first install build dependencies: -

-
-	sudo apt-get build-dep libusb-1.0-0 dfu-util
-	sudo apt-get install mingw32
-
- -

-The below example builds dfu-util 0.8 and libusb 1.0.19 from unpacked release -tarballs. If you instead build from git, you will have to run "./autogen.sh" -before running the "./configure" steps. -

- -
-mkdir -p build
-cd libusb-1.0.19
-PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure \
-    --host=i586-mingw32msvc --prefix=$PWD/../build
-# WINVER workaround needed for 1.0.19 only
-make CFLAGS="-DWINVER=0x0501"
-make install
-cd ..
-
-cd dfu-util-0.8
-PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure \
-    --host=i586-mingw32msvc --prefix=$PWD/../build
-make
-make install
-cd ..
-
-The build files will now be in build/bin. -

- -

Building on Windows using MinGW

-This assumes using release tarballs or having run ./autogen.sh on -the git sources. -
-cd libusb-1.0.19
-./configure --prefix=$HOME
-# WINVER workaround needed for 1.0.19 only
-# MKDIR_P setting should not really be needed...
-make CFLAGS="-DWINVER=0x0501" MKDIR_P="mkdir -p"
-make install
-cd ..
-
-cd dfu-util-0.8
-./configure USB_CFLAGS="-I$HOME/include/libusb-1.0" \
-            USB_LIBS="-L $HOME/lib -lusb-1.0" PKG_CONFIG=true
-make
-make install
-cd ..
-
-To link libusb statically into dfu-util.exe use instead of "make": -
-make LDFLAGS=-static
-
-The built executables (and DLL) will now be under $HOME/bin. - -

-[Back to dfu-util main page] -

- -
- - diff --git a/macosx/src/dfu-util/www/dfu-util.1.html b/macosx/src/dfu-util/www/dfu-util.1.html deleted file mode 100644 index 62ca40b5d..000000000 --- a/macosx/src/dfu-util/www/dfu-util.1.html +++ /dev/null @@ -1,411 +0,0 @@ - - -Man page of DFU-UTIL - - -

DFU-UTIL(1)

- -  -

NAME

- -dfu-util - Device firmware update (DFU) USB programmer -  -

SYNOPSIS

- - -
-
-dfu-util - --l - -[-v] - -[-d - -vid:pid[,vid:pid]] - -[-p - -path] - -[-c - -configuration] - -[-i - -interface] - -[-a - -alt-intf] - -[-S - -serial[,serial]] - - -
-dfu-util - -[-v] - -[-d - -vid:pid[,vid:pid]] - -[-p - -path] - -[-c - -configuration] - -[-i - -interface] - -[-a - -alt-intf] - -[-S - -serial[,serial]] - -[-t - -size] - -[-Z - -size] - -[-s - -address] - -[-R] - -[-D|-U - -file] - - -
-dfu-util - -[-hV] - -
-  -

DESCRIPTION

- -dfu-util - -is a program that implements the host (computer) side of the USB DFU -(Universal Serial Bus Device Firmware Upgrade) protocol. -

-dfu-util communicates with devices that implement the device side of the -USB DFU protocol, and is often used to upgrade the firmware of such -devices. -  -

OPTIONS

- -
-
-l, --list - -
-List the currently attached DFU capable USB devices. -
-d, --device [Run-Time VENDOR]:[Run-Time PRODUCT][,[DFU Mode VENDOR]:[DFU Mode PRODUCT]] - -
-
-Specify run-time and/or DFU mode vendor and/or product IDs of the DFU device -to work with. VENDOR and PRODUCT are hexadecimal numbers (no prefix -needed), "*" (match any), or "-" (match nothing). By default, any DFU capable -device in either run-time or DFU mode will be considered. -

-If you only have one standards-compliant DFU device attached to your computer, -this parameter is optional. However, as soon as you have multiple DFU devices -connected, dfu-util will detect this and abort, asking you to specify which -device to use. -

-If only run-time IDs are specified (e.g. "--device 1457:51ab"), then in -addition to the specified run-time IDs, any DFU mode devices will also be -considered. This is beneficial to allow a DFU capable device to be found -again after a switch to DFU mode, since the vendor and/or product ID of a -device usually changes in DFU mode. -

-If only DFU mode IDs are specified (e.g. "--device ,951:26"), then all -run-time devices will be ignored, making it easy to target a specific device in -DFU mode. -

-If both run-time and DFU mode IDs are specified (e.g. "--device -1457:51ab,:2bc"), then unspecified DFU mode components will use the run-time -value specified. -

-Examples: -

-
--device 1457:51ab,951:26 - -
-
- -Work with a device in run-time mode with -vendor ID 0x1457 and product ID 0x51ab, or in DFU mode with vendor ID 0x0951 -and product ID 0x0026 -

-

--device 1457:51ab,:2bc - -
-
- -Work with a device in run-time mode with vendor ID 0x1457 and product ID -0x51ab, or in DFU mode with vendor ID 0x1457 and product ID 0x02bc -

-

--device 1457:51ab - -
-
- -Work with a device in run-time mode with vendor ID 0x1457 and product ID -0x51ab, or in DFU mode with any vendor and product ID -

-

--device ,951:26 - -
-
- -Work with a device in DFU mode with vendor ID 0x0951 and product ID 0x0026 -

-

--device *,- - -
-
- -Work with any device in run-time mode, and ignore any device in DFU mode -

-

--device , - -
-
- -Ignore any device in run-time mode, and Work with any device in DFU mode -
-
- -
-p, --path BUS-PORT. ... .PORT - -
-Specify the path to the DFU device. -
-c, --cfg CONFIG-NR - -
-Specify the configuration of the DFU device. Note that this is only used for matching, the configuration is not set by dfu-util. -
-i, --intf INTF-NR - -
-Specify the DFU interface number. -
-a, --alt ALT - -
-Specify the altsetting of the DFU interface by name or by number. -
-S, --serial [Run-Time SERIAL][,[DFU Mode SERIAL]] - -
-Specify the run-time and DFU mode serial numbers used to further restrict -device matches. If multiple, identical DFU devices are simultaneously -connected to a system then vendor and product ID will be insufficient for -targeting a single device. In this situation, it may be possible to use this -parameter to specify a serial number which also must match. -

-If only a single serial number is specified, then the same serial number is -used in both run-time and DFU mode. An empty serial number will match any -serial number in the corresponding mode. -

-t, --transfer-size SIZE - -
-Specify the number of bytes per USB transfer. The optimal value is -usually determined automatically so this option is rarely useful. If -you need to use this option for a device, please report it as a bug. -
-Z, --upload-size SIZE - -
-Specify the expected upload size, in bytes. -
-U, --upload FILE - -
-Read firmware from device into -FILE. - -
-D, --download FILE - -
-Write firmware from -FILE - -into device. -
-R, --reset - -
-Issue USB reset signalling after upload or download has finished. -
-s, --dfuse-address address - -
-Specify target address for raw binary download/upload on DfuSe devices. Do -not - -use this for downloading DfuSe (.dfu) files. Modifiers can be added -to the address, separated by a colon, to perform special DfuSE commands such -as "leave" DFU mode, "unprotect" and "mass-erase" flash memory. -
-v, --verbose - -
-Print more information about dfu-util's operation. A second --v - -will turn on verbose logging of USB requests. Repeat this option to further -increase verbosity. -
-h, --help - -
-Show a help text and exit. -
-V, --version - -
-Show version information and exit. -
-  -

EXAMPLES

- -  -

Using dfu-util in the OpenMoko project

- -(with the Neo1973 hardware) -

- -Flashing the rootfs: -
- - $ dfu-util -a rootfs -R -D /path/to/openmoko-devel-image.jffs2 - -

- -Flashing the kernel: -
- - $ dfu-util -a kernel -R -D /path/to/uImage - -

- -Flashing the bootloader: -
- - $ dfu-util -a u-boot -R -D /path/to/u-boot.bin - -

- -Copying a kernel into RAM: -
- - $ dfu-util -a 0 -R -D /path/to/uImage - -

-Once this has finished, the kernel will be available at the default load -address of 0x32000000 in Neo1973 RAM. -Note: - -You cannot transfer more than 2MB of data into RAM using this method. -

-  -

Using dfu-util with a DfuSe device

- -

- -Flashing a -.dfu - -(special DfuSe format) file to the device: -
- - $ dfu-util -a 0 -D /path/to/dfuse-image.dfu - -

- -Reading out 1 KB of flash starting at address 0x8000000: -
- - $ dfu-util -a 0 -s 0x08000000:1024 -U newfile.bin - -

- -Flashing a binary file to address 0x8004000 of device memory and -ask the device to leave DFU mode: -
- - $ dfu-util -a 0 -s 0x08004000:leave -D /path/to/image.bin - - -  -

BUGS

- -Please report any bugs to the dfu-util mailing list at -dfu-util@lists.gnumonks.org. - -Please use the ---verbose option (repeated as necessary) to provide more - -information in your bug report. -  -

SEE ALSO

- -The dfu-util home page is -http://dfu-util.gnumonks.org - -  -

HISTORY

- -dfu-util was originally written for the OpenMoko project by -Weston Schmidt <weston_schmidt@yahoo.com> and -Harald Welte <hwelte@hmw-consulting.de>. Over time, nearly complete -support of DFU 1.0, DFU 1.1 and DfuSe ("1.1a") has been added. -  -

LICENCE

- -dfu-util - -is covered by the GNU General Public License (GPL), version 2 or later. -  -

COPYRIGHT

- -This manual page was originally written by Uwe Hermann <uwe@hermann-uwe.de>, -and is now part of the dfu-util project. -

- -


- 

Index

-
-
NAME
-
SYNOPSIS
-
DESCRIPTION
-
OPTIONS
-
EXAMPLES
-
-
Using dfu-util in the OpenMoko project
-
Using dfu-util with a DfuSe device
-
-
BUGS
-
SEE ALSO
-
HISTORY
-
LICENCE
-
COPYRIGHT
-
-
-This document was created by man2html, -using the doc/dfu-util.1 manual page from dfu-util 0.8.
-Time: 14:40:57 GMT, September 13, 2014 - - diff --git a/macosx/src/dfu-util/www/dfuse.html b/macosx/src/dfu-util/www/dfuse.html deleted file mode 100644 index 35e4ffa9f..000000000 --- a/macosx/src/dfu-util/www/dfuse.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - DfuSe and dfu-util - - - - - - - - - -
-

Using dfu-util with DfuSe devices

-

DfuSe

-

- DfuSe (DFU with ST Microsystems extensions) is a protocol based on - DFU 1.1. However, in expanding the functionality of the DFU protocol, - ST Microsystems broke all compatibility with the DFU 1.1 standard. - DfuSe devices report the DFU version as "1.1a". -

-

- DfuSe can be used to download firmware and other data - from a host computer to a conforming device (or upload in the - opposite direction) over USB similar to standard DFU. -

-

- The main difference from standard DFU is that the target address in - the device (flash) memory is specified by the host, so that a - download can be performed to parts of the device memory. The host - program is also responsible for erasing flash pages before they - are written to. -

-

.dfu files

-

- A special file format is defined by ST Microsystems to carry firmware - for DfuSe devices. The file contains target information such as address - and alternate interface information in addition to the binary data. - Several blocks of binary data can be combined in one .dfu file. -

-

Alternate interfaces

-

- Different memory locations of the device may have different - characteristics that the host program (dfu-util) has to take - into considerations, such as flash memory page size, read-only - versus read-write segments, the need to erase, and so on. - These parameters are reported by the device in the string - descriptors meant for describing the USB interfaces. - The host program decodes these strings to build a memory map of - the device. Different memory units or address spaces are listed - in separate alternate interface settings that must be selected - according to the memory unit to access. -

-

- Note that dfu-util leaves it to the user to select alternate - interface. When parsing a .dfu file it will skip file segments - not matching the selected alternate interface. Also, some - DfuSe device firmware implementations ignore the setting of - alternate interface and deduct the memory unit from the - address, since they have no address space overlap. -

-

DfuSe special commands

-

- DfuSe special commands are used by the host program during normal - downloads or uploads, such as SET_ADDRESS and ERASE_PAGE. Also - the normal DFU_DNLOAD and DFU_UPLOAD commands have special - implementations in DfuSe. - Many DfuSe devices also support commands to leave DFU mode, - read unprotect the flash memory or mass erase the flash memory. - dfu-util (from version 0.7) - supports adding "leave", "unprotect", or "mass-erase" - to the -s option argument to send such requests in combination - with a download request. These modifiers are separated with a colon. -

-

- Some DfuSe devices have their DfuSe bootloader running from flash - memory. Erasing the whole flash memory would therefore destroy - the DfuSe bootloader itself and practically brick the device - for most users. Any use of modifiers such as "unprotect" - and "mass-erase" therefore needs to be combined with the "force" - modifer. This is not included in the examples, to not encourage - ignorant users to copy and paste such instructions and shoot - themselves in the foot. -

-

- Devices based on for instance STM32F103 all run the bootloader - from flash, since there is no USB bootloader in ROM. -

-

- For instance STM32F107, STM32F2xx and STM32F4xx devices have a - DfuSe bootloader in ROM, so the flash can be erased while - keeping the device available for USB DFU transfers as long - as the device designers use this built-in bootloader and have - not implemented another DfuSe bootloader in flash that the user is - dependent upon. -

-

- Well-written bootloaders running from flash will report their - own memory region as read-only and not eraseable, but this does - not prevent dfu-util from sending a "unprotect" or "mass-erase" - request which overrides this, if the user insists. -

-

Example usage

-

- Flashing a .dfu (special DfuSe format) file to the device: -

-
-         $ dfu-util -a 0 -D /path/to/dfuse-image.dfu
-	
-

- Reading out 1 KB of flash starting at address 0x8000000: -

-
-         $ dfu-util -a 0 -s 0x08000000:1024 -U newfile.bin
-	
-

- Flashing a binary file to address 0x8004000 of device memory and ask - the device to leave DFU mode: -

-
-         $ dfu-util -a 0 -s 0x08004000:leave -D /path/to/image.bin
-	
-

- [Back to dfu-util main page] -

- -
- - diff --git a/macosx/src/dfu-util/www/index.html b/macosx/src/dfu-util/www/index.html deleted file mode 100644 index 108ddaf66..000000000 --- a/macosx/src/dfu-util/www/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - dfu-util Homepage - - - - - - - - - -
-

dfu-util - Device Firmware Upgrade Utilities

-

Description

-

- dfu-util is a host side implementation of the DFU 1.0 and DFU 1.1 specifications of the USB forum. - - DFU is intended to download and upload firmware to/from devices connected - over USB. It ranges from small devices like micro-controller boards - to mobile phones. Using dfu-util you can download firmware to your - DFU-enabled device or upload firmware from it. dfu-util has been - tested with the Openmoko Neo1973 and Freerunner and many other devices. -

-

- See the manual page for examples of use. -

-

Supported Devices

- -

Releases

-

- Releases of the dfu-util software can be found in the - releases folder. - The current release is 0.8. -

-

- We offer binaries for Microsoft Windows and some other platforms. - dfu-util uses libusb 1.0 to access your device, so - on Windows you have to register the device with the WinUSB driver - (alternatively libusb-win32 or libusbK), please see the libusbx wiki - for more details. -

-

- Mac OS X users can also get dfu-util from Homebrew with "brew install dfu-util" or from MacPorts. -

-

- Most Linux distributions ship dfu-util in binary packages for those - who do not want to compile dfu-util from source. - On Debian, Ubuntu, Fedora and Gentoo you can install it through the - normal software package tools. For other distributions -(namely OpenSuSe, Mandriva, and CentOS) Holger Freyther was kind enough to -provide binary packages through the Open Build Service. -

-

Development

-

- Development happens in a GIT repository. Browse it via the web -interface or clone it with: -

-
-	git clone git://gitorious.org/dfu-util/dfu-util.git
-	
-

- See our build instructions for how to - build the source on different platforms. -

-

License

-

- This software is licensed under the GPL version 2. -

-

Contact

-

- If you have questions about the development or use of dfu-util please - send an e-mail to our dedicated -mailing list for dfu-util. -

-

People

-

- dfu-util was originally written by - Harald Welte partially based on code from - dfu-programmer 0.4 and is currently maintained by Stefan Schmidt and - Tormod Volden. -

- -
- - diff --git a/macosx/src/dfu-util/www/simple.css b/macosx/src/dfu-util/www/simple.css deleted file mode 100644 index 98100bc5c..000000000 --- a/macosx/src/dfu-util/www/simple.css +++ /dev/null @@ -1,56 +0,0 @@ -body { - margin: 10px; - font-size: 0.82em; - background-color: #EEE; -} - -h1 { - clear: both; - padding: 0 0 12px 0; - margin: 0; - font-size: 2em; - font-weight: bold; -} - -h2 { - clear: both; - margin: 0; - font-size: 1.5em; - font-weight: normal; -} - -h3 { - clear: both; - margin: 15px 0 0 0; - font-size: 1.0em; - font-weight: bold; -} - -p { - line-height: 20px; - padding: 8px 0 8px 0; - margin: 0; - font-size: 1.1em; -} - -pre { - white-space: pre-wrap; - background-color: #CCC; - padding: 3px; -} - -a:hover { - background-color: #DDD; -} - -#middlebox { - width: 600px; - margin: 0px auto; - text-align: left; -} - -#footer { - height: 100px; - padding: 28px 3px 0 0; - margin: 20px 0 20px 0; -} diff --git a/linux/src/build_dfu-util.sh b/src/dfu-util/build_dfu-util.sh similarity index 96% rename from linux/src/build_dfu-util.sh rename to src/dfu-util/build_dfu-util.sh index 3563f576c..eb4895f1e 100644 --- a/linux/src/build_dfu-util.sh +++ b/src/dfu-util/build_dfu-util.sh @@ -5,7 +5,6 @@ sudo apt-get install build-essentials sudo apt-get install libusb-1.0-0-dev sudo apt-get install autoconf automake autotools-dev -cd dfu-util ./autogen.sh ./configure make diff --git a/win/src/build_dfu-util.sh b/win/src/build_dfu-util.sh deleted file mode 100644 index 3563f576c..000000000 --- a/win/src/build_dfu-util.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -sudo apt-get build-dep dfu-util -sudo apt-get install build-essentials -sudo apt-get install libusb-1.0-0-dev -sudo apt-get install autoconf automake autotools-dev - -cd dfu-util -./autogen.sh -./configure -make -cp src/dfu-util ../../linux/dfu-util -cp src/dfu-suffix ../../linux/dfu-util -cp src/dfu-prefix ../../linux/dfu-util -