├── .gitignore ├── AUTHORS ├── COPYING ├── FIXED_ISSUES.rst ├── Makefile.am ├── README.md ├── README.rst ├── autogen.sh ├── configure.ac └── src ├── Makefile.am ├── dfu_file.c ├── dfu_file.h ├── dfu_load.c ├── dfu_load.h ├── dfu_util_qda.c ├── dfu_util_qda.h ├── main.c ├── portable.h ├── qda ├── qda.c ├── qda.h ├── qda_packets.h ├── serial_io.c ├── serial_io.h ├── serial_io_windows.c ├── xmodem.c └── xmodem.h ├── quirks.c ├── quirks.h └── usb_dfu.h /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | */Makefile 3 | autom4te.cache/ 4 | config.h 5 | configure 6 | m4/ 7 | src/.deps/ 8 | src/dfu-suffix 9 | src/dfu-prefix 10 | src/dfu-util 11 | src/dfu-version.h 12 | stamp-h1 13 | Win32/ 14 | msvc/ipch/ 15 | *.log 16 | *.status 17 | *.m4 18 | *.o 19 | *.in 20 | *.suo 21 | *.user 22 | *.opensdf 23 | *.sdf 24 | *~ 25 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | dfu-util-qda is developed by Intel Corporation and is based on dfu-util. 2 | 3 | This list contains the original authors of dfu-util 0.8 ordered by first 4 | contribution. 5 | 6 | Harald Welte 7 | Werner Almesberger 8 | Michael Lauer 9 | Jim Huang 10 | Stefan Schmidt 11 | Daniel Willmann 12 | Mike Frysinger 13 | Uwe Hermann 14 | C. Scott Ananian 15 | Bernard Blackham 16 | Holger Freyther 17 | Marc Singer 18 | James Perkins 19 | Tommi Keisala 20 | Pascal Schweizer 21 | Bradley Scott 22 | Uwe Bonnes 23 | Andrey Smirnov 24 | Jussi Timperi 25 | Hans Petter Selasky 26 | Bo Shen 27 | Henrique de Almeida Mendonca 28 | Bernd Krumboeck 29 | Dennis Meier 30 | Veli-Pekka Peltola 31 | Dave Hylands 32 | Michael Grzeschik 33 | Paul Fertser 34 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /FIXED_ISSUES.rst: -------------------------------------------------------------------------------- 1 | Fixed Issues 2 | ************ 3 | 4 | Issues fixed since version 1.3.0. 5 | 6 | =========== ==================================================================== 7 | Issue No support for COM ports >= COM10 on Windows 8 | ----------- -------------------------------------------------------------------- 9 | Implication On Windows, when the used serial port is equal to or greater than 10 | COM10, the error "Cannot open serial device" is returned. 11 | ----------- -------------------------------------------------------------------- 12 | Workaround Users should change the COM port number for their device to 13 | something less than COM10. This can be done via the Windows Device 14 | Manager by editing the advanced settings of the serial port. 15 | =========== ==================================================================== 16 | 17 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | EXTRA_DIST = autogen.sh 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DISCONTINUATION OF PROJECT. 2 | 3 | This project will no longer be maintained by Intel. 4 | 5 | This project has been identified as having known security escapes. 6 | 7 | Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project. 8 | 9 | Intel no longer accepts patches to this project. 10 | DISCONTINUATION OF PROJECT. 11 | 12 | This project will no longer be maintained by Intel. 13 | 14 | This project has been identified as having known security escapes. 15 | 16 | Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project. 17 | 18 | Intel no longer accepts patches to this project. 19 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | qm-dfu-util - Intel® Quark™ Microcontroller Device Firmware Upgrade Utility 2 | ########################################################################### 3 | 4 | *qm-dfu-util* is a fork of |dfu-util|_, a host side implementation of the `DFU 5 | 1.0`_ and `DFU 1.1`_ specification of the USB forum. 6 | 7 | DFU is intended to download and upload firmware to devices connected over USB. 8 | It ranges from small devices like micro-controller boards up to mobile phones. 9 | *qm-dfu-util* allows you to download firmware to your Intel® Quark™ 10 | Microcontroller by using the serial interface (UART). 11 | 12 | Building 13 | ******** 14 | 15 | LINUX 16 | ===== 17 | 18 | For building the host tool, first configure the build with:: 19 | 20 | ./autogen.sh 21 | ./configure 22 | 23 | Then compile it with:: 24 | 25 | make 26 | 27 | The generated binary is ``src/dfu-util-qda``. You can have it installed into 28 | your GNU/Linux host with:: 29 | 30 | sudo make install 31 | 32 | The binary will be put into ``/usr/local/bin/``. 33 | 34 | WINDOWS 35 | ======= 36 | 37 | Windows Native with MSYS 38 | ------------------------ 39 | 40 | Windows binaries can be built in a MSYS2 environment, which provides a 41 | Linux-like environment for Windows. 42 | 43 | MSYS2 can be downloaded from http://msys2.github.io 44 | 45 | Install it and then copy the qm-dfu-util folder to 46 | ``\home\``. 47 | 48 | Open MSYS2 Shell and install the needed components:: 49 | 50 | pacman -S autoconf 51 | pacman -S perl 52 | pacman -S automake 53 | pacman -S make 54 | pacman -S mingw-w64-x86_64-gcc 55 | PATH=$PATH:/mingw64/bin/ 56 | 57 | To build the host tool, first configure the build with:: 58 | 59 | ./autogen.sh 60 | ./configure 61 | 62 | Then compile it with:: 63 | 64 | make 65 | 66 | The generated binary is ``src/dfu-util-qda.exe``. 67 | 68 | 69 | Windows Cross-compile from Ubuntu 16.04 70 | --------------------------------------- 71 | 72 | Windows binaries can also be cross-compiled from Ubuntu. 73 | 74 | First, install MinGW:: 75 | 76 | sudo apt-get install mingw-w64 77 | 78 | Then, configure the build with:: 79 | 80 | ./autogen.sh 81 | ./configure --host=x86_64-w64-mingw32 82 | 83 | Finally compile it with:: 84 | 85 | make 86 | 87 | The generated binary is ``src/dfu-util-qda.exe``. 88 | 89 | .. |dfu-util| replace:: *dfu-util* 90 | .. _dfu-util: http://dfu-util.gnumonks.org 91 | .. _`DFU 1.0`: http://www.usb.org/developers/devclass_docs/usbdfu10.pdf 92 | .. _`DFU 1.1`: http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf 93 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | autoreconf -v -i 3 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.59) 5 | AC_INIT([dfu-util-qda],[1.3.0 (dfu-util 0.8)],,,]) 6 | AC_CONFIG_AUX_DIR(m4) 7 | AM_INIT_AUTOMAKE([foreign]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | 10 | # Test for new silent rules and enable only if they are available 11 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 12 | 13 | # Checks for programs. 14 | AC_PROG_CC 15 | 16 | # Checks for libraries. 17 | LIBS="$LIBS" 18 | CFLAGS="$CFLAGS" 19 | 20 | # Checks for header files. 21 | AC_HEADER_STDC 22 | AC_CHECK_HEADERS([usbpath.h windows.h sysexits.h]) 23 | 24 | # Check if it's a Windows system 25 | AC_CHECK_HEADER([windows.h], [windows_build=yes]) 26 | AM_CONDITIONAL([WINDOWS_BUILD], [test "x$windows_build" = "xyes"]) 27 | 28 | # Checks for typedefs, structures, and compiler characteristics. 29 | AC_C_CONST 30 | AC_TYPE_SIZE_T 31 | 32 | # Checks for library functions. 33 | AC_FUNC_MEMCMP 34 | AC_CHECK_FUNCS([ftruncate getpagesize nanosleep err]) 35 | 36 | AC_CONFIG_FILES(Makefile src/Makefile) 37 | AC_OUTPUT 38 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = subdir-objects 2 | bin_PROGRAMS = dfu-util-qda 3 | 4 | dfu_util_qda_CFLAGS = -Wall -Wextra -DUSE_QDA -I./qda/ 5 | dfu_util_qda_SOURCES = main.c \ 6 | portable.h \ 7 | dfu_load.c \ 8 | dfu_load.h \ 9 | dfu_util_qda.c \ 10 | dfu_util_qda.h \ 11 | usb_dfu.h \ 12 | dfu_file.c \ 13 | dfu_file.h \ 14 | qda/qda.c \ 15 | qda/xmodem.c \ 16 | quirks.c \ 17 | quirks.h 18 | 19 | if WINDOWS_BUILD 20 | dfu_util_qda_SOURCES += qda/serial_io_windows.c 21 | dfu_util_qda_LDFLAGS = -static 22 | else 23 | dfu_util_qda_SOURCES += qda/serial_io.c 24 | endif -------------------------------------------------------------------------------- /src/dfu_file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Load or store DFU files including suffix and prefix 3 | * 4 | * Copyright 2014 Tormod Volden 5 | * Copyright 2012 Stefan Schmidt 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "portable.h" 31 | #include "dfu_file.h" 32 | 33 | #define DFU_SUFFIX_LENGTH 16 34 | #define LMDFU_PREFIX_LENGTH 8 35 | #define LPCDFU_PREFIX_LENGTH 16 36 | #define PROGRESS_BAR_WIDTH 25 37 | #define STDIN_CHUNK_SIZE 65536 38 | 39 | static const unsigned long crc32_table[] = { 40 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 41 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 42 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 43 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 44 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 45 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 46 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 47 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 48 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 49 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 50 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 51 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 52 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 53 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 54 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 55 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 56 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 57 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 58 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 59 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 60 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 61 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 62 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 63 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 64 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 65 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 66 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 67 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 68 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 69 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 70 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 71 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 72 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 73 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 74 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 75 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 76 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 77 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 78 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 79 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 80 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 81 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 82 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; 83 | 84 | static uint32_t crc32_byte(uint32_t accum, uint8_t delta) 85 | { 86 | return crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8); 87 | } 88 | 89 | static int probe_prefix(struct dfu_file *file) 90 | { 91 | uint8_t *prefix = file->firmware; 92 | 93 | if (file->size.total < LMDFU_PREFIX_LENGTH) 94 | return 1; 95 | if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) { 96 | file->prefix_type = LMDFU_PREFIX; 97 | file->size.prefix = LMDFU_PREFIX_LENGTH; 98 | file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]); 99 | } 100 | else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f)== 0x3f)) { 101 | file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX; 102 | file->size.prefix = LPCDFU_PREFIX_LENGTH; 103 | } 104 | 105 | if (file->size.prefix + file->size.suffix > file->size.total) 106 | return 1; 107 | return 0; 108 | } 109 | 110 | void dfu_progress_bar(const char *desc, unsigned long long curr, 111 | unsigned long long max) 112 | { 113 | static char buf[PROGRESS_BAR_WIDTH + 1]; 114 | static unsigned long long last_progress = -1; 115 | static time_t last_time; 116 | time_t curr_time = time(NULL); 117 | unsigned long long progress; 118 | unsigned long long x; 119 | 120 | /* check for not known maximum */ 121 | if (max < curr) 122 | max = curr + 1; 123 | /* make none out of none give zero */ 124 | if (max == 0 && curr == 0) 125 | max = 1; 126 | 127 | /* compute completion */ 128 | progress = (PROGRESS_BAR_WIDTH * curr) / max; 129 | if (progress > PROGRESS_BAR_WIDTH) 130 | progress = PROGRESS_BAR_WIDTH; 131 | if (progress == last_progress && 132 | curr_time == last_time) 133 | return; 134 | last_progress = progress; 135 | last_time = curr_time; 136 | 137 | for (x = 0; x != PROGRESS_BAR_WIDTH; x++) { 138 | if (x < progress) 139 | buf[x] = '='; 140 | else 141 | buf[x] = ' '; 142 | } 143 | buf[x] = 0; 144 | 145 | #ifdef HAVE_WINDOWS_H 146 | printf("\r%s\t[%s] %3I64d%% %12I64d bytes", desc, buf, 147 | (100ULL * curr) / max, curr); 148 | #else 149 | printf("\r%s\t[%s] %3lld%% %12lld bytes", desc, buf, 150 | (100ULL * curr) / max, curr); 151 | #endif 152 | 153 | if (progress == PROGRESS_BAR_WIDTH) 154 | printf("\n%s done.\n", desc); 155 | } 156 | 157 | void *dfu_malloc(size_t size) 158 | { 159 | void *ptr = malloc(size); 160 | if (ptr == NULL) 161 | errx(EX_SOFTWARE, "Cannot allocate memory of size %d bytes", (int)size); 162 | return (ptr); 163 | } 164 | 165 | uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size) 166 | { 167 | int x; 168 | 169 | /* compute CRC */ 170 | for (x = 0; x != size; x++) 171 | crc = crc32_byte(crc, ((uint8_t *)buf)[x]); 172 | 173 | /* write data */ 174 | if (write(f, buf, size) != size) 175 | err(EX_IOERR, "Could not write %d bytes to file %d", size, f); 176 | 177 | return (crc); 178 | } 179 | 180 | void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix) 181 | { 182 | off_t offset; 183 | int f; 184 | int i; 185 | int res; 186 | 187 | file->size.prefix = 0; 188 | file->size.suffix = 0; 189 | 190 | /* default values, if no valid suffix is found */ 191 | file->bcdDFU = 0; 192 | file->idVendor = 0xffff; /* wildcard value */ 193 | file->idProduct = 0xffff; /* wildcard value */ 194 | file->bcdDevice = 0xffff; /* wildcard value */ 195 | 196 | /* default values, if no valid prefix is found */ 197 | file->lmdfu_address = 0; 198 | 199 | free(file->firmware); 200 | 201 | if (!strcmp(file->name, "-")) { 202 | int read_bytes; 203 | 204 | #ifdef WIN32 205 | _setmode( _fileno( stdin ), _O_BINARY ); 206 | #endif 207 | file->firmware = (uint8_t*) dfu_malloc(STDIN_CHUNK_SIZE); 208 | read_bytes = fread(file->firmware, 1, STDIN_CHUNK_SIZE, stdin); 209 | file->size.total = read_bytes; 210 | while (read_bytes == STDIN_CHUNK_SIZE) { 211 | file->firmware = (uint8_t*) realloc(file->firmware, file->size.total + STDIN_CHUNK_SIZE); 212 | if (!file->firmware) 213 | err(EX_IOERR, "Could not allocate firmware buffer"); 214 | read_bytes = fread(file->firmware + file->size.total, 1, STDIN_CHUNK_SIZE, stdin); 215 | file->size.total += read_bytes; 216 | } 217 | if (verbose) 218 | printf("Read %i bytes from stdin\n", file->size.total); 219 | /* Never require suffix when reading from stdin */ 220 | check_suffix = MAYBE_SUFFIX; 221 | } else { 222 | f = open(file->name, O_RDONLY | O_BINARY); 223 | if (f < 0) 224 | err(EX_IOERR, "Could not open file %s for reading", file->name); 225 | 226 | offset = lseek(f, 0, SEEK_END); 227 | 228 | if ((int)offset < 0 || (int)offset != offset) 229 | err(EX_IOERR, "File size is too big"); 230 | 231 | if (lseek(f, 0, SEEK_SET) != 0) 232 | err(EX_IOERR, "Could not seek to beginning"); 233 | 234 | file->size.total = offset; 235 | file->firmware = dfu_malloc(file->size.total); 236 | 237 | if (read(f, file->firmware, file->size.total) != file->size.total) { 238 | err(EX_IOERR, "Could not read %d bytes from %s", 239 | file->size.total, file->name); 240 | } 241 | close(f); 242 | } 243 | 244 | /* Check for possible DFU file suffix by trying to parse one */ 245 | { 246 | uint32_t crc = 0xffffffff; 247 | const uint8_t *dfusuffix; 248 | int missing_suffix = 0; 249 | const char *reason; 250 | 251 | if (file->size.total < DFU_SUFFIX_LENGTH) { 252 | reason = "File too short for DFU suffix"; 253 | missing_suffix = 1; 254 | goto checked; 255 | } 256 | 257 | dfusuffix = file->firmware + file->size.total - 258 | DFU_SUFFIX_LENGTH; 259 | 260 | for (i = 0; i < file->size.total - 4; i++) 261 | crc = crc32_byte(crc, file->firmware[i]); 262 | 263 | if (dfusuffix[10] != 'D' || 264 | dfusuffix[9] != 'F' || 265 | dfusuffix[8] != 'U') { 266 | reason = "Invalid DFU suffix signature"; 267 | missing_suffix = 1; 268 | goto checked; 269 | } 270 | 271 | file->dwCRC = (dfusuffix[15] << 24) + 272 | (dfusuffix[14] << 16) + 273 | (dfusuffix[13] << 8) + 274 | dfusuffix[12]; 275 | 276 | if (file->dwCRC != crc) { 277 | reason = "DFU suffix CRC does not match"; 278 | missing_suffix = 1; 279 | goto checked; 280 | } 281 | 282 | /* At this point we believe we have a DFU suffix 283 | so we require further checks to succeed */ 284 | 285 | file->bcdDFU = (dfusuffix[7] << 8) + dfusuffix[6]; 286 | 287 | if (verbose) 288 | printf("DFU suffix version %x\n", file->bcdDFU); 289 | 290 | file->size.suffix = dfusuffix[11]; 291 | 292 | if (file->size.suffix < DFU_SUFFIX_LENGTH) { 293 | errx(EX_IOERR, "Unsupported DFU suffix length %d", 294 | file->size.suffix); 295 | } 296 | 297 | if (file->size.suffix > file->size.total) { 298 | errx(EX_IOERR, "Invalid DFU suffix length %d", 299 | file->size.suffix); 300 | } 301 | 302 | file->idVendor = (dfusuffix[5] << 8) + dfusuffix[4]; 303 | file->idProduct = (dfusuffix[3] << 8) + dfusuffix[2]; 304 | file->bcdDevice = (dfusuffix[1] << 8) + dfusuffix[0]; 305 | 306 | checked: 307 | if (missing_suffix) { 308 | if (check_suffix == NEEDS_SUFFIX) { 309 | warnx("%s", reason); 310 | errx(EX_IOERR, "Valid DFU suffix needed"); 311 | } else if (check_suffix == MAYBE_SUFFIX) { 312 | warnx("%s", reason); 313 | warnx("A valid DFU suffix will be required in " 314 | "a future dfu-util release!!!"); 315 | } 316 | } else { 317 | if (check_suffix == NO_SUFFIX) { 318 | errx(EX_SOFTWARE, "Please remove existing DFU suffix before adding a new one.\n"); 319 | } 320 | } 321 | } 322 | res = probe_prefix(file); 323 | if ((res || file->size.prefix == 0) && check_prefix == NEEDS_PREFIX) 324 | errx(EX_IOERR, "Valid DFU prefix needed"); 325 | if (file->size.prefix && check_prefix == NO_PREFIX) 326 | errx(EX_IOERR, "A prefix already exists, please delete it first"); 327 | if (file->size.prefix && verbose) { 328 | uint8_t *data = file->firmware; 329 | if (file->prefix_type == LMDFU_PREFIX) 330 | printf("Possible TI Stellaris DFU prefix with " 331 | "the following properties\n" 332 | "Address: 0x%08x\n" 333 | "Payload length: %d\n", 334 | file->lmdfu_address, 335 | data[4] | (data[5] << 8) | 336 | (data[6] << 16) | (data[7] << 14)); 337 | else if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) 338 | printf("Possible unencrypted NXP LPC DFU prefix with " 339 | "the following properties\n" 340 | "Payload length: %d kiByte\n", 341 | data[2] >>1 | (data[3] << 7) ); 342 | else 343 | errx(EX_IOERR, "Unknown DFU prefix type"); 344 | } 345 | } 346 | 347 | void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix) 348 | { 349 | uint32_t crc = 0xffffffff; 350 | int f; 351 | 352 | f = open(file->name, O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, 0666); 353 | if (f < 0) 354 | err(EX_IOERR, "Could not open file %s for writing", file->name); 355 | 356 | /* write prefix, if any */ 357 | if (write_prefix) { 358 | if (file->prefix_type == LMDFU_PREFIX) { 359 | uint8_t lmdfu_prefix[LMDFU_PREFIX_LENGTH]; 360 | uint32_t addr = file->lmdfu_address / 1024; 361 | 362 | /* lmdfu_dfu_prefix payload length excludes prefix and suffix */ 363 | uint32_t len = file->size.total - 364 | file->size.prefix - file->size.suffix; 365 | 366 | lmdfu_prefix[0] = 0x01; /* STELLARIS_DFU_PROG */ 367 | lmdfu_prefix[1] = 0x00; /* Reserved */ 368 | lmdfu_prefix[2] = (uint8_t)(addr & 0xff); 369 | lmdfu_prefix[3] = (uint8_t)(addr >> 8); 370 | lmdfu_prefix[4] = (uint8_t)(len & 0xff); 371 | lmdfu_prefix[5] = (uint8_t)(len >> 8) & 0xff; 372 | lmdfu_prefix[6] = (uint8_t)(len >> 16) & 0xff; 373 | lmdfu_prefix[7] = (uint8_t)(len >> 24); 374 | 375 | crc = dfu_file_write_crc(f, crc, lmdfu_prefix, LMDFU_PREFIX_LENGTH); 376 | } 377 | if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) { 378 | uint8_t lpcdfu_prefix[LPCDFU_PREFIX_LENGTH] = {0}; 379 | int i; 380 | 381 | /* Payload is firmware and prefix rounded to 512 bytes */ 382 | uint32_t len = (file->size.total - file->size.suffix + 511) /512; 383 | 384 | lpcdfu_prefix[0] = 0x1a; /* Unencypted*/ 385 | lpcdfu_prefix[1] = 0x3f; /* Reserved */ 386 | lpcdfu_prefix[2] = (uint8_t)(len & 0xff); 387 | lpcdfu_prefix[3] = (uint8_t)((len >> 8) & 0xff); 388 | for (i = 12; i < LPCDFU_PREFIX_LENGTH; i++) 389 | lpcdfu_prefix[i] = 0xff; 390 | 391 | crc = dfu_file_write_crc(f, crc, lpcdfu_prefix, LPCDFU_PREFIX_LENGTH); 392 | } 393 | } 394 | /* write firmware binary */ 395 | crc = dfu_file_write_crc(f, crc, file->firmware + file->size.prefix, 396 | file->size.total - file->size.prefix - file->size.suffix); 397 | 398 | /* write suffix, if any */ 399 | if (write_suffix) { 400 | uint8_t dfusuffix[DFU_SUFFIX_LENGTH]; 401 | 402 | dfusuffix[0] = file->bcdDevice & 0xff; 403 | dfusuffix[1] = file->bcdDevice >> 8; 404 | dfusuffix[2] = file->idProduct & 0xff; 405 | dfusuffix[3] = file->idProduct >> 8; 406 | dfusuffix[4] = file->idVendor & 0xff; 407 | dfusuffix[5] = file->idVendor >> 8; 408 | dfusuffix[6] = file->bcdDFU & 0xff; 409 | dfusuffix[7] = file->bcdDFU >> 8; 410 | dfusuffix[8] = 'U'; 411 | dfusuffix[9] = 'F'; 412 | dfusuffix[10] = 'D'; 413 | dfusuffix[11] = DFU_SUFFIX_LENGTH; 414 | 415 | crc = dfu_file_write_crc(f, crc, dfusuffix, 416 | DFU_SUFFIX_LENGTH - 4); 417 | 418 | dfusuffix[12] = crc; 419 | dfusuffix[13] = crc >> 8; 420 | dfusuffix[14] = crc >> 16; 421 | dfusuffix[15] = crc >> 24; 422 | 423 | crc = dfu_file_write_crc(f, crc, dfusuffix + 12, 4); 424 | } 425 | close(f); 426 | } 427 | 428 | void show_suffix_and_prefix(struct dfu_file *file) 429 | { 430 | if (file->size.prefix == LMDFU_PREFIX_LENGTH) { 431 | printf("The file %s contains a TI Stellaris DFU prefix with the following properties:\n", file->name); 432 | printf("Address:\t0x%08x\n", file->lmdfu_address); 433 | } else if (file->size.prefix == LPCDFU_PREFIX_LENGTH) { 434 | uint8_t * prefix = file->firmware; 435 | printf("The file %s contains a NXP unencrypted LPC DFU prefix with the following properties:\n", file->name); 436 | printf("Size:\t%5d kiB\n", prefix[2]>>1|prefix[3]<<7); 437 | } else if (file->size.prefix != 0) { 438 | printf("The file %s contains an unknown prefix\n", file->name); 439 | } 440 | if (file->size.suffix > 0) { 441 | printf("The file %s contains a DFU suffix with the following properties:\n", file->name); 442 | printf("BCD device:\t0x%04X\n", file->bcdDevice); 443 | printf("Product ID:\t0x%04X\n",file->idProduct); 444 | printf("Vendor ID:\t0x%04X\n", file->idVendor); 445 | printf("BCD DFU:\t0x%04X\n", file->bcdDFU); 446 | printf("Length:\t\t%i\n", file->size.suffix); 447 | printf("CRC:\t\t0x%08X\n", file->dwCRC); 448 | } 449 | } 450 | -------------------------------------------------------------------------------- /src/dfu_file.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DFU_FILE_H 3 | #define DFU_FILE_H 4 | 5 | #include 6 | 7 | struct dfu_file { 8 | /* File name */ 9 | const char *name; 10 | /* Pointer to file loaded into memory */ 11 | uint8_t *firmware; 12 | /* Different sizes */ 13 | struct { 14 | int total; 15 | int prefix; 16 | int suffix; 17 | } size; 18 | /* From prefix fields */ 19 | uint32_t lmdfu_address; 20 | /* From prefix fields */ 21 | uint32_t prefix_type; 22 | 23 | /* From DFU suffix fields */ 24 | uint32_t dwCRC; 25 | uint16_t bcdDFU; 26 | uint16_t idVendor; 27 | uint16_t idProduct; 28 | uint16_t bcdDevice; 29 | }; 30 | 31 | enum suffix_req { 32 | NO_SUFFIX, 33 | NEEDS_SUFFIX, 34 | MAYBE_SUFFIX 35 | }; 36 | 37 | enum prefix_req { 38 | NO_PREFIX, 39 | NEEDS_PREFIX, 40 | MAYBE_PREFIX 41 | }; 42 | 43 | enum prefix_type { 44 | ZERO_PREFIX, 45 | LMDFU_PREFIX, 46 | LPCDFU_UNENCRYPTED_PREFIX 47 | }; 48 | 49 | extern int verbose; 50 | 51 | void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix); 52 | void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix); 53 | 54 | void dfu_progress_bar(const char *desc, unsigned long long curr, 55 | unsigned long long max); 56 | void *dfu_malloc(size_t size); 57 | uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size); 58 | void show_suffix_and_prefix(struct dfu_file *file); 59 | 60 | #endif /* DFU_FILE_H */ 61 | -------------------------------------------------------------------------------- /src/dfu_load.c: -------------------------------------------------------------------------------- 1 | /* 2 | * DFU transfer routines 3 | * 4 | * This is supposed to be a general DFU implementation, as specified in the 5 | * USB DFU 1.0 and 1.1 specification. 6 | * 7 | * The code was originally intended to interface with a USB device running the 8 | * "sam7dfu" firmware (see http://www.openpcd.org/) on an AT91SAM7 processor. 9 | * 10 | * Copyright 2007-2008 Harald Welte 11 | * Copyright 2013 Hans Petter Selasky 12 | * Copyright 2014 Tormod Volden 13 | * Copyright 2016 Intel Corporation. 14 | * 15 | * This program is free software; you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * This program is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with this program; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #ifndef USE_QDA 36 | #include 37 | #endif 38 | 39 | #include "portable.h" 40 | 41 | #ifdef USE_QDA 42 | #include "qda.h" 43 | #else 44 | #include "dfu.h" 45 | #endif 46 | 47 | #include "usb_dfu.h" 48 | #include "dfu_file.h" 49 | #include "dfu_load.h" 50 | #include "quirks.h" 51 | 52 | int dfuload_do_upload(struct dfu_if *dif, int xfer_size, 53 | int expected_size, int fd) 54 | { 55 | int total_bytes = 0; 56 | unsigned short transaction = 0; 57 | unsigned char *buf; 58 | int ret; 59 | 60 | buf = dfu_malloc(xfer_size); 61 | 62 | printf("Copying data from DFU device to PC\n"); 63 | dfu_progress_bar("Upload", 0, 1); 64 | 65 | while (1) { 66 | int rc; 67 | rc = dfu_upload(dif->dev_handle, dif->interface, 68 | xfer_size, transaction++, buf); 69 | if (rc < 0) { 70 | warnx("Error during upload"); 71 | ret = rc; 72 | goto out_free; 73 | } 74 | 75 | dfu_file_write_crc(fd, 0, buf, rc); 76 | total_bytes += rc; 77 | 78 | if (total_bytes < 0) 79 | errx(EX_SOFTWARE, "Received too many bytes (wraparound)"); 80 | 81 | if (rc < xfer_size) { 82 | /* last block, return */ 83 | ret = total_bytes; 84 | break; 85 | } 86 | dfu_progress_bar("Upload", total_bytes, expected_size); 87 | } 88 | ret = 0; 89 | 90 | out_free: 91 | dfu_progress_bar("Upload", total_bytes, total_bytes); 92 | if (total_bytes == 0) 93 | printf("\nFailed.\n"); 94 | free(buf); 95 | if (verbose) 96 | printf("Received a total of %i bytes\n", total_bytes); 97 | if (expected_size != 0 && total_bytes != expected_size) 98 | errx(EX_SOFTWARE, "Unexpected number of bytes uploaded from device"); 99 | return ret; 100 | } 101 | 102 | int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file) 103 | { 104 | int bytes_sent; 105 | int expected_size; 106 | unsigned char *buf; 107 | unsigned short transaction = 0; 108 | struct dfu_status dst; 109 | int ret; 110 | 111 | printf("Copying data from PC to DFU device\n"); 112 | 113 | buf = file->firmware; 114 | expected_size = file->size.total - file->size.suffix; 115 | bytes_sent = 0; 116 | 117 | dfu_progress_bar("Download", 0, 1); 118 | while (bytes_sent < expected_size) { 119 | int bytes_left; 120 | int chunk_size; 121 | 122 | bytes_left = expected_size - bytes_sent; 123 | if (bytes_left < xfer_size) 124 | chunk_size = bytes_left; 125 | else 126 | chunk_size = xfer_size; 127 | 128 | ret = dfu_download(dif->dev_handle, dif->interface, 129 | chunk_size, transaction++, chunk_size ? buf : NULL); 130 | if (ret < 0) { 131 | warnx("Error during download"); 132 | goto out; 133 | } 134 | bytes_sent += chunk_size; 135 | buf += chunk_size; 136 | 137 | do { 138 | ret = dfu_get_status(dif, &dst); 139 | if (ret < 0) { 140 | errx(EX_IOERR, "Error during download get_status"); 141 | goto out; 142 | } 143 | 144 | if (dst.bState == DFU_STATE_dfuDNLOAD_IDLE || 145 | dst.bState == DFU_STATE_dfuERROR) 146 | break; 147 | 148 | /* Wait while device executes flashing */ 149 | milli_sleep(dst.bwPollTimeout); 150 | 151 | } while (1); 152 | if (dst.bStatus != DFU_STATUS_OK) { 153 | printf(" failed!\n"); 154 | printf("state(%u) = %s, status(%u) = %s\n", dst.bState, 155 | dfu_state_to_string(dst.bState), dst.bStatus, 156 | dfu_status_to_string(dst.bStatus)); 157 | ret = -1; 158 | goto out; 159 | } 160 | dfu_progress_bar("Download", bytes_sent, bytes_sent + bytes_left); 161 | } 162 | 163 | /* send one zero sized download request to signalize end */ 164 | ret = dfu_download(dif->dev_handle, dif->interface, 165 | 0, transaction, NULL); 166 | if (ret < 0) { 167 | errx(EX_IOERR, "Error sending completion packet"); 168 | goto out; 169 | } 170 | 171 | dfu_progress_bar("Download", bytes_sent, bytes_sent); 172 | 173 | if (verbose) 174 | printf("Sent a total of %i bytes\n", bytes_sent); 175 | 176 | get_status: 177 | /* Transition to MANIFEST_SYNC state */ 178 | ret = dfu_get_status(dif, &dst); 179 | if (ret < 0) { 180 | warnx("unable to read DFU status after completion"); 181 | goto out; 182 | } 183 | printf("state(%u) = %s, status(%u) = %s\n", dst.bState, 184 | dfu_state_to_string(dst.bState), dst.bStatus, 185 | dfu_status_to_string(dst.bStatus)); 186 | 187 | milli_sleep(dst.bwPollTimeout); 188 | 189 | /* FIXME: deal correctly with ManifestationTolerant=0 / WillDetach bits */ 190 | switch (dst.bState) { 191 | case DFU_STATE_dfuMANIFEST_SYNC: 192 | case DFU_STATE_dfuMANIFEST: 193 | /* some devices (e.g. TAS1020b) need some time before we 194 | * can obtain the status */ 195 | milli_sleep(1000); 196 | goto get_status; 197 | break; 198 | case DFU_STATE_dfuIDLE: 199 | break; 200 | } 201 | printf("Done!\n"); 202 | 203 | out: 204 | return bytes_sent; 205 | } 206 | -------------------------------------------------------------------------------- /src/dfu_load.h: -------------------------------------------------------------------------------- 1 | #ifndef DFU_LOAD_H 2 | #define DFU_LOAD_H 3 | 4 | int dfuload_do_upload(struct dfu_if *dif, int xfer_size, int expected_size, int fd); 5 | int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file); 6 | 7 | #endif /* DFU_LOAD_H */ 8 | -------------------------------------------------------------------------------- /src/dfu_util_qda.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "qda.h" 28 | #include "xmodem.h" 29 | 30 | #define DEBUG_MSG (0) 31 | 32 | #if DEBUG_MSG 33 | #define printd(...) printf(__VA_ARGS__) 34 | #else 35 | #define printd(...) 36 | #endif 37 | 38 | /* called from QDA */ 39 | int dfu_util_qda_send(uint8_t *data, size_t len) 40 | { 41 | printd("QDA send: (%d)\n", len); 42 | return xmodem_transmit_package(data, len); 43 | } 44 | 45 | /* called from QDA */ 46 | size_t dfu_util_qda_receive(uint8_t *data, size_t len) 47 | { 48 | int ret; 49 | 50 | printd("QDA receive: (%d)\n", len); 51 | ret = xmodem_receive_package(data, len); 52 | 53 | return (ret==-1)?0:ret; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/dfu_util_qda.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #ifndef DFU_UTIL_QDA_H 20 | #define DFU_UTIL_QDA_H 21 | 22 | #include 23 | 24 | enum mode { 25 | MODE_NONE, 26 | MODE_VERSION, 27 | MODE_LIST, 28 | MODE_DETACH, 29 | MODE_UPLOAD, 30 | MODE_DOWNLOAD 31 | }; 32 | 33 | /** 34 | * Send a QDA message using XMODEM. 35 | * 36 | * This function is called by QDA as a send callback. 37 | * 38 | * @param[in] data Data to be sent. 39 | * @param[in] len Length of data to be sent. 40 | * 41 | * @return Error Status 42 | * @retval 0 Success 43 | * @retval <0 Error (Forwarded error code from XMODEM) 44 | */ 45 | int dfu_util_qda_send(uint8_t *data, size_t len); 46 | 47 | /** 48 | * Receive a QDA message using XMODEM. 49 | * 50 | * This function is called by QDA as a receive callback. 51 | * 52 | * @param[out] data Data buffer for received bytes. 53 | * @param[in] len Maximum allocated bytes that can be received. 54 | * 55 | * @return Length of received data. 56 | */ 57 | size_t dfu_util_qda_receive(uint8_t *data, size_t len); 58 | 59 | #endif /* DFU_UTIL_QDA_H */ 60 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dfu-util 3 | * 4 | * Copyright 2007-2008 by OpenMoko, Inc. 5 | * Copyright 2013-2014 Hans Petter Selasky 6 | * Copyright 2016 Intel Corporation. 7 | * 8 | * Written by Harald Welte 9 | * 10 | * Based on existing code of dfu-programmer-0.4 11 | * 12 | * This program is free software; you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation; either version 2 of the License, or 15 | * (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU General Public License 23 | * along with this program; if not, write to the Free Software 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifndef USE_QDA 33 | #include 34 | #endif 35 | 36 | #include 37 | #include 38 | 39 | #include "portable.h" 40 | #ifdef USE_QDA 41 | #include "qda.h" 42 | #include "serial_io.h" 43 | #include "dfu_util_qda.h" 44 | #else 45 | #include "dfu.h" 46 | #endif 47 | #include "usb_dfu.h" 48 | #include "dfu_file.h" 49 | #include "dfu_load.h" 50 | #ifndef USE_QDA 51 | #include "dfu_util.h" 52 | #include "dfuse.h" 53 | #endif 54 | #include "quirks.h" 55 | 56 | #ifdef HAVE_USBPATH_H 57 | #include 58 | #endif 59 | 60 | int verbose = 0; 61 | 62 | struct dfu_if *dfu_root = NULL; 63 | 64 | int match_bus = -1; 65 | int match_device = -1; 66 | int match_vendor = -1; 67 | int match_product = -1; 68 | int match_vendor_dfu = -1; 69 | int match_product_dfu = -1; 70 | int match_config_index = -1; 71 | int match_iface_index = -1; 72 | int match_iface_alt_index = -1; 73 | const char *match_iface_alt_name = NULL; 74 | const char *match_serial = NULL; 75 | const char *match_serial_dfu = NULL; 76 | 77 | static int parse_match_value(const char *str, int default_value) 78 | { 79 | char *remainder; 80 | int value; 81 | 82 | if (str == NULL) { 83 | value = default_value; 84 | } else if (*str == '*') { 85 | value = -1; /* Match anything */ 86 | } else if (*str == '-') { 87 | value = 0x10000; /* Impossible vendor/product ID */ 88 | } else { 89 | value = strtoul(str, &remainder, 16); 90 | if (remainder == str) { 91 | value = default_value; 92 | } 93 | } 94 | return value; 95 | } 96 | 97 | static void parse_vendprod(const char *str) 98 | { 99 | const char *comma; 100 | const char *colon; 101 | 102 | /* Default to match any DFU device in runtime or DFU mode */ 103 | match_vendor = -1; 104 | match_product = -1; 105 | match_vendor_dfu = -1; 106 | match_product_dfu = -1; 107 | 108 | comma = strchr(str, ','); 109 | if (comma == str) { 110 | /* DFU mode vendor/product being specified without any runtime 111 | * vendor/product specification, so don't match any runtime device */ 112 | match_vendor = match_product = 0x10000; 113 | } else { 114 | colon = strchr(str, ':'); 115 | if (colon != NULL) { 116 | ++colon; 117 | if ((comma != NULL) && (colon > comma)) { 118 | colon = NULL; 119 | } 120 | } 121 | match_vendor = parse_match_value(str, match_vendor); 122 | match_product = parse_match_value(colon, match_product); 123 | if (comma != NULL) { 124 | /* Both runtime and DFU mode vendor/product specifications are 125 | * available, so default DFU mode match components to the given 126 | * runtime match components */ 127 | match_vendor_dfu = match_vendor; 128 | match_product_dfu = match_product; 129 | } 130 | } 131 | if (comma != NULL) { 132 | ++comma; 133 | colon = strchr(comma, ':'); 134 | if (colon != NULL) { 135 | ++colon; 136 | } 137 | match_vendor_dfu = parse_match_value(comma, match_vendor_dfu); 138 | match_product_dfu = parse_match_value(colon, match_product_dfu); 139 | } 140 | } 141 | 142 | static void parse_serial(char *str) 143 | { 144 | char *comma; 145 | 146 | match_serial = str; 147 | comma = strchr(str, ','); 148 | if (comma == NULL) { 149 | match_serial_dfu = match_serial; 150 | } else { 151 | *comma++ = 0; 152 | match_serial_dfu = comma; 153 | } 154 | if (*match_serial == 0) match_serial = NULL; 155 | if (*match_serial_dfu == 0) match_serial_dfu = NULL; 156 | } 157 | 158 | #ifdef HAVE_USBPATH_H 159 | 160 | static int resolve_device_path(char *path) 161 | { 162 | int res; 163 | 164 | res = usb_path2devnum(path); 165 | if (res < 0) 166 | return -EINVAL; 167 | if (!res) 168 | return 0; 169 | 170 | match_bus = atoi(path); 171 | match_device = res; 172 | 173 | return 0; 174 | } 175 | 176 | #else /* HAVE_USBPATH_H */ 177 | #ifndef USE_QDA 178 | 179 | static int resolve_device_path(char *path) 180 | { 181 | (void)path; /* Eliminate unused variable warning */ 182 | errx(EX_SOFTWARE, "USB device paths are not supported by this dfu-util.\n"); 183 | } 184 | 185 | #endif /* !USE_QDA */ 186 | #endif /* !HAVE_USBPATH_H */ 187 | 188 | #ifdef USE_QDA 189 | static void help(void) 190 | { 191 | fprintf(stderr, 192 | "Usage: dfu-util-qda [options] ...\n" 193 | " -h --help\t\t\tPrint this help message\n" 194 | " -V --version\t\t\tPrint the version number\n" 195 | " -v --verbose\t\t\tPrint verbose debug statements\n"); 196 | fprintf(stderr, 197 | " -p --path \tSpecify path to UART\n" 198 | " -s --speed \tSpecify UART baud rate [default: 115200]\n" 199 | " -t --transfer-size \tOverride DFU transfer block size.\n" 200 | " -a --alt \t\tSpecify the Altsetting of the DFU Interface\n" 201 | "\t\t\t\tby name or by number\n"); 202 | fprintf(stderr, 203 | " -U --upload \t\tRead firmware from device into \n" 204 | " -D --download \t\tWrite firmware from into device\n" 205 | " -R --reset\t\t\tReset device once we're finished\n"); 206 | exit(EX_USAGE); 207 | } 208 | 209 | static void print_version(void) 210 | { 211 | printf(PACKAGE_STRING "\n\n"); 212 | printf("Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.\n" 213 | "Copyright 2010-2014 Tormod Volden and Stefan Schmidt\n" 214 | "Copyright 2016 Intel Corporation.\n" 215 | "This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n"); 216 | } 217 | 218 | static struct option opts[] = { 219 | { "help", 0, 0, 'h' }, 220 | { "version", 0, 0, 'V' }, 221 | { "verbose", 0, 0, 'v' }, 222 | { "list", 0, 0, 'l' }, 223 | { "path", 1, 0, 'p' }, 224 | { "altsetting", 1, 0, 'a' }, 225 | { "alt", 1, 0, 'a' }, 226 | { "transfer-size", 1, 0, 't' }, 227 | { "upload", 1, 0, 'U' }, 228 | { "download", 1, 0, 'D' }, 229 | { "reset", 0, 0, 'R' }, 230 | { "speed", 1, 0, 's'}, 231 | { 0, 0, 0, 0 } 232 | }; 233 | 234 | const char * short_opts = "hVvp:a:t:U:D:Rs:"; 235 | 236 | #else /* USE_QDA */ 237 | 238 | static void help(void) 239 | { 240 | fprintf(stderr, "Usage: dfu-util [options] ...\n" 241 | " -h --help\t\t\tPrint this help message\n" 242 | " -V --version\t\t\tPrint the version number\n" 243 | " -v --verbose\t\t\tPrint verbose debug statements\n" 244 | " -l --list\t\t\tList currently attached DFU capable devices\n"); 245 | fprintf(stderr, " -e --detach\t\t\tDetach currently attached DFU capable devices\n" 246 | " -E --detach-delay seconds\tTime to wait before reopening a device after detach\n" 247 | " -d --device :[,:]\n" 248 | "\t\t\t\tSpecify Vendor/Product ID(s) of DFU device\n" 249 | " -p --path \tSpecify path to DFU device\n" 250 | " -c --cfg \t\tSpecify the Configuration of DFU device\n" 251 | " -i --intf \t\tSpecify the DFU Interface number\n" 252 | " -S --serial [,]\n" 253 | "\t\t\t\tSpecify Serial String of DFU device\n" 254 | " -a --alt \t\tSpecify the Altsetting of the DFU Interface\n" 255 | "\t\t\t\tby name or by number\n"); 256 | fprintf(stderr, " -t --transfer-size \tSpecify the number of bytes per USB Transfer\n" 257 | " -U --upload \t\tRead firmware from device into \n" 258 | " -Z --upload-size \tSpecify the expected upload size in bytes\n" 259 | " -D --download \t\tWrite firmware from into device\n" 260 | " -R --reset\t\t\tIssue USB Reset signalling once we're finished\n" 261 | " -s --dfuse-address
\tST DfuSe mode, specify target address for\n" 262 | "\t\t\t\traw file download or upload. Not applicable for\n" 263 | "\t\t\t\tDfuSe file (.dfu) downloads\n" 264 | ); 265 | exit(EX_USAGE); 266 | } 267 | 268 | static void print_version(void) 269 | { 270 | printf(PACKAGE_STRING "\n\n"); 271 | printf("Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.\n" 272 | "Copyright 2010-2014 Tormod Volden and Stefan Schmidt\n" 273 | "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" 274 | "Please report bugs to " PACKAGE_BUGREPORT "\n\n"); 275 | } 276 | 277 | static struct option opts[] = { 278 | { "help", 0, 0, 'h' }, 279 | { "version", 0, 0, 'V' }, 280 | { "verbose", 0, 0, 'v' }, 281 | { "list", 0, 0, 'l' }, 282 | { "detach", 0, 0, 'e' }, 283 | { "detach-delay", 1, 0, 'E' }, 284 | { "device", 1, 0, 'd' }, 285 | { "path", 1, 0, 'p' }, 286 | { "configuration", 1, 0, 'c' }, 287 | { "cfg", 1, 0, 'c' }, 288 | { "interface", 1, 0, 'i' }, 289 | { "intf", 1, 0, 'i' }, 290 | { "altsetting", 1, 0, 'a' }, 291 | { "alt", 1, 0, 'a' }, 292 | { "serial", 1, 0, 'S' }, 293 | { "transfer-size", 1, 0, 't' }, 294 | { "upload", 1, 0, 'U' }, 295 | { "upload-size", 1, 0, 'Z' }, 296 | { "download", 1, 0, 'D' }, 297 | { "reset", 0, 0, 'R' }, 298 | { "dfuse-address", 1, 0, 's' }, 299 | { 0, 0, 0, 0 } 300 | }; 301 | 302 | const char * short_opts = "hVvleE:d:p:c:i:a:S:t:U:D:Rs:Z:"; 303 | 304 | #endif /* USE_QDA */ 305 | 306 | int main(int argc, char **argv) 307 | { 308 | int expected_size = 0; 309 | unsigned int transfer_size = 0; 310 | enum mode mode = MODE_NONE; 311 | struct dfu_status status; 312 | #ifdef USE_QDA 313 | unsigned int transfer_speed = 115200; 314 | char * serial_device_path = NULL; 315 | #else 316 | libusb_context *ctx; 317 | #endif 318 | struct dfu_file file; 319 | char *end; 320 | int final_reset = 0; 321 | int ret; 322 | int dfuse_device = 0; 323 | int fd; 324 | const char *dfuse_options = NULL; 325 | #ifndef USE_QDA 326 | int detach_delay = 5; 327 | #endif 328 | uint16_t runtime_vendor; 329 | uint16_t runtime_product; 330 | 331 | memset(&file, 0, sizeof(file)); 332 | 333 | /* make sure all prints are flushed */ 334 | setvbuf(stdout, NULL, _IONBF, 0); 335 | 336 | while (1) { 337 | int c, option_index = 0; 338 | c = getopt_long(argc, argv, short_opts, opts, &option_index); 339 | if (c == -1) 340 | break; 341 | 342 | switch (c) { 343 | case 'h': 344 | help(); 345 | break; 346 | case 'V': 347 | mode = MODE_VERSION; 348 | break; 349 | case 'v': 350 | verbose++; 351 | break; 352 | case 'l': 353 | mode = MODE_LIST; 354 | break; 355 | case 'e': 356 | mode = MODE_DETACH; 357 | match_iface_alt_index = 0; 358 | match_iface_index = 0; 359 | break; 360 | #ifndef USE_QDA 361 | case 'E': 362 | detach_delay = atoi(optarg); 363 | break; 364 | #endif 365 | case 'd': 366 | parse_vendprod(optarg); 367 | break; 368 | case 'p': 369 | #ifdef USE_QDA 370 | serial_device_path = optarg; 371 | #else 372 | /* Parse device path */ 373 | ret = resolve_device_path(optarg); 374 | if (ret < 0) 375 | errx(EX_SOFTWARE, "Unable to parse '%s'", optarg); 376 | if (!ret) 377 | errx(EX_SOFTWARE, "Cannot find '%s'", optarg); 378 | #endif 379 | break; 380 | case 'c': 381 | /* Configuration */ 382 | #ifdef USE_QDA 383 | serial_device_path = optarg; 384 | #else 385 | match_config_index = atoi(optarg); 386 | #endif 387 | break; 388 | case 'i': 389 | /* Interface */ 390 | match_iface_index = atoi(optarg); 391 | break; 392 | case 'a': 393 | /* Interface Alternate Setting */ 394 | match_iface_alt_index = strtoul(optarg, &end, 0); 395 | if (*end) { 396 | match_iface_alt_name = optarg; 397 | match_iface_alt_index = -1; 398 | } 399 | break; 400 | case 'S': 401 | parse_serial(optarg); 402 | break; 403 | case 't': 404 | transfer_size = atoi(optarg); 405 | break; 406 | case 'U': 407 | mode = MODE_UPLOAD; 408 | file.name = optarg; 409 | break; 410 | case 'Z': 411 | expected_size = atoi(optarg); 412 | break; 413 | case 'D': 414 | mode = MODE_DOWNLOAD; 415 | file.name = optarg; 416 | break; 417 | case 'R': 418 | final_reset = 1; 419 | break; 420 | case 's': 421 | #ifdef USE_QDA 422 | transfer_speed = atoi(optarg); 423 | #else 424 | dfuse_options = optarg; 425 | #endif 426 | break; 427 | default: 428 | help(); 429 | break; 430 | } 431 | } 432 | 433 | print_version(); 434 | if (mode == MODE_VERSION) { 435 | exit(0); 436 | } 437 | 438 | if (mode == MODE_NONE) { 439 | fprintf(stderr, "You need to specify one of -D or -U\n"); 440 | help(); 441 | } 442 | 443 | if (match_config_index == 0) { 444 | /* Handle "-c 0" (unconfigured device) as don't care */ 445 | match_config_index = -1; 446 | } 447 | 448 | if (mode == MODE_DOWNLOAD) { 449 | dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); 450 | /* If the user didn't specify product and/or vendor IDs to match, 451 | * use any IDs from the file suffix for device matching */ 452 | if (match_vendor < 0 && file.idVendor != 0xffff) { 453 | match_vendor = file.idVendor; 454 | printf("Match vendor ID from file: %04x\n", match_vendor); 455 | } 456 | if (match_product < 0 && file.idProduct != 0xffff) { 457 | match_product = file.idProduct; 458 | printf("Match product ID from file: %04x\n", match_product); 459 | } 460 | } 461 | 462 | #ifdef USE_QDA 463 | qda_if_t root; 464 | dfu_root = (struct dfu_if *)&root; 465 | dfu_root->altsetting = match_iface_alt_index; 466 | 467 | qda_conf_t qda_conf; 468 | qda_conf.send = dfu_util_qda_send; 469 | qda_conf.receive = dfu_util_qda_receive; 470 | qda_conf.detach = serial_detach; 471 | qda_init(&qda_conf); 472 | 473 | /* open interface */ 474 | ret = serial_io_open(serial_device_path, 475 | transfer_speed); 476 | 477 | if (ret < 0) { 478 | errx(EX_IOERR, "Cannot open serial device."); 479 | } 480 | 481 | printf("Detaching device into DFU mode.\n"); 482 | if (qda_dfu_detach() < 0) { 483 | errx(EX_IOERR, "can't detach device."); 484 | } 485 | 486 | 487 | printf("Determining device capabilities.\n"); 488 | if (qda_get_dfu_desc(dfu_root) < 0) { 489 | errx(EX_IOERR, "can't read device capabilities."); 490 | } 491 | 492 | runtime_vendor = dfu_root->vendor; 493 | runtime_product = dfu_root->product; 494 | #else 495 | ret = libusb_init(&ctx); 496 | if (ret) 497 | errx(EX_IOERR, "unable to initialize libusb: %i", ret); 498 | 499 | if (verbose > 2) { 500 | libusb_set_debug(ctx, 255); 501 | } 502 | 503 | probe_devices(ctx); 504 | 505 | if (mode == MODE_LIST) { 506 | list_dfu_interfaces(); 507 | exit(0); 508 | } 509 | 510 | if (dfu_root == NULL) { 511 | errx(EX_IOERR, "No DFU capable USB device available"); 512 | } else if (dfu_root->next != NULL) { 513 | /* We cannot safely support more than one DFU capable device 514 | * with same vendor/product ID, since during DFU we need to do 515 | * a USB bus reset, after which the target device will get a 516 | * new address */ 517 | errx(EX_IOERR, "More than one DFU capable USB device found! " 518 | "Try `--list' and specify the serial number " 519 | "or disconnect all but one device\n"); 520 | } 521 | 522 | /* We have exactly one device. Its libusb_device is now in dfu_root->dev */ 523 | 524 | printf("Opening DFU capable USB device...\n"); 525 | ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); 526 | if (ret || !dfu_root->dev_handle) 527 | errx(EX_IOERR, "Cannot open device"); 528 | 529 | printf("ID %04x:%04x\n", dfu_root->vendor, dfu_root->product); 530 | 531 | printf("Run-time device DFU version %04x\n", 532 | libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); 533 | 534 | /* Transition from run-Time mode to DFU mode */ 535 | if (!(dfu_root->flags & DFU_IFF_DFU)) { 536 | int err; 537 | /* In the 'first round' during runtime mode, there can only be one 538 | * DFU Interface descriptor according to the DFU Spec. */ 539 | 540 | /* FIXME: check if the selected device really has only one */ 541 | 542 | runtime_vendor = dfu_root->vendor; 543 | runtime_product = dfu_root->product; 544 | 545 | printf("Claiming USB DFU Runtime Interface...\n"); 546 | if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { 547 | errx(EX_IOERR, "Cannot claim interface %d", 548 | dfu_root->interface); 549 | } 550 | 551 | if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, 0) < 0) { 552 | errx(EX_IOERR, "Cannot set alt interface zero"); 553 | } 554 | 555 | printf("Determining device status: "); 556 | 557 | err = dfu_get_status(dfu_root, &status); 558 | if (err == LIBUSB_ERROR_PIPE) { 559 | printf("Device does not implement get_status, assuming appIDLE\n"); 560 | status.bStatus = DFU_STATUS_OK; 561 | status.bwPollTimeout = 0; 562 | status.bState = DFU_STATE_appIDLE; 563 | status.iString = 0; 564 | } else if (err < 0) { 565 | errx(EX_IOERR, "error get_status"); 566 | } else { 567 | printf("state = %s, status = %d\n", 568 | dfu_state_to_string(status.bState), status.bStatus); 569 | } 570 | milli_sleep(status.bwPollTimeout); 571 | 572 | switch (status.bState) { 573 | case DFU_STATE_appIDLE: 574 | case DFU_STATE_appDETACH: 575 | printf("Device really in Runtime Mode, send DFU " 576 | "detach request...\n"); 577 | if (dfu_detach(dfu_root->dev_handle, 578 | dfu_root->interface, 1000) < 0) { 579 | warnx("error detaching"); 580 | } 581 | if (dfu_root->func_dfu.bmAttributes & USB_DFU_WILL_DETACH) { 582 | printf("Device will detach and reattach...\n"); 583 | } else { 584 | printf("Resetting USB...\n"); 585 | ret = libusb_reset_device(dfu_root->dev_handle); 586 | if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) 587 | errx(EX_IOERR, "error resetting " 588 | "after detach"); 589 | } 590 | break; 591 | case DFU_STATE_dfuERROR: 592 | printf("dfuERROR, clearing status\n"); 593 | if (dfu_clear_status(dfu_root->dev_handle, 594 | dfu_root->interface) < 0) { 595 | errx(EX_IOERR, "error clear_status"); 596 | } 597 | /* fall through */ 598 | default: 599 | warnx("WARNING: Runtime device already in DFU state ?!?"); 600 | libusb_release_interface(dfu_root->dev_handle, 601 | dfu_root->interface); 602 | goto dfustate; 603 | } 604 | libusb_release_interface(dfu_root->dev_handle, 605 | dfu_root->interface); 606 | libusb_close(dfu_root->dev_handle); 607 | dfu_root->dev_handle = NULL; 608 | 609 | if (mode == MODE_DETACH) { 610 | libusb_exit(ctx); 611 | exit(0); 612 | } 613 | 614 | /* keeping handles open might prevent re-enumeration */ 615 | disconnect_devices(); 616 | 617 | milli_sleep(detach_delay * 1000); 618 | 619 | /* Change match vendor and product to impossible values to force 620 | * only DFU mode matches in the following probe */ 621 | match_vendor = match_product = 0x10000; 622 | 623 | probe_devices(ctx); 624 | 625 | if (dfu_root == NULL) { 626 | errx(EX_IOERR, "Lost device after RESET?"); 627 | } else if (dfu_root->next != NULL) { 628 | errx(EX_IOERR, "More than one DFU capable USB device found! " 629 | "Try `--list' and specify the serial number " 630 | "or disconnect all but one device"); 631 | } 632 | 633 | /* Check for DFU mode device */ 634 | if (!(dfu_root->flags | DFU_IFF_DFU)) 635 | errx(EX_SOFTWARE, "Device is not in DFU mode"); 636 | 637 | printf("Opening DFU USB Device...\n"); 638 | ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); 639 | if (ret || !dfu_root->dev_handle) { 640 | errx(EX_IOERR, "Cannot open device"); 641 | } 642 | } else { 643 | /* we're already in DFU mode, so we can skip the detach/reset 644 | * procedure */ 645 | /* If a match vendor/product was specified, use that as the runtime 646 | * vendor/product, otherwise use the DFU mode vendor/product */ 647 | runtime_vendor = match_vendor < 0 ? dfu_root->vendor : match_vendor; 648 | runtime_product = match_product < 0 ? dfu_root->product : match_product; 649 | } 650 | 651 | dfustate: 652 | #if 0 653 | printf("Setting Configuration %u...\n", dfu_root->configuration); 654 | if (libusb_set_configuration(dfu_root->dev_handle, dfu_root->configuration) < 0) { 655 | errx(EX_IOERR, "Cannot set configuration"); 656 | } 657 | #endif 658 | printf("Claiming USB DFU Interface...\n"); 659 | if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { 660 | errx(EX_IOERR, "Cannot claim interface"); 661 | } 662 | #endif /* USE_QDA */ 663 | 664 | printf("Setting Alternate Setting #%d ...\n", dfu_root->altsetting); 665 | if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, dfu_root->altsetting) < 0) { 666 | errx(EX_IOERR, "Cannot set alternate interface"); 667 | } 668 | 669 | status_again: 670 | printf("Determining device status: "); 671 | if (dfu_get_status(dfu_root, &status ) < 0) { 672 | errx(EX_IOERR, "error get_status"); 673 | } 674 | printf("state = %s, status = %d\n", 675 | dfu_state_to_string(status.bState), status.bStatus); 676 | 677 | milli_sleep(status.bwPollTimeout); 678 | 679 | switch (status.bState) { 680 | case DFU_STATE_appIDLE: 681 | case DFU_STATE_appDETACH: 682 | errx(EX_IOERR, "Device still in Runtime Mode!"); 683 | break; 684 | case DFU_STATE_dfuERROR: 685 | printf("dfuERROR, clearing status\n"); 686 | if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) { 687 | errx(EX_IOERR, "error clear_status"); 688 | } 689 | goto status_again; 690 | break; 691 | case DFU_STATE_dfuDNLOAD_IDLE: 692 | case DFU_STATE_dfuUPLOAD_IDLE: 693 | printf("aborting previous incomplete transfer\n"); 694 | if (dfu_abort(dfu_root->dev_handle, dfu_root->interface) < 0) { 695 | errx(EX_IOERR, "can't send DFU_ABORT"); 696 | } 697 | goto status_again; 698 | break; 699 | case DFU_STATE_dfuIDLE: 700 | printf("dfuIDLE, continuing\n"); 701 | break; 702 | default: 703 | break; 704 | } 705 | 706 | /* TODO: change "USB" string in QDA mode */ 707 | if (DFU_STATUS_OK != status.bStatus ) { 708 | printf("WARNING: DFU Status: '%s'\n", 709 | dfu_status_to_string(status.bStatus)); 710 | /* Clear our status & try again. */ 711 | if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) 712 | errx(EX_IOERR, "USB communication error"); 713 | if (dfu_get_status(dfu_root, &status) < 0) 714 | errx(EX_IOERR, "USB communication error"); 715 | if (DFU_STATUS_OK != status.bStatus) 716 | errx(EX_SOFTWARE, "Status is not OK: %d", status.bStatus); 717 | 718 | milli_sleep(status.bwPollTimeout); 719 | } 720 | 721 | printf("DFU mode device DFU version %04x\n", 722 | libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); 723 | 724 | if (dfu_root->func_dfu.bcdDFUVersion == libusb_cpu_to_le16(0x11a)) 725 | dfuse_device = 1; 726 | 727 | /* If not overridden by the user */ 728 | if (!transfer_size) { 729 | transfer_size = libusb_le16_to_cpu( 730 | dfu_root->func_dfu.wTransferSize); 731 | if (transfer_size) { 732 | printf("Device returned transfer size %i\n", 733 | transfer_size); 734 | } else { 735 | errx(EX_IOERR, "Transfer size must be specified"); 736 | } 737 | } 738 | 739 | #ifdef HAVE_GETPAGESIZE 740 | /* autotools lie when cross-compiling for Windows using mingw32/64 */ 741 | #ifndef __MINGW32__ 742 | /* limitation of Linux usbdevio */ 743 | if ((int)transfer_size > getpagesize()) { 744 | transfer_size = getpagesize(); 745 | printf("Limited transfer size to %i\n", transfer_size); 746 | } 747 | #endif /* __MINGW32__ */ 748 | #endif /* HAVE_GETPAGESIZE */ 749 | 750 | if (transfer_size < dfu_root->bMaxPacketSize0) { 751 | transfer_size = dfu_root->bMaxPacketSize0; 752 | printf("Adjusted transfer size to %i\n", transfer_size); 753 | } 754 | 755 | switch (mode) { 756 | case MODE_UPLOAD: 757 | /* open for "exclusive" writing */ 758 | fd = open(file.name, O_WRONLY | O_BINARY | O_CREAT | O_EXCL | O_TRUNC, 0666); 759 | if (fd < 0) 760 | err(EX_IOERR, "Cannot open file %s for writing", file.name); 761 | 762 | if (dfuse_device || dfuse_options) { 763 | #ifndef USE_QDA 764 | if (dfuse_do_upload(dfu_root, transfer_size, fd, 765 | dfuse_options) < 0) 766 | #endif 767 | exit(1); 768 | } else { 769 | if (dfuload_do_upload(dfu_root, transfer_size, 770 | expected_size, fd) < 0) { 771 | exit(1); 772 | } 773 | } 774 | close(fd); 775 | break; 776 | 777 | case MODE_DOWNLOAD: 778 | if (((file.idVendor != 0xffff && file.idVendor != runtime_vendor) || 779 | (file.idProduct != 0xffff && file.idProduct != runtime_product)) && 780 | ((file.idVendor != 0xffff && file.idVendor != dfu_root->vendor) || 781 | (file.idProduct != 0xffff && file.idProduct != dfu_root->product))) { 782 | errx(EX_IOERR, "Error: File ID %04x:%04x does " 783 | "not match device (%04x:%04x or %04x:%04x)", 784 | file.idVendor, file.idProduct, 785 | runtime_vendor, runtime_product, 786 | dfu_root->vendor, dfu_root->product); 787 | } 788 | if (dfuse_device || dfuse_options || file.bcdDFU == 0x11a) { 789 | #ifndef USE_QDA 790 | if (dfuse_do_dnload(dfu_root, transfer_size, &file, 791 | dfuse_options) < 0) 792 | #endif 793 | exit(1); 794 | } else { 795 | if (dfuload_do_dnload(dfu_root, transfer_size, &file) < 0) 796 | exit(1); 797 | } 798 | break; 799 | case MODE_DETACH: 800 | if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { 801 | warnx("can't detach"); 802 | } 803 | break; 804 | default: 805 | errx(EX_IOERR, "Unsupported mode: %u", mode); 806 | break; 807 | } 808 | 809 | if (final_reset) { 810 | #ifdef USE_QDA 811 | printf("Resetting device to switch back to runtime mode\n"); 812 | #else 813 | if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { 814 | /* Even if detach failed, just carry on to leave the 815 | device in a known state */ 816 | warnx("can't detach"); 817 | } 818 | printf("Resetting USB to switch back to runtime mode\n"); 819 | #endif 820 | ret = libusb_reset_device(dfu_root->dev_handle); 821 | if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) { 822 | errx(EX_IOERR, "error resetting after download"); 823 | } 824 | } 825 | 826 | #ifdef USE_QDA 827 | serial_io_close(); 828 | #else 829 | libusb_close(dfu_root->dev_handle); 830 | dfu_root->dev_handle = NULL; 831 | libusb_exit(ctx); 832 | #endif 833 | 834 | return (0); 835 | } 836 | -------------------------------------------------------------------------------- /src/portable.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PORTABLE_H 3 | #define PORTABLE_H 4 | 5 | #ifdef HAVE_CONFIG_H 6 | # include "config.h" 7 | #else 8 | # define PACKAGE "dfu-util" 9 | # define PACKAGE_VERSION "0.8-msvc" 10 | # define PACKAGE_STRING "dfu-util 0.8-msvc" 11 | # define PACKAGE_BUGREPORT "dfu-util@lists.gnumonks.org" 12 | #endif /* HAVE_CONFIG_H */ 13 | 14 | #ifdef HAVE_FTRUNCATE 15 | # include 16 | #else 17 | # include 18 | #endif /* HAVE_FTRUNCATE */ 19 | 20 | #ifdef HAVE_NANOSLEEP 21 | # include 22 | # define milli_sleep(msec) do {\ 23 | if (msec) {\ 24 | struct timespec nanosleepDelay = { (msec) / 1000, ((msec) % 1000) * 1000000 };\ 25 | nanosleep(&nanosleepDelay, NULL);\ 26 | } } while (0) 27 | #elif defined HAVE_WINDOWS_H 28 | # define milli_sleep(msec) do {\ 29 | if (msec) {\ 30 | Sleep(msec);\ 31 | } } while (0) 32 | #else 33 | # error "Can't get no sleep! Please report" 34 | #endif /* HAVE_NANOSLEEP */ 35 | 36 | #ifdef HAVE_ERR 37 | # include 38 | #else 39 | # include 40 | # include 41 | # define warnx(...) do {\ 42 | fprintf(stderr, __VA_ARGS__);\ 43 | fprintf(stderr, "\n"); } while (0) 44 | # define errx(eval, ...) do {\ 45 | warnx(__VA_ARGS__);\ 46 | exit(eval); } while (0) 47 | # define warn(...) do {\ 48 | fprintf(stderr, "%s: ", strerror(errno));\ 49 | warnx(__VA_ARGS__); } while (0) 50 | # define err(eval, ...) do {\ 51 | warn(__VA_ARGS__);\ 52 | exit(eval); } while (0) 53 | #endif /* HAVE_ERR */ 54 | 55 | #ifdef HAVE_SYSEXITS_H 56 | # include 57 | #else 58 | # define EX_OK 0 /* successful termination */ 59 | # define EX_USAGE 64 /* command line usage error */ 60 | # define EX_SOFTWARE 70 /* internal software error */ 61 | # define EX_IOERR 74 /* input/output error */ 62 | #endif /* HAVE_SYSEXITS_H */ 63 | 64 | #ifndef O_BINARY 65 | # define O_BINARY 0 66 | #endif 67 | 68 | #ifndef off_t 69 | # define off_t long int 70 | #endif 71 | 72 | #endif /* PORTABLE_H */ 73 | -------------------------------------------------------------------------------- /src/qda/qda.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #include "qda_packets.h" 20 | #include 21 | #include 22 | #include 23 | #include "qda.h" 24 | #include "usb_dfu.h" 25 | 26 | /* For x86 hosts we do not have to do any conversion */ 27 | #define htoq32(val) (val) 28 | #define htoq16(val) (val) 29 | 30 | #define qtoh32(val) (val) 31 | #define qtoh16(val) (val) 32 | 33 | #define DEBUG_MSG (0) 34 | 35 | #if DEBUG_MSG 36 | #define printd(...) printf(__VA_ARGS__) 37 | #else 38 | #define printd(...) 39 | #endif 40 | 41 | #define FAIL_IF(statement) do { \ 42 | if(statement) { \ 43 | printd("[FAIL]\n"); \ 44 | return -1; \ 45 | } \ 46 | } while(0) \ 47 | 48 | qda_conf_t *qda_conf; 49 | 50 | /* NOTE: make the size of the payload dynamic */ 51 | static uint8_t qda_buf[8192]; 52 | 53 | int qda_init(qda_conf_t *conf) 54 | { 55 | qda_conf = conf; 56 | return 0; 57 | } 58 | 59 | int qda_reset() 60 | { 61 | printd("qda_reset...\t"); 62 | int rc; 63 | qda_pkt_t *req, *resp; 64 | 65 | req = (qda_pkt_t *)qda_buf; 66 | req->type = htoq32(QDA_PKT_RESET); 67 | 68 | rc = qda_conf->send((uint8_t *)req, sizeof(req->type)); 69 | FAIL_IF(rc < 0); 70 | rc = qda_conf->receive(qda_buf, sizeof(qda_buf)); 71 | FAIL_IF(rc >= (int) sizeof(qda_buf)); 72 | 73 | resp = (qda_pkt_t *)qda_buf; 74 | FAIL_IF(resp->type != htoq32(QDA_PKT_ACK)); 75 | printd("[DONE]\n"); 76 | return 0; 77 | } 78 | 79 | int qda_get_dev_desc(qda_if_t *dif) 80 | { 81 | printd("qda_get_dev_desc...\t"); 82 | int rc; 83 | qda_pkt_t *req, *resp; 84 | dev_desc_resp_payload_t *pl; 85 | 86 | req = (qda_pkt_t *)qda_buf; 87 | req->type = htoq32(QDA_PKT_DEV_DESC_REQ); 88 | 89 | rc = qda_conf->send((uint8_t *)req, sizeof(req->type)); 90 | FAIL_IF(rc < 0); 91 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 92 | 93 | resp = (qda_pkt_t *)qda_buf; 94 | FAIL_IF(resp->type != htoq32(QDA_PKT_DEV_DESC_RESP)); 95 | pl = (dev_desc_resp_payload_t *)resp->payload; 96 | 97 | dif->product = qtoh16(pl->id_product); 98 | dif->vendor = qtoh16(pl->id_vendor); 99 | dif->bcdDevice = qtoh16(pl->bcd_device); 100 | 101 | printd("[DONE]\n"); 102 | printd("\tvendId: 0x%04x\n", dif->vendor); 103 | printd("\tprodId: 0x%04x\n", dif->product); 104 | printd("\tbcd: 0x%04x\n", dif->bcdDevice); 105 | 106 | return 0; 107 | } 108 | 109 | int qda_get_dfu_desc(qda_if_t *dif) 110 | { 111 | printd("qda_get_dfu_desc...\t"); 112 | int rc; 113 | qda_pkt_t *req, *resp; 114 | dfu_desc_resp_payload_t *pl; 115 | 116 | req = (qda_pkt_t *)qda_buf; 117 | req->type = htoq32(QDA_PKT_DFU_DESC_REQ); 118 | 119 | rc = qda_conf->send((uint8_t *)req, sizeof(req->type)); 120 | FAIL_IF(rc < 0); 121 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 122 | 123 | resp = (qda_pkt_t *)qda_buf; 124 | FAIL_IF(resp->type != htoq32(QDA_PKT_DFU_DESC_RESP)); 125 | pl = (dfu_desc_resp_payload_t *)resp->payload; 126 | 127 | /* TODO: save alt setting number, attributes and timeout 128 | desc->num_alt_settings = pl->num_alt_settings; 129 | desc->bm_attributes = pl->bm_attributes; 130 | desc->detach_timeout = qtoh16(pl->detach_timeout); 131 | */ 132 | 133 | dif->func_dfu.wTransferSize = qtoh16(pl->transfer_size); 134 | dif->func_dfu.bcdDFUVersion = qtoh16(pl->bcd_dfu_ver); 135 | printd("\twTransferSize: %d\n", dif->func_dfu.wTransferSize); 136 | printd("\tbcdDFUversion: 0x%04x\n", dif->func_dfu.bcdDFUVersion); 137 | 138 | printd("[DONE]\n"); 139 | return 0; 140 | } 141 | 142 | int qda_set_alt_setting(uint8_t alt) 143 | { 144 | printd("qda_set_dfu_alt_setting...\t"); 145 | int rc; 146 | qda_pkt_t *req, *resp; 147 | set_alt_setting_payload_t *pl; 148 | 149 | req = (qda_pkt_t *)qda_buf; 150 | req->type = htoq32(QDA_PKT_DFU_SET_ALT_SETTING); 151 | pl = (set_alt_setting_payload_t *)req->payload; 152 | pl->alt_setting = alt; 153 | 154 | rc = qda_conf->send((uint8_t *)req, sizeof(req->type) + sizeof(*pl)); 155 | FAIL_IF(rc < 0); 156 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 157 | 158 | resp = (qda_pkt_t *)qda_buf; 159 | FAIL_IF(resp->type != htoq32(QDA_PKT_ACK)); 160 | printd("[DONE]\n"); 161 | return 0; 162 | } 163 | 164 | int qda_dfu_detach(void) 165 | { 166 | printd("qda_dfu_detach...\t"); 167 | FAIL_IF(qda_conf->detach() < 0); 168 | printd("[DONE]\n"); 169 | return 0; 170 | } 171 | 172 | int qda_dfu_download(uint16_t len, uint16_t transaction, const uint8_t *data) 173 | { 174 | printd("qda_dfu_dnload (len=%d)\nstarting...\t\t", len); 175 | int rc; 176 | qda_pkt_t *req, *resp; 177 | dnload_req_payload_t *pl; 178 | 179 | req = (qda_pkt_t *)qda_buf; 180 | req->type = htoq32(QDA_PKT_DFU_DNLOAD_REQ); 181 | pl = (dnload_req_payload_t *)req->payload; 182 | pl->data_len = len; 183 | pl->block_num = transaction; 184 | if (len > (sizeof(qda_buf) - sizeof(*req) - sizeof(*pl))) { 185 | return -1; 186 | } 187 | memcpy(pl->data, data, len); 188 | 189 | rc = qda_conf->send((uint8_t *)req, 190 | sizeof(*req) + sizeof(*pl) + pl->data_len); 191 | FAIL_IF(rc < 0); 192 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 193 | 194 | resp = (qda_pkt_t *)qda_buf; 195 | FAIL_IF(resp->type != htoq32(QDA_PKT_ACK)); 196 | 197 | printd("[DONE]\n"); 198 | return 0; 199 | } 200 | 201 | int qda_dfu_upload(uint16_t len, uint16_t transaction, uint8_t *data) 202 | { 203 | printd("qda_dfu_upload...\t"); 204 | int rc; 205 | qda_pkt_t *req, *resp; 206 | upload_req_payload_t *pl_req; 207 | upload_resp_payload_t *pl_resp; 208 | int retv; 209 | 210 | req = (qda_pkt_t *)qda_buf; 211 | req->type = htoq32(QDA_PKT_DFU_UPLOAD_REQ); 212 | pl_req = (upload_req_payload_t *)req->payload; 213 | pl_req->max_data_len = len; 214 | pl_req->block_num = transaction; 215 | 216 | rc = qda_conf->send((uint8_t *)req, sizeof(*req) + sizeof(*pl_req)); 217 | FAIL_IF(rc < 0); 218 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 219 | 220 | resp = (qda_pkt_t *)qda_buf; 221 | FAIL_IF(resp->type != htoq32(QDA_PKT_DFU_UPLOAD_RESP)); 222 | pl_resp = (upload_resp_payload_t *)resp->payload; 223 | retv = qtoh16(pl_resp->data_len); 224 | FAIL_IF(retv > len); 225 | memcpy(data, pl_resp->data, retv); 226 | 227 | printd("[DONE]\n"); 228 | printd("\tlen: %d\t", retv); 229 | return retv; 230 | } 231 | 232 | int qda_dfu_getstatus(dfu_status_t *status) 233 | { 234 | printd("qda_dfu_getstatus...\t"); 235 | int rc; 236 | qda_pkt_t *req, *resp; 237 | get_status_resp_payload_t *pl; 238 | req = (qda_pkt_t *)qda_buf; 239 | req->type = htoq32(QDA_PKT_DFU_GETSTATUS_REQ); 240 | 241 | rc = qda_conf->send((uint8_t *)req, sizeof(*req)); 242 | FAIL_IF(rc < 0); 243 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 244 | 245 | resp = (qda_pkt_t *)qda_buf; 246 | FAIL_IF(resp->type != htoq32(QDA_PKT_DFU_GETSTATUS_RESP)); 247 | pl = (get_status_resp_payload_t *)resp->payload; 248 | status->bState = pl->state; 249 | status->bStatus = pl->status; 250 | status->bwPollTimeout = qtoh32(pl->poll_timeout); 251 | 252 | printd("[DONE]\n"); 253 | return 0; 254 | } 255 | 256 | int qda_dfu_clrstatus() 257 | { 258 | printd("qda_dfu_clrstatus...\t"); 259 | int rc; 260 | qda_pkt_t *req, *resp; 261 | req = (qda_pkt_t *)qda_buf; 262 | req->type = htoq32(QDA_PKT_DFU_CLRSTATUS); 263 | 264 | rc = qda_conf->send((uint8_t *)req, sizeof(*req)); 265 | FAIL_IF(rc < 0); 266 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 267 | 268 | resp = (qda_pkt_t *)qda_buf; 269 | FAIL_IF(resp->type != htoq32(QDA_PKT_ACK)); 270 | 271 | printd("[DONE]\n"); 272 | return 0; 273 | } 274 | 275 | int qda_dfu_getstate() 276 | { 277 | printd("qda_dfu_getstate...\t"); 278 | int rc; 279 | qda_pkt_t *req, *resp; 280 | get_state_resp_payload_t *pl; 281 | req = (qda_pkt_t *)qda_buf; 282 | req->type = htoq32(QDA_PKT_DFU_GETSTATE_REQ); 283 | 284 | rc = qda_conf->send((uint8_t *)req, sizeof(*req)); 285 | FAIL_IF(rc < 0); 286 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 287 | 288 | resp = (qda_pkt_t *)qda_buf; 289 | FAIL_IF(resp->type != htoq32(QDA_PKT_DFU_GETSTATE_RESP)); 290 | pl = (get_state_resp_payload_t *)resp->payload; 291 | 292 | printd("[DONE] (%s)\n", dfu_state_to_string(pl->state)); 293 | return pl->state; 294 | } 295 | 296 | int qda_dfu_abort() 297 | { 298 | printd("qda_dfu_abort...\t\t"); 299 | int rc; 300 | qda_pkt_t *req, *resp; 301 | req = (qda_pkt_t *)qda_buf; 302 | req->type = htoq32(QDA_PKT_DFU_ABORT); 303 | 304 | rc = qda_conf->send((uint8_t *)req, sizeof(*req)); 305 | FAIL_IF(rc < 0); 306 | qda_conf->receive(qda_buf, sizeof(qda_buf)); 307 | 308 | resp = (qda_pkt_t *)qda_buf; 309 | FAIL_IF(resp->type != htoq32(QDA_PKT_ACK)); 310 | 311 | printd("[DONE]\n"); 312 | return 0; 313 | } 314 | 315 | /* The following dfu_status functions are copied from dfu.c */ 316 | /* TODO: consider reusing the existing functions from dfu.c */ 317 | 318 | /* Chapter 6.1.2 */ 319 | static const char *dfu_status_names[] = { 320 | /* DFU_STATUS_OK */ 321 | "No error condition is present", 322 | /* DFU_STATUS_errTARGET */ 323 | "File is not targeted for use by this device", 324 | /* DFU_STATUS_errFILE */ 325 | "File is for this device but fails some vendor-specific test", 326 | /* DFU_STATUS_errWRITE */ 327 | "Device is unable to write memory", 328 | /* DFU_STATUS_errERASE */ 329 | "Memory erase function failed", 330 | /* DFU_STATUS_errCHECK_ERASED */ 331 | "Memory erase check failed", 332 | /* DFU_STATUS_errPROG */ 333 | "Program memory function failed", 334 | /* DFU_STATUS_errVERIFY */ 335 | "Programmed memory failed verification", 336 | /* DFU_STATUS_errADDRESS */ 337 | "Cannot program memory due to received address that is out of range", 338 | /* DFU_STATUS_errNOTDONE */ 339 | "Received DFU_DNLOAD with wLength = 0, but device does not think that it " 340 | "has all data yet", 341 | /* DFU_STATUS_errFIRMWARE */ 342 | "Device's firmware is corrupt. It cannot return to run-time (non-DFU) " 343 | "operations", 344 | /* DFU_STATUS_errVENDOR */ 345 | "iString indicates a vendor specific error", 346 | /* DFU_STATUS_errUSBR */ 347 | "Device detected unexpected USB reset signalling", 348 | /* DFU_STATUS_errPOR */ 349 | "Device detected unexpected power on reset", 350 | /* DFU_STATUS_errUNKNOWN */ 351 | "Something went wrong, but the device does not know what it was", 352 | /* DFU_STATUS_errSTALLEDPKT */ 353 | "Device stalled an unexpected request"}; 354 | 355 | static const char *dfu_state_names[] = { 356 | /* DFU_STATE_appIDLE */ 357 | "appIDLE", 358 | /* DFU_STATE_appDETACH */ 359 | "appDETACH", 360 | /* DFU_STATE_dfuIDLE */ 361 | "dfuIDLE", 362 | /* DFU_STATE_dfuDNLOAD_SYNC */ 363 | "dfuDNLOAD-SYNC", 364 | /* DFU_STATE_dfuDNBUSY */ 365 | "dfuDNBUSY", 366 | /* DFU_STATE_dfuDNLOAD_IDLE */ 367 | "dfuDNLOAD-IDLE", 368 | /* DFU_STATE_dfuMANIFEST_SYNC */ 369 | "dfuMANIFEST-SYNC", 370 | /* DFU_STATE_dfuMANIFEST */ 371 | "dfuMANIFEST", 372 | /* DFU_STATE_dfuMANIFEST_WAIT_RST */ 373 | "dfuMANIFEST-WAIT-RESET", 374 | /* DFU_STATE_dfuUPLOAD_IDLE */ 375 | "dfuUPLOAD-IDLE", 376 | /* DFU_STATE_dfuERROR */ 377 | "dfuERROR", 378 | }; 379 | 380 | const char *qda_dfu_state_to_string(int state) 381 | { 382 | if (state > DFU_STATE_dfuERROR) 383 | return "INVALID STATE ID"; 384 | return dfu_state_names[state]; 385 | } 386 | 387 | const char *qda_dfu_status_to_string(int status) 388 | { 389 | if (status > DFU_STATUS_errSTALLEDPKT) 390 | return "INVALID"; 391 | return dfu_status_names[status]; 392 | } 393 | -------------------------------------------------------------------------------- /src/qda/qda.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #ifndef _QDA_H_ 20 | #define _QDA_H_ 21 | 22 | #include 23 | #include "usb_dfu.h" 24 | 25 | #include "qda_packets.h" 26 | 27 | /* Note: dfu_status and dfu_if are copied from dfu.h */ 28 | 29 | /** 30 | * DFU status structure 31 | */ 32 | typedef struct dfu_status { 33 | unsigned char bStatus; 34 | unsigned int bwPollTimeout; 35 | unsigned char bState; 36 | unsigned char iString; 37 | } dfu_status_t; 38 | 39 | /** 40 | * QDA interface structure 41 | */ 42 | typedef struct dfu_if { 43 | struct usb_dfu_func_descriptor func_dfu; 44 | uint16_t vendor; 45 | uint16_t product; 46 | uint16_t bcdDevice; 47 | uint8_t interface; 48 | uint8_t altsetting; 49 | uint8_t bMaxPacketSize0; 50 | } qda_if_t; 51 | 52 | /** 53 | * QDA Configuration structure. 54 | */ 55 | typedef struct qda_conf_s { 56 | /** 57 | * QDA send callback. 58 | * 59 | * @param[in] data Data to be sent. 60 | * @param[in] len Length of data to be sent. 61 | * 62 | * @return Error Status 63 | * @retval 0 Success 64 | * @retval -1 Error 65 | */ 66 | int (*send)(uint8_t *data, size_t len); 67 | 68 | /** 69 | * QDA receive callback. 70 | * 71 | * @param[out] data Data buffer for received bytes. 72 | * @param[in] len Maximum allocated bytes that can be received. 73 | * 74 | * @return Length of received data. 75 | */ 76 | size_t (*receive)(uint8_t *data, size_t len); 77 | 78 | /** 79 | * QDA detach callback. 80 | * 81 | * @return Error Status 82 | * @retval 0 Success 83 | * @retval -1 Error 84 | **/ 85 | int (*detach)(void); 86 | } qda_conf_t; 87 | 88 | /** 89 | * Init QDA and set configuration. 90 | * 91 | * @paqram[in] conf A QDA configuration structure. 92 | * 93 | * @return Error Status 94 | * @retval 0 Success 95 | * @retval -1 Error 96 | */ 97 | int qda_init(qda_conf_t *conf); 98 | 99 | /** 100 | * Reset QDA device. 101 | * 102 | * @return Error Status 103 | * @retval 0 Success 104 | * @retval -1 Error 105 | */ 106 | int qda_reset(); 107 | 108 | /** 109 | * Get device description. 110 | * 111 | * @param[out] dif Target structure to update configuration values. 112 | * 113 | * @return Error Status 114 | * @retval 0 Success 115 | * @retval -1 Error 116 | */ 117 | int qda_get_dev_desc(qda_if_t *dif); 118 | 119 | /** 120 | * Get DFU description. 121 | * 122 | * @param[out] dif Target structure to update configuration values. 123 | * 124 | * @return Error Status 125 | * @retval 0 Success 126 | * @retval -1 Error 127 | */ 128 | int qda_get_dfu_desc(qda_if_t *dif); 129 | 130 | /** 131 | * Set alternate setting. 132 | * 133 | * @param[in] alt Alternate setting to be set. 134 | * 135 | * @return Error Status 136 | * @retval 0 Success 137 | * @retval -1 Error 138 | */ 139 | int qda_set_alt_setting(uint8_t alt); 140 | 141 | /** 142 | * Detach device and enter DFU mode. 143 | * 144 | * @return Error Status 145 | * @retval 0 Success 146 | * @retval -1 Error 147 | */ 148 | int qda_dfu_detach(void); 149 | 150 | /** 151 | * Perform a DFU download. 152 | * 153 | * Write firmware data to the target device. 154 | * 155 | * @param[in] len Length of block. 156 | * @param[in] transaction Block number. 157 | * @param[in] data Pointer to data. 158 | * 159 | * @return Error Status 160 | * @retval 0 Success 161 | * @retval -1 Error 162 | */ 163 | int qda_dfu_download(uint16_t len, uint16_t transaction, const uint8_t *data); 164 | 165 | /** 166 | * Perform a DFU upload. 167 | * 168 | * Read firmware data from target device. 169 | * 170 | * @param[in] len Length of block. 171 | * @param[in] transaction Block number. 172 | * @param[out] data Pointer to data. 173 | * 174 | * @return Length or Error Status 175 | * @retval >0 Length of downloaded data. 176 | * @retval 0 Success 177 | * @retval -1 Error 178 | */ 179 | int qda_dfu_upload(uint16_t len, uint16_t transaction, uint8_t *data); 180 | 181 | /** 182 | * Request device's DFU status. 183 | * 184 | * @param[out] status The current DFU status. 185 | * 186 | * @return Error Status 187 | * @retval 0 Success 188 | * @retval -1 Error 189 | */ 190 | int qda_dfu_getstatus(dfu_status_t *status); 191 | 192 | /** 193 | * Clear device's DFU status. 194 | * 195 | * @return Error Status 196 | * @retval 0 Success 197 | * @retval -1 Error 198 | */ 199 | int qda_dfu_clrstatus(); 200 | 201 | /** 202 | * Request device's DFU state. 203 | * 204 | * @return Success or error State 205 | * @retval >=0 DFU State 206 | * @retval -1 Error 207 | */ 208 | int qda_dfu_getstate(); 209 | 210 | /** 211 | * Send DFU abort message to device. 212 | * 213 | * @return Error Status 214 | * @retval 0 Success 215 | * @retval -1 Error 216 | */ 217 | int qda_dfu_abort(); 218 | 219 | /** 220 | * Retrieve state string. 221 | * 222 | * Return state string of a valid DFU state. 223 | * 224 | * @param[in] state The DFU state number. 225 | * 226 | * @return String of the requested state number. 227 | */ 228 | const char *qda_dfu_state_to_string(int state); 229 | 230 | /** 231 | * Retrieve status string. 232 | * 233 | * Return status string of a valid DFU status. 234 | * 235 | * @param[in] status The DFU status number. 236 | * 237 | * @return String of the requested status number. 238 | */ 239 | const char *qda_dfu_status_to_string(int status); 240 | 241 | /* DFU SHIM */ 242 | #define dfu_detach(dev, interface, timeout) qda_dfu_detach() 243 | /* 244 | * In the following two macros we use the 'comma' operator and we cast 245 | * 'interface' to void to mark it as used and avoid compilation warnings about 246 | * unused variables. 247 | */ 248 | #define dfu_download(dev, interface, len, trans, data) \ 249 | ((void)interface, qda_dfu_download(len, trans, data)) 250 | #define dfu_upload(dev, interface, len, trans, data) \ 251 | ((void)interface, qda_dfu_upload(len, trans, data)) 252 | 253 | #define dfu_get_status(dif, status) qda_dfu_getstatus(status) 254 | #define dfu_clear_status(dev, interface) qda_dfu_getstate() 255 | #define dfu_abort(dev, interface) qda_dfu_abort() 256 | #define dfu_state_to_string(state) qda_dfu_state_to_string(state) 257 | #define dfu_status_to_string(status) qda_dfu_status_to_string(status) 258 | 259 | /* LIBUSB SHIM */ 260 | #define libusb_set_interface_alt_setting(handle, interface, alt) \ 261 | qda_set_alt_setting(alt) 262 | #define libusb_reset_device(ndle) qda_reset() 263 | 264 | static inline uint16_t libusb_cpu_to_le16(const uint16_t x) 265 | { 266 | union { 267 | uint8_t b8[2]; 268 | uint16_t b16; 269 | } _tmp; 270 | _tmp.b8[1] = x >> 8; 271 | _tmp.b8[0] = x & 0xff; 272 | return _tmp.b16; 273 | } 274 | #define libusb_le16_to_cpu libusb_cpu_to_le16 275 | 276 | #define LIBUSB_ERROR_NOT_FOUND (-5) 277 | 278 | #endif 279 | -------------------------------------------------------------------------------- /src/qda/qda_packets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #ifndef __QDA_PACKETS_H__ 20 | #define __QDA_PACKETS_H__ 21 | 22 | #include 23 | 24 | #define __ATTR_PACKED__ __attribute__((__packed__)) 25 | 26 | /** 27 | * QDA packet types 28 | */ 29 | typedef enum { 30 | /* Host requests */ 31 | QDA_PKT_RESET = 0x4D550000, 32 | QDA_PKT_DEV_DESC_REQ = 0x4D550005, 33 | QDA_PKT_DFU_DESC_REQ = 0x4D5501FF, 34 | QDA_PKT_DFU_SET_ALT_SETTING = 0x4D5501FE, 35 | QDA_PKT_DFU_DETACH = 0x4D550100, 36 | QDA_PKT_DFU_DNLOAD_REQ = 0x4D550101, 37 | QDA_PKT_DFU_UPLOAD_REQ = 0x4D550102, 38 | QDA_PKT_DFU_GETSTATUS_REQ = 0x4D550103, 39 | QDA_PKT_DFU_CLRSTATUS = 0x4D550104, 40 | QDA_PKT_DFU_GETSTATE_REQ = 0x4D550105, 41 | QDA_PKT_DFU_ABORT = 0x4D550106, 42 | /* Device responses */ 43 | QDA_PKT_ATTACH = 0x4D558001, 44 | QDA_PKT_DETACH = 0x4D558002, 45 | QDA_PKT_ACK = 0x4D558003, 46 | QDA_PKT_STALL = 0x4D558004, 47 | QDA_PKT_DEV_DESC_RESP = 0x4D558005, 48 | QDA_PKT_DFU_DESC_RESP = 0x4D5581FF, 49 | QDA_PKT_DFU_UPLOAD_RESP = 0x4D558102, 50 | QDA_PKT_DFU_GETSTATUS_RESP = 0x4D558103, 51 | QDA_PKT_DFU_GETSTATE_RESP = 0x4D558105, 52 | 53 | } qda_pkt_type_t; 54 | 55 | /** 56 | * Generic QDA Packet structure 57 | */ 58 | typedef struct __ATTR_PACKED__ { 59 | uint32_t type; 60 | uint8_t payload[]; 61 | } qda_pkt_t; 62 | 63 | /** 64 | * QDA_DNLOAD_REQ payload structure 65 | */ 66 | typedef struct __ATTR_PACKED__ { 67 | uint16_t data_len; 68 | uint16_t block_num; 69 | uint8_t data[]; 70 | } dnload_req_payload_t; 71 | 72 | /** 73 | * QDA_UPLOAD_REQ payload structure 74 | */ 75 | typedef struct __ATTR_PACKED__ { 76 | uint16_t max_data_len; 77 | uint16_t block_num; 78 | } upload_req_payload_t; 79 | 80 | /** 81 | * QDA_USB_SET_ALT_SETTING payload structure 82 | */ 83 | typedef struct __ATTR_PACKED__ { 84 | uint8_t alt_setting; 85 | } set_alt_setting_payload_t; 86 | 87 | /** 88 | * QDA_UPLOAD_RESP payload structure 89 | */ 90 | typedef struct __ATTR_PACKED__ { 91 | uint16_t data_len; 92 | uint8_t data[]; 93 | } upload_resp_payload_t; 94 | 95 | /** 96 | * QDA_USB_DEV_DESC_RESP payload structure 97 | */ 98 | typedef struct __ATTR_PACKED__ { 99 | uint16_t id_vendor; 100 | uint16_t id_product; 101 | uint16_t bcd_device; 102 | } dev_desc_resp_payload_t; 103 | 104 | /** 105 | * QDA_DFU_DESC_RESP payload structure 106 | */ 107 | typedef struct __ATTR_PACKED__ { 108 | uint8_t num_alt_settings; 109 | uint8_t bm_attributes; 110 | uint16_t detach_timeout; 111 | uint16_t transfer_size; 112 | uint16_t bcd_dfu_ver; 113 | } dfu_desc_resp_payload_t; 114 | 115 | /** 116 | * QDA_GET_STATUS_RESP payload structure 117 | */ 118 | typedef struct __ATTR_PACKED__ { 119 | /* 120 | * As per the DFU spec, poll_timeout is 3-byte integer, but QDA stores 121 | * it in a 4-byte field for simplicity 122 | */ 123 | uint32_t poll_timeout; 124 | uint8_t status; 125 | uint8_t state; 126 | } get_status_resp_payload_t; 127 | 128 | /** 129 | * QDA_GET_STATE_RESP payload structure 130 | */ 131 | typedef struct __ATTR_PACKED__ { 132 | uint8_t state; 133 | } get_state_resp_payload_t; 134 | 135 | #endif /* __QDA_PACKETS_H__ */ 136 | -------------------------------------------------------------------------------- /src/qda/serial_io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "xmodem.h" 31 | 32 | static int serial_handle; 33 | static struct termios tio_initial; 34 | 35 | static void _signal_handler(int sig); 36 | 37 | void xmodem_putc(uint8_t *ch) 38 | { 39 | size_t size = write(serial_handle, ch, 1); 40 | (void)size; 41 | } 42 | 43 | /* 44 | * Get a character from the XMODEM I/O layer. 45 | * 46 | * This function must be blocking, but is also expected to timeout after a 47 | * certain amount of time. Moreover, in case of error, the function must not 48 | * set the output parameter (i.e., the pointed variable must remain unchanged). 49 | * 50 | * @param[out] ch A pointer to the variable where to store the read character. 51 | * In case of error, the current value of the pointed variable 52 | * is not modified. 53 | * 54 | * @return 0 on success, negative error code otherwise. 55 | * @retval -ETIMEDOUT in case of timeout. 56 | * @retval -EIO in case of I/O error. 57 | */ 58 | int xmodem_getc(uint8_t *ch) 59 | { 60 | ssize_t retv; 61 | 62 | retv = read(serial_handle, ch, 1); 63 | 64 | switch (retv) { 65 | case 1: 66 | /* We read one character as expected: success */ 67 | return 0; 68 | case 0: 69 | /* We read 0 characters: we timed out */ 70 | return -ETIMEDOUT; 71 | default: 72 | /* Error or unexpected value: generic I/O error */ 73 | return -EIO; 74 | 75 | } 76 | } 77 | 78 | int xmodem_set_timeout(int ms) 79 | { 80 | struct termios tio; 81 | if(tcgetattr(serial_handle, &tio) < 0) 82 | return -1; 83 | 84 | tio.c_cc[VTIME] = ms / 100; 85 | return tcsetattr(serial_handle, TCSANOW, &tio); 86 | } 87 | 88 | int serial_io_open(char *path, int speed) 89 | { 90 | struct termios tio; 91 | memset(&tio, 0, sizeof(tio)); 92 | tio.c_iflag = 0; 93 | tio.c_oflag = 0; 94 | /* 8n1, see termios.h for more information */ 95 | tio.c_cflag = CS8 | CREAD | CLOCAL; 96 | tio.c_lflag = 0; 97 | tio.c_cc[VMIN] = 0; 98 | /* Set 3s as a standart value. Will be set by xmodem_set_timeout before 99 | * each run. */ 100 | tio.c_cc[VTIME] = 30; 101 | 102 | serial_handle = open(path, O_RDWR | O_NOCTTY); 103 | 104 | /* Check if file is open */ 105 | if (serial_handle == -1) { 106 | return -1; 107 | } 108 | 109 | /* Check if file is a terminal */ 110 | if (isatty(serial_handle) != 1) { 111 | return -1; 112 | } 113 | 114 | /* Save initial system settings */ 115 | if(tcgetattr(serial_handle, &tio_initial)) { 116 | return -1; 117 | } 118 | 119 | /* Set signal handler for SIGINT to catch user initiated ^C signals. This 120 | * allows serial_io to reset the serial settings and close the serial port 121 | * before the program exits. This is done after the port is opened and 122 | * before new configuration is set. */ 123 | signal(SIGINT, _signal_handler); 124 | 125 | speed_t serial_speed; 126 | switch (speed) { 127 | case 1200: 128 | serial_speed = B1200; 129 | break; 130 | case 2400: 131 | serial_speed = B2400; 132 | break; 133 | case 4800: 134 | serial_speed = B4800; 135 | break; 136 | case 9600: 137 | serial_speed = B9600; 138 | break; 139 | case 19200: 140 | serial_speed = B19200; 141 | break; 142 | case 38400: 143 | serial_speed = B38400; 144 | break; 145 | case 57600: 146 | serial_speed = B57600; 147 | break; 148 | case 115200: 149 | serial_speed = B115200; 150 | break; 151 | default: 152 | errno = EINVAL; 153 | return -1; 154 | } 155 | cfsetospeed(&tio, serial_speed); 156 | cfsetispeed(&tio, serial_speed); 157 | 158 | if (tcsetattr(serial_handle, TCSANOW, &tio) < 0) { 159 | return -1; 160 | } 161 | return serial_handle; 162 | } 163 | 164 | int serial_detach(void) 165 | { 166 | int status = 0; 167 | int ret = 0; 168 | ret = ioctl(serial_handle, TIOCMGET, &status); 169 | 170 | if (ret < 0) { 171 | return ret; 172 | } 173 | 174 | status |= TIOCM_RTS; 175 | ret = ioctl(serial_handle, TIOCMSET, &status); 176 | 177 | if (ret < 0) { 178 | return ret; 179 | } 180 | /* Keep RTS pulled low for 100 ms. */ 181 | usleep(100000); 182 | status &= ~TIOCM_RTS; 183 | ret = ioctl(serial_handle, TIOCMSET, &status); 184 | if (ret < 0) { 185 | return ret; 186 | } 187 | 188 | return ret; 189 | } 190 | 191 | int serial_io_close(void) 192 | { 193 | if (serial_handle == -1) { 194 | return -1; 195 | } 196 | 197 | /* Set initial system settings. */ 198 | if(tcsetattr(serial_handle, TCSANOW, &tio_initial)) { 199 | return -1; 200 | } 201 | 202 | return close(serial_handle); 203 | } 204 | 205 | #if _BullseyeCoverage 206 | #pragma BullseyeCoverage off 207 | #endif 208 | 209 | static void _signal_handler(int sig) 210 | { 211 | /* Clean up open serial port before exiting. */ 212 | serial_io_close(); 213 | 214 | /* Exit codes for kill signals are (128 + signal_number). */ 215 | exit(128 + sig); 216 | } 217 | 218 | #if _BullseyeCoverage 219 | #pragma BullseyeCoverage on 220 | #endif 221 | -------------------------------------------------------------------------------- /src/qda/serial_io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #ifndef _SERIAL_IO_H_ 20 | #define _SERIAL_IO_H_ 21 | 22 | #include 23 | #include "xmodem.h" 24 | 25 | /** 26 | * Open serial port for XMODEM usage. 27 | * 28 | * @param[in] path Path to serial interface. 29 | * @param[in] speed XMODEM speed. 30 | * @param[out] handle Stores the resulting device handle. 31 | * 32 | * @retval Serial interface handle or error status 33 | * @retval >0 Serial interface handle. 34 | * @retval -1 Error (Check errno) 35 | */ 36 | int serial_io_open(const char *path, int speed); 37 | 38 | /** 39 | * Close serial port after XMODEM usage. 40 | * 41 | * @retval Error Status 42 | * @retval 0 Success 43 | * @retval -1 Error (Check errno) 44 | */ 45 | int serial_io_close(void); 46 | 47 | 48 | /** 49 | * Uses RTS line to simulate a DFU detach command. 50 | * 51 | * @retval Error Status 52 | * @retval 0 Success 53 | * @retval -1 Error (Check errno) 54 | */ 55 | int serial_detach(void); 56 | 57 | #endif /* _SERIAL_IO_H_ */ 58 | -------------------------------------------------------------------------------- /src/qda/serial_io_windows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "xmodem.h" 30 | 31 | /* Support for up to COM 999 */ 32 | #define MAX_COM_PATH_LEN 11 33 | #define COM_PATH_ESPACE_PREFIX "\\\\.\\" 34 | 35 | static HANDLE serial_handle; 36 | static DCB serial_initial_params; 37 | 38 | void xmodem_putc(uint8_t *ch) 39 | { 40 | WriteFile(serial_handle, ch, 1, NULL, NULL); 41 | } 42 | 43 | /* 44 | * Get a character from the XMODEM I/O layer. 45 | * 46 | * This function must be blocking, but is also expected to timeout after a 47 | * certain amount of time. Moreover, in case of error, the function must not 48 | * set the output parameter (i.e., the pointed variable must remain unchanged). 49 | * 50 | * @param[out] ch A pointer to the variable where to store the read character. 51 | * In case of error, the current value of the pointed variable 52 | * is not modified. 53 | * 54 | * @return 0 on success, negative error code otherwise. 55 | * @retval -ETIMEDOUT in case of timeout. 56 | * @retval -EIO in case of I/O error. 57 | */ 58 | int xmodem_getc(uint8_t *ch) 59 | { 60 | DWORD n_bytes_read = 0; 61 | 62 | ReadFile(serial_handle, ch, 1, &n_bytes_read, NULL); 63 | switch (n_bytes_read) { 64 | case 1: 65 | /* We read one character as expected: success */ 66 | return 0; 67 | case 0: 68 | /* We read 0 characters: we timed out */ 69 | return -ETIMEDOUT; 70 | default: 71 | /* Error or unexpected value: generic I/O error */ 72 | return -EIO; 73 | 74 | } 75 | } 76 | 77 | int xmodem_set_timeout(int ms) 78 | { 79 | COMMTIMEOUTS timeouts = {0}; 80 | 81 | // Set COM port timeout settings 82 | timeouts.ReadIntervalTimeout = ms; 83 | timeouts.ReadTotalTimeoutConstant = ms; 84 | timeouts.ReadTotalTimeoutMultiplier = 0; 85 | timeouts.WriteTotalTimeoutConstant = ms; 86 | timeouts.WriteTotalTimeoutMultiplier = 0; 87 | if(SetCommTimeouts(serial_handle, &timeouts) == 0) { 88 | CloseHandle(serial_handle); 89 | return -1; 90 | } 91 | 92 | return 0; 93 | } 94 | 95 | int serial_io_open(char *path, int speed) 96 | { 97 | DCB serial_params = {0}; 98 | char escaped_path[MAX_COM_PATH_LEN]; 99 | int escaping_path_ret_v; 100 | 101 | /* 102 | * MS naming convention for opening COM ports can vary for below 9 and 103 | * above 9. However, the above 9 does also work for the below 9, so the 104 | * COMXYZ port is escaped to match that pattern: \\.\COMXYZ 105 | */ 106 | escaping_path_ret_v = snprintf (escaped_path, MAX_COM_PATH_LEN, "%s%s", 107 | COM_PATH_ESPACE_PREFIX, path); 108 | 109 | /* Fail in case of error or input string too long */ 110 | if ((escaping_path_ret_v < 0) || 111 | (escaping_path_ret_v >= MAX_COM_PATH_LEN)) { 112 | return -1; 113 | } 114 | 115 | /* Open the serial port */ 116 | serial_handle = CreateFile( 117 | escaped_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, 118 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 119 | 120 | if (serial_handle == INVALID_HANDLE_VALUE) { 121 | return -1; 122 | } 123 | 124 | /* Save original serial params */ 125 | if(GetCommState(serial_handle, &serial_initial_params) == 0) { 126 | CloseHandle(serial_handle); 127 | return -1; 128 | } 129 | 130 | /* Set the comm parameters */ 131 | serial_params.ByteSize = 8; 132 | serial_params.StopBits = ONESTOPBIT; 133 | serial_params.Parity = NOPARITY; 134 | switch (speed) { 135 | case 1200: 136 | serial_params.BaudRate = CBR_1200; 137 | break; 138 | case 2400: 139 | serial_params.BaudRate = CBR_2400; 140 | break; 141 | case 4800: 142 | serial_params.BaudRate = CBR_4800; 143 | break; 144 | case 9600: 145 | serial_params.BaudRate = CBR_9600; 146 | break; 147 | case 19200: 148 | serial_params.BaudRate = CBR_19200; 149 | break; 150 | case 38400: 151 | serial_params.BaudRate = CBR_38400; 152 | break; 153 | case 57600: 154 | serial_params.BaudRate = CBR_57600; 155 | break; 156 | case 115200: 157 | serial_params.BaudRate = CBR_115200; 158 | break; 159 | default: 160 | errno = EINVAL; 161 | return -1; 162 | } 163 | if(SetCommState(serial_handle, &serial_params) == 0) { 164 | CloseHandle(serial_handle); 165 | return -1; 166 | } 167 | 168 | return 0; 169 | } 170 | 171 | int serial_detach(void) 172 | { 173 | 174 | if (EscapeCommFunction(serial_handle, SETRTS) == 0) { 175 | return -1; 176 | } 177 | 178 | /* Keep RTS pulled low for 100 ms. */ 179 | usleep(100000); 180 | 181 | 182 | if (EscapeCommFunction(serial_handle, CLRRTS) == 0) { 183 | return -1; 184 | } 185 | 186 | return 0; 187 | } 188 | 189 | int serial_io_close(void) 190 | { 191 | if (serial_handle == INVALID_HANDLE_VALUE) { 192 | return -1; 193 | } 194 | 195 | /* Set initial system settings. */ 196 | if (SetCommState(serial_handle, &serial_initial_params) == 0) { 197 | return -1; 198 | } 199 | 200 | if (CloseHandle(serial_handle) == 0) { 201 | return -1; 202 | } 203 | 204 | return 0; 205 | } 206 | -------------------------------------------------------------------------------- /src/qda/xmodem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "xmodem.h" 25 | 26 | /* The maximum number of consecutive RX errors XMODEM tolerates */ 27 | #define MAX_RX_ERRORS (5) 28 | 29 | /* Timeouts in milliseconds */ 30 | #define TIMEOUT_STD 3000 31 | #define TIMEOUT_ERR 300 32 | 33 | /* Custom value, not transfered via XMODEM, but used as return codes */ 34 | #define ERR (0xFF) 35 | #define DUP (0xFE) 36 | 37 | /* XMODEM control bytes */ 38 | #define SOH (0x01) 39 | #define EOT (0x04) 40 | #define ACK (0x06) 41 | #define NAK (0x15) 42 | #define CAN (0x18) 43 | 44 | /* XMODEM block size */ 45 | #define PACKET_PAYLOAD_SIZE (XMODEM_BLOCK_SIZE) 46 | 47 | /* CRC-16 CCITT */ 48 | #define POLY 0x1021 49 | 50 | /* Activate debug messages by defining DEBUG_MSG to 1 */ 51 | #define DEBUG_MSG (0) 52 | 53 | #if DEBUG_MSG 54 | #define printd(...) printf(__VA_ARGS__) 55 | #else 56 | #define printd(...) 57 | #endif 58 | 59 | extern int xmodem_getc(uint8_t *ch); 60 | extern void xmodem_putc(uint8_t *ch); 61 | extern int xmodem_set_timeout(int ms); 62 | 63 | /** 64 | * The XMODEM packet buffer. 65 | * 66 | * This buffer is used for both incoming and outgoing packets. 67 | */ 68 | static struct __attribute__((__packed__)) xmodem_packet { 69 | uint8_t soh; 70 | uint8_t seq_no; 71 | uint8_t seq_no_inv; 72 | uint8_t data[PACKET_PAYLOAD_SIZE]; 73 | uint8_t crc_u8[2]; 74 | } pkt_buf; 75 | 76 | /** 77 | * Compute CRC. 78 | * 79 | * This function computes CRC 16bits CCITT of the payload, which means: 80 | * - with CRC initialized to 0xffff 81 | * - with 16 'zero' bits appended to the end of the message 82 | * - 0x1021 for the polynomial 83 | * 84 | * @retval computed CRC value 85 | */ 86 | static uint16_t crc_xmodem(void) 87 | { 88 | uint8_t i, b; 89 | uint8_t data; 90 | uint32_t crc = 0; 91 | 92 | for (i = 0; i < PACKET_PAYLOAD_SIZE; i++) { 93 | data = pkt_buf.data[i]; 94 | for (b = 0; b < 8; b++) { 95 | crc <<= 1; 96 | /* add MSB bit of data to message */ 97 | if (data & 0x80) { 98 | crc |= 1; 99 | } 100 | if (crc & 0x10000) 101 | crc ^= POLY; 102 | data <<= 1; 103 | } 104 | }; 105 | 106 | /* append 0 */ 107 | for (i = 0; i < 16; i++) { 108 | if (crc & 0x8000) 109 | crc = (crc << 1) ^ POLY; 110 | else 111 | crc <<= 1; 112 | } 113 | 114 | return (uint16_t)(crc); 115 | } 116 | 117 | /** 118 | * Send a single XMODEM packet. 119 | * 120 | * @param[in] data The payload of the packet. 121 | * @param[in] data_len The length of the payload. Must be at most 128 bytes. 122 | * If less, (random) padding is automatically added. 123 | * @param[in] pkt_no The desired packet sequence number. 124 | * 125 | * @return Resulting status code. 126 | * @retval 0 Success (only possible retval for now). 127 | */ 128 | static int xmodem_send_pkt(const uint8_t *data, size_t data_len, uint8_t pkt_no) 129 | { 130 | size_t i; 131 | uint8_t *buf; 132 | uint16_t crc; 133 | 134 | printd("xmodem_send_pkt(): pkt_no: %d\n", pkt_no); 135 | pkt_buf.soh = SOH; 136 | memcpy(pkt_buf.data, data, data_len); 137 | crc = crc_xmodem(); 138 | pkt_buf.crc_u8[0] = (crc >> 8) & 0xFF; 139 | pkt_buf.crc_u8[1] = crc & 0xFF; 140 | pkt_buf.seq_no = pkt_no; 141 | pkt_buf.seq_no_inv = ~pkt_no; 142 | buf = (uint8_t *)&pkt_buf; 143 | /* Send the packet */ 144 | for (i = 0; i < sizeof(pkt_buf); i++) { 145 | xmodem_putc(&buf[i]); 146 | } 147 | 148 | return 0; 149 | } 150 | 151 | /** 152 | * Try to send an XMODEM packet for MAX_RETRANSMIT times. 153 | * 154 | * This function sends an XMODEM packet and checks if an ACK is received. If no 155 | * ACK is received, the packet is retransmitted. This is done until 156 | * 'MAX_RETRANSMIT' is exceeded. 157 | * 158 | * @param[in] data The payload of the packet. 159 | * @param[in] data_len The length of the payload. Must be at most 128 bytes. 160 | * If less, (random) padding is automatically added. 161 | * @param[in] pkt_no The packet sequence number. 162 | * 163 | * @return Exit status. 164 | * @retval 0 Success, the packet has been transmitted and an ACK received. 165 | * @retval -1 Error, retransmit count exceeded. 166 | */ 167 | static int xmodem_send_pkt_with_retry(const uint8_t *data, size_t data_len, 168 | uint8_t pkt_no) 169 | { 170 | uint8_t retransmit = MAX_RETRANSMIT; 171 | uint8_t rsp; 172 | 173 | printd("xmodem_send_pkt_with_retry(): pkt_no: %d\n", pkt_no); 174 | while (retransmit--) { 175 | xmodem_send_pkt(data, data_len, pkt_no); 176 | rsp = ERR; 177 | xmodem_getc(&rsp); 178 | if (rsp == ACK) { 179 | printd("xmodem_send_pkt_with_retry(): done\n"); 180 | return 0; 181 | } 182 | printd("xmodem_send_pkt_with_retry(): failure (%d) 0x%02x\n", 183 | retransmit, rsp); 184 | } 185 | 186 | return -1; 187 | } 188 | 189 | /** 190 | * Try to send a byte for MAX_RETRANSMIT times. 191 | * 192 | * This function sends a byte (typically an XMODEM control byte) and checks if 193 | * an ACK is received. If no ACK is received, the byte is retransmitted. This is 194 | * done until 'MAX_RETRANSMIT' is exceeded. 195 | * 196 | * @param[in] cmd The byte to send. 197 | * 198 | * @return Exit status. 199 | * @retval 0 Success, the byte has been transmitted and an ACK received. 200 | * @retval -1 Error, retransmit count exceeded. 201 | */ 202 | static int xmodem_send_byte_with_retry(uint8_t cmd) 203 | { 204 | uint8_t retransmit = MAX_RETRANSMIT; 205 | uint8_t rsp; 206 | 207 | while (retransmit--) { 208 | xmodem_putc(&cmd); 209 | rsp = ERR; 210 | xmodem_getc(&rsp); 211 | if (rsp == ACK) { 212 | return 0; 213 | } 214 | printd("xmodem_send_pkt_with_retry(): failure (%d) 0x%02x\n", 215 | retransmit, rsp); 216 | } 217 | 218 | return -1; 219 | } 220 | 221 | /* 222 | * Receive an XMODEM packet. 223 | * 224 | * @param[in] exp_seq_no The expected sequence number of the packet to be 225 | * received. 226 | * @param[in] data The buffer where to store the packet payload. 227 | * @param[in] len The size of the buffer. 228 | * 229 | * @return Status code. 230 | * @retval SOH The packet has been successful received. 231 | * @retval DUP The received packet is a duplicate of the previous one (based on 232 | * the expected sequence number); nothing has not been written to 233 | * the data buffer. 234 | * @retval ERR An error has occurred (either a timeout or the reception of 235 | * invalid / corrupted data), but the XMODEM session is not 236 | * compromised. 237 | * @retval CAN An unrecoverable error has occurred (either the sender and 238 | * receiver have lost sync or the passed buffer is too small). 239 | * @retval EOT The sender notified the end of transmission (i.e., there are no 240 | * more packets to receive). 241 | */ 242 | static int xmodem_read_pkt(uint8_t exp_seq_no, uint8_t *data, size_t len) 243 | { 244 | uint8_t cmd; 245 | uint16_t crc_recv; /* received CRC */ 246 | uint16_t crc_comp; /* computed CRC */ 247 | uint8_t *buf; 248 | uint8_t *buf_end; 249 | 250 | cmd = ERR; 251 | 252 | if (xmodem_getc(&cmd) < 0) { 253 | return ERR; 254 | } 255 | 256 | switch (cmd) { 257 | case SOH: 258 | printd("xmodem_read_pkt(): cmd: SOH\n"); 259 | break; 260 | case EOT: 261 | printd("xmodem_read_pkt(): cmd: EOT\n"); 262 | return EOT; 263 | default: 264 | /* 265 | * Unexpected cmd case. 266 | * 267 | * This includes the case of a corrupted/lost SOH; therefore, 268 | * we should check if other bytes are arriving and, in case, 269 | * discard them before returning (and replying with a NAK). 270 | * 271 | * This is the purpose of the following loop. 272 | */ 273 | printd("xmodem_read_pkt(): cmd: unexpected ctrl byte (0x%x)\n", cmd); 274 | /* Wait until the sender stops sending bytes. We change timeout value 275 | * for the next loop */ 276 | xmodem_set_timeout(TIMEOUT_ERR); 277 | while (xmodem_getc(&cmd) >= 0) 278 | ; 279 | xmodem_set_timeout(TIMEOUT_STD); 280 | return ERR; 281 | } 282 | 283 | /* Read the rest of the packet (seq_no, ~seq_no, data, and CRC) */ 284 | /* Start from seq_no, since we have already read SOH */ 285 | buf = (uint8_t *)&pkt_buf.seq_no; 286 | /* Compute end of buffer */ 287 | buf_end = (uint8_t *)(&pkt_buf + 1); 288 | while (buf < buf_end) { 289 | if (xmodem_getc(buf++) < 0) { 290 | printd("xmodem_read_pkt(): pkt: ERROR: timeout\n"); 291 | printd("----\n"); 292 | /* This is a timeout error */ 293 | return ERR; 294 | } 295 | } 296 | 297 | /* Check sequence number fields and CRC */ 298 | crc_comp = crc_xmodem(); 299 | crc_recv = (pkt_buf.crc_u8[0] << 8) | pkt_buf.crc_u8[1]; 300 | /* 301 | * NOTE: Using 'a == (~a &FF)' instead of 'a == ~a', since the latter 302 | * leads to a compilation error due to the following GCC bug: 303 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38341 304 | */ 305 | if ((pkt_buf.seq_no != (~pkt_buf.seq_no_inv & 0xFF)) || 306 | (crc_recv != crc_comp)) { 307 | printd("xmodem_read_pkt(): pkt: ERROR: corrupted packet\n"); 308 | return ERR; 309 | } 310 | /* Check packet numbers. */ 311 | if ((pkt_buf.seq_no == (exp_seq_no - 1))) { 312 | printd("xmodem_read_pkt(): pkt: WARNING duplicated packet\n"); 313 | return DUP; 314 | } 315 | if (pkt_buf.seq_no != exp_seq_no) { 316 | printd("xmodem_read_pkt(): pkt: ERROR: wrong seq number\n"); 317 | return CAN; 318 | } 319 | 320 | /* 321 | * If we reach this point, the packet is the expected one and it has 322 | * been correctly received: now we can check that the buffer is big 323 | * enough to hold the payload (NOTE: this check should not be 324 | * anticipated, otherwise we risk to return a CAN in case of a simple 325 | * EOT from the sender). 326 | */ 327 | if (len < sizeof(pkt_buf.data)) { 328 | printd("xmodem_read_pkt(): pkt: " 329 | "ERROR: user buffer out of space\n"); 330 | return CAN; 331 | } 332 | memcpy(data, pkt_buf.data, sizeof(pkt_buf.data)); 333 | printd("xmodem_read_pkt(): pkt: received correctly\n"); 334 | 335 | return SOH; 336 | } 337 | 338 | int xmodem_receive_package(uint8_t *buf, size_t buf_len) 339 | { 340 | int status; 341 | uint8_t exp_seq_no; 342 | uint8_t nak; 343 | uint8_t cmd; 344 | int retv; 345 | int data_cnt; 346 | int err_cnt; 347 | 348 | xmodem_set_timeout(TIMEOUT_STD); 349 | 350 | /* XMODEM sequence number starts from 1 */ 351 | exp_seq_no = 1; 352 | /* Reception is started by sending a 'C' */ 353 | cmd = 'C'; 354 | /* 355 | * Until the first packet is received (i.e., the XMODEM transfer is 356 | * started), we must nak with a 'C' instead of a regular NAK 357 | * [this is an XMODEM-CRC peculiarity] 358 | */ 359 | nak = 'C'; 360 | 361 | err_cnt = 0; 362 | data_cnt = 0; 363 | retv = -1; 364 | while (err_cnt < MAX_RX_ERRORS) { 365 | printd("xmodem_receive(): sending cmd: %x\n", cmd); 366 | xmodem_putc(&cmd); 367 | status = xmodem_read_pkt(exp_seq_no, &buf[data_cnt], buf_len); 368 | switch (status) { 369 | case SOH: 370 | nak = NAK; 371 | data_cnt += sizeof(pkt_buf.data); 372 | buf_len -= sizeof(pkt_buf.data); 373 | exp_seq_no++; 374 | err_cnt = 0; 375 | /* no 'break' on purpose */ 376 | case DUP: 377 | /* 378 | * We must acknowledge duplicated packets to have the 379 | * sender transmit the next packet 380 | */ 381 | cmd = ACK; 382 | break; 383 | case EOT: 384 | cmd = ACK; 385 | retv = data_cnt; 386 | goto exit; 387 | case CAN: 388 | cmd = CAN; 389 | goto exit; 390 | default: 391 | err_cnt++; 392 | cmd = nak; 393 | } 394 | } 395 | exit: 396 | if (retv < 0) { 397 | printd("xmodem_receive(): ERROR: reception failed\n"); 398 | } 399 | xmodem_putc(&cmd); 400 | 401 | return retv; 402 | } 403 | 404 | int xmodem_transmit_package(uint8_t *data, size_t len) 405 | { 406 | int mlen; 407 | uint8_t retransmit; 408 | uint8_t rsp; 409 | uint8_t pkt_no; 410 | 411 | xmodem_set_timeout(TIMEOUT_STD); 412 | retransmit = MAX_RETRANSMIT; 413 | 414 | while (retransmit--) { 415 | printd("xmodem_transmit(): waiting for 'C' (%d)\n", retransmit); 416 | rsp = ERR; 417 | xmodem_getc(&rsp); 418 | if (rsp == 'C') { 419 | goto start_transmit; 420 | } 421 | } 422 | 423 | return -1; 424 | 425 | start_transmit: 426 | printd("xmodem_transmit(): starting transmission\n"); 427 | pkt_no = 1; 428 | /* Send packets as long data */ 429 | while (len) { 430 | mlen = (len >= sizeof(pkt_buf.data)) ? sizeof(pkt_buf.data) : len; 431 | if (xmodem_send_pkt_with_retry(data, mlen, pkt_no) < 0) { 432 | return -1; 433 | } 434 | data += mlen; 435 | len -= mlen; 436 | pkt_no++; 437 | } 438 | if (xmodem_send_byte_with_retry(EOT) < 0) { 439 | return -1; 440 | } 441 | 442 | return (pkt_no - 1) * 128; 443 | } 444 | -------------------------------------------------------------------------------- /src/qda/xmodem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Quark Microcontroller DFU Utility 3 | * Copyright (C) 2016, Intel Corporation 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the GNU General Public License version 2 only, as published by 7 | * the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 | * details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | */ 18 | 19 | #ifndef __XMODEM_H__ 20 | #define __XMODEM_H__ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | /** XMODEM block size */ 27 | #define XMODEM_BLOCK_SIZE (128) 28 | 29 | /* The maximum number of times XMODEM tries to send a packet / control byte */ 30 | #define MAX_RETRANSMIT (3) 31 | 32 | /** 33 | * @defgroup groupXMODEM XMODEM 34 | * @{ 35 | */ 36 | 37 | /** 38 | * Switch XMODEM to receive mode. 39 | * 40 | * XMODEM starts to send 'C' (NAK-CRC) messages to the sender and waits for 41 | * incoming transmissions. Received data is copied into the provided buffer. 42 | * 43 | * This function is blocking and it does not timeout. 44 | * 45 | * @param[out] buf Buffer where to store the received data. 46 | * @param[in] buf_size The size of the buffer. 47 | * 48 | * @return Number of received bytes or negative error code. Note that XMODEM 49 | * may add up to 127 padding bytes at the end of the real data. 50 | * @retval >0 Number of received bytes (including padding). 51 | * @retval -1 Error (either the reception failed for an unrecoverable protocol 52 | * error or the provided buffer is too small) 53 | */ 54 | int xmodem_receive_package(uint8_t *buf, size_t buf_size); 55 | 56 | /** 57 | * Switch XMODEM to transmit mode. 58 | * 59 | * XMODEM waits for 'C' (NAK-CRC) messages until the transmission begins. The 60 | * package content is sent in 128 bytes frames. Extra (padding) data is added 61 | * to the last frame if the data size is not multiple of 128 bytes. 62 | * 63 | * This function is blocking, but may timeout. 64 | * 65 | * @param[in] data The data to send. 66 | * @param[in] len The length of the data. 67 | * 68 | * @return Number of bytes actually transmitted (including padding) on success, 69 | * negative error code otherwise. 70 | * @retval >0 Number of sent bytes (including padding). 71 | * @retval -1 Error (timeout or number of retries exceeded). 72 | */ 73 | int xmodem_transmit_package(uint8_t *data, size_t len); 74 | 75 | /** 76 | * @} 77 | */ 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/quirks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple quirk system for dfu-util 3 | * 4 | * Copyright 2010-2014 Tormod Volden 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | 21 | #include 22 | #include "quirks.h" 23 | 24 | uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice) 25 | { 26 | uint16_t quirks = 0; 27 | 28 | /* Device returns bogus bwPollTimeout values */ 29 | if ((vendor == VENDOR_OPENMOKO || vendor == VENDOR_FIC) && 30 | product >= PRODUCT_FREERUNNER_FIRST && 31 | product <= PRODUCT_FREERUNNER_LAST) 32 | quirks |= QUIRK_POLLTIMEOUT; 33 | 34 | if (vendor == VENDOR_VOTI && 35 | product == PRODUCT_OPENPCD) 36 | quirks |= QUIRK_POLLTIMEOUT; 37 | 38 | /* Reports wrong DFU version in DFU descriptor */ 39 | if (vendor == VENDOR_LEAFLABS && 40 | product == PRODUCT_MAPLE3 && 41 | bcdDevice == 0x0200) 42 | quirks |= QUIRK_FORCE_DFU11; 43 | 44 | /* old devices(bcdDevice == 0) return bogus bwPollTimeout values */ 45 | if (vendor == VENDOR_SIEMENS && 46 | (product == PRODUCT_PXM40 || product == PRODUCT_PXM50) && 47 | bcdDevice == 0) 48 | quirks |= QUIRK_POLLTIMEOUT; 49 | 50 | /* M-Audio Transit returns bogus bwPollTimeout values */ 51 | if (vendor == VENDOR_MIDIMAN && 52 | product == PRODUCT_TRANSIT) 53 | quirks |= QUIRK_POLLTIMEOUT; 54 | 55 | return (quirks); 56 | } 57 | -------------------------------------------------------------------------------- /src/quirks.h: -------------------------------------------------------------------------------- 1 | #ifndef DFU_QUIRKS_H 2 | #define DFU_QUIRKS_H 3 | 4 | #define VENDOR_OPENMOKO 0x1d50 /* Openmoko Freerunner / GTA02 */ 5 | #define VENDOR_FIC 0x1457 /* Openmoko Freerunner / GTA02 */ 6 | #define VENDOR_VOTI 0x16c0 /* OpenPCD Reader */ 7 | #define VENDOR_LEAFLABS 0x1eaf /* Maple */ 8 | #define VENDOR_SIEMENS 0x0908 /* Siemens AG */ 9 | #define VENDOR_MIDIMAN 0x0763 /* Midiman */ 10 | 11 | #define PRODUCT_FREERUNNER_FIRST 0x5117 12 | #define PRODUCT_FREERUNNER_LAST 0x5126 13 | #define PRODUCT_OPENPCD 0x076b 14 | #define PRODUCT_MAPLE3 0x0003 /* rev 3 and 5 */ 15 | #define PRODUCT_PXM40 0x02c4 /* Siemens AG, PXM 40 */ 16 | #define PRODUCT_PXM50 0x02c5 /* Siemens AG, PXM 50 */ 17 | #define PRODUCT_TRANSIT 0x2806 /* M-Audio Transit (Midiman) */ 18 | 19 | #define QUIRK_POLLTIMEOUT (1<<0) 20 | #define QUIRK_FORCE_DFU11 (1<<1) 21 | 22 | /* Fallback value, works for OpenMoko */ 23 | #define DEFAULT_POLLTIMEOUT 5 24 | 25 | uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice); 26 | 27 | #endif /* DFU_QUIRKS_H */ 28 | -------------------------------------------------------------------------------- /src/usb_dfu.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_DFU_H 2 | #define USB_DFU_H 3 | /* USB Device Firmware Update Implementation for OpenPCD 4 | * (C) 2006 by Harald Welte 5 | * 6 | * Protocol definitions for USB DFU 7 | * 8 | * This ought to be compliant to the USB DFU Spec 1.0 as available from 9 | * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 | */ 25 | 26 | #include 27 | 28 | #define USB_DT_DFU 0x21 29 | 30 | #ifdef _MSC_VER 31 | # pragma pack(push) 32 | # pragma pack(1) 33 | #endif /* _MSC_VER */ 34 | struct usb_dfu_func_descriptor { 35 | uint8_t bLength; 36 | uint8_t bDescriptorType; 37 | uint8_t bmAttributes; 38 | #define USB_DFU_CAN_DOWNLOAD (1 << 0) 39 | #define USB_DFU_CAN_UPLOAD (1 << 1) 40 | #define USB_DFU_MANIFEST_TOL (1 << 2) 41 | #define USB_DFU_WILL_DETACH (1 << 3) 42 | uint16_t wDetachTimeOut; 43 | uint16_t wTransferSize; 44 | uint16_t bcdDFUVersion; 45 | #ifdef _MSC_VER 46 | }; 47 | # pragma pack(pop) 48 | #elif defined __GNUC__ 49 | } __attribute__ ((packed)); 50 | #else 51 | #warning "No way to pack struct on this compiler? This will break!" 52 | #endif /* _MSC_VER */ 53 | 54 | #define USB_DT_DFU_SIZE 9 55 | 56 | #define USB_TYPE_DFU (LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE) 57 | 58 | /* DFU class-specific requests (Section 3, DFU Rev 1.1) */ 59 | #define USB_REQ_DFU_DETACH 0x00 60 | #define USB_REQ_DFU_DNLOAD 0x01 61 | #define USB_REQ_DFU_UPLOAD 0x02 62 | #define USB_REQ_DFU_GETSTATUS 0x03 63 | #define USB_REQ_DFU_CLRSTATUS 0x04 64 | #define USB_REQ_DFU_GETSTATE 0x05 65 | #define USB_REQ_DFU_ABORT 0x06 66 | 67 | /* DFU_GETSTATUS bStatus values (Section 6.1.2, DFU Rev 1.1) */ 68 | #define DFU_STATUS_OK 0x00 69 | #define DFU_STATUS_errTARGET 0x01 70 | #define DFU_STATUS_errFILE 0x02 71 | #define DFU_STATUS_errWRITE 0x03 72 | #define DFU_STATUS_errERASE 0x04 73 | #define DFU_STATUS_errCHECK_ERASED 0x05 74 | #define DFU_STATUS_errPROG 0x06 75 | #define DFU_STATUS_errVERIFY 0x07 76 | #define DFU_STATUS_errADDRESS 0x08 77 | #define DFU_STATUS_errNOTDONE 0x09 78 | #define DFU_STATUS_errFIRMWARE 0x0a 79 | #define DFU_STATUS_errVENDOR 0x0b 80 | #define DFU_STATUS_errUSBR 0x0c 81 | #define DFU_STATUS_errPOR 0x0d 82 | #define DFU_STATUS_errUNKNOWN 0x0e 83 | #define DFU_STATUS_errSTALLEDPKT 0x0f 84 | 85 | enum dfu_state { 86 | DFU_STATE_appIDLE = 0, 87 | DFU_STATE_appDETACH = 1, 88 | DFU_STATE_dfuIDLE = 2, 89 | DFU_STATE_dfuDNLOAD_SYNC = 3, 90 | DFU_STATE_dfuDNBUSY = 4, 91 | DFU_STATE_dfuDNLOAD_IDLE = 5, 92 | DFU_STATE_dfuMANIFEST_SYNC = 6, 93 | DFU_STATE_dfuMANIFEST = 7, 94 | DFU_STATE_dfuMANIFEST_WAIT_RST = 8, 95 | DFU_STATE_dfuUPLOAD_IDLE = 9, 96 | DFU_STATE_dfuERROR = 10 97 | }; 98 | 99 | #endif /* USB_DFU_H */ 100 | --------------------------------------------------------------------------------