├── .gitignore ├── COPYING ├── Makefile ├── Makefile.mingw ├── README.md ├── image.h ├── imx_loader.h ├── imx_loader_config.c ├── imx_loader_config.h ├── imx_sdp.c ├── imx_sdp.h ├── imx_sdp_simulation.c ├── imx_sdp_simulation.h ├── imx_uart.c ├── imx_usb.c ├── imx_usb.conf ├── msvc ├── getopt.c ├── getopt.h ├── imx_loader.sln ├── imx_uart.vcxproj └── imx_usb.vcxproj ├── mx50_usb_work.conf ├── mx51_usb_work.conf ├── mx53_usb_work.conf ├── mx6_usb_sdp_spl.conf ├── mx6_usb_work.conf ├── mx6ull_usb_work.conf ├── mx7_usb_work.conf ├── mx7ulp_usb_work.conf ├── mx8m_usb_sdp_spl.conf ├── mx8mm_usb_work.conf ├── mx8mn_usb_work.conf ├── mx8mq_usb_work.conf ├── portable.h ├── sdp.c ├── sdp.h ├── sdps.c ├── sdps.h ├── tests ├── Makefile ├── bare.cfg ├── create.txt ├── dcd.cfg ├── image.bin ├── plugin.bin ├── plugin.cfg ├── test-dcd.imx ├── test-dcd.imx.output ├── test-plugin.imx ├── test-plugin.imx.output ├── test.imx └── test.imx.output └── vybrid_usb_work.conf /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | imx_usb 3 | imx_uart 4 | imx_usb.lds 5 | imx_uart.lds 6 | *.bin 7 | *.imx 8 | .*.swp 9 | tests/*.test 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: imx_usb imx_uart 2 | 3 | DESTDIR ?= 4 | prefix ?= /usr 5 | bindir ?= $(prefix)/bin 6 | sysconfdir ?= $(prefix)/etc 7 | rel_sysconfdir = $(shell realpath -m --relative-to=$(bindir) $(sysconfdir)) 8 | 9 | BUILDHOST := $(shell uname -s) 10 | BUILDHOST := $(patsubst CYGWIN_%,CYGWIN,$(BUILDHOST)) 11 | 12 | ifneq ($(BUILDHOST),CYGWIN) 13 | PKG_CONFIG ?= pkg-config 14 | USBCFLAGS = `$(PKG_CONFIG) --cflags libusb-1.0` 15 | USBLDFLAGS = `$(PKG_CONFIG) --libs libusb-1.0` 16 | else 17 | USBCFLAGS = -I/usr/include/libusb-1.0 18 | USBLDFLAGS = -L/usr/lib -lusb-1.0 19 | endif 20 | CONFCPPFLAGS = -DSYSCONFDIR='"$(sysconfdir)"' -DREL_SYSCONFDIR='"$(rel_sysconfdir)"' 21 | CFLAGS ?= -Wall -Wstrict-prototypes -Wno-trigraphs 22 | 23 | imx_usb.o : imx_usb.c imx_sdp.h imx_loader_config.h portable.h 24 | $(CC) -c $*.c -o $@ -pipe -ggdb $(USBCFLAGS) $(CFLAGS) $(CONFCPPFLAGS) 25 | 26 | %.o : %.c imx_sdp.h imx_loader_config.h portable.h image.h 27 | $(CC) -c $*.c -o $@ -pipe -ggdb $(CFLAGS) $(CONFCPPFLAGS) 28 | 29 | imx_usb: imx_usb.o imx_sdp.o imx_sdp_simulation.o imx_loader_config.o sdp.o sdps.o 30 | $(CC) -o $@ $^ $(LDFLAGS) $(USBLDFLAGS) 31 | 32 | imx_uart: imx_uart.o imx_sdp.o imx_loader_config.o sdp.o 33 | $(CC) -o $@ $^ $(LDFLAGS) 34 | 35 | install: imx_usb imx_uart 36 | mkdir -p '$(DESTDIR)$(sysconfdir)/imx-loader.d/' 37 | install -m644 *.conf '$(DESTDIR)$(sysconfdir)/imx-loader.d/' 38 | mkdir -p '$(DESTDIR)$(bindir)' 39 | install -m755 imx_usb '$(DESTDIR)$(bindir)/imx_usb' 40 | install -m755 imx_uart '$(DESTDIR)$(bindir)/imx_uart' 41 | 42 | uninstall: 43 | rm -rf '$(DESTDIR)$(sysconfdir)/imx-loader.d/' 44 | rm -rf '$(DESTDIR)$(bindir)/imx_usb' 45 | rm -rf '$(DESTDIR)$(bindir)/imx_uart' 46 | 47 | clean: 48 | rm -f imx_usb imx_uart *.o 49 | 50 | tests: imx_usb 51 | $(MAKE) -C tests/ tests 52 | 53 | regen: imx_usb 54 | $(MAKE) -C tests/ regen 55 | 56 | .PHONY: all clean install tests 57 | -------------------------------------------------------------------------------- /Makefile.mingw: -------------------------------------------------------------------------------- 1 | all: imx_usb imx_uart 2 | 3 | #$(foreach v,$(.VARIABLES), $(info $(v) = $($(v)))) 4 | 5 | # Building with MinGW natively 6 | CC = gcc 7 | USBCFLAGS = -I$(LIBUSBPATH)\include 8 | USBLDFLAGS = -L$(LIBUSBPATH)\MinGW32\dll -lusb-1.0 9 | 10 | imx_usb.o : imx_usb.c imx_sdp.h portable.h 11 | $(CC) -c $*.c -o $@ -Wstrict-prototypes -Wno-trigraphs -pipe -ggdb $(USBCFLAGS) $(CFLAGS) 12 | 13 | %.o : %.c imx_sdp.h portable.h 14 | $(CC) -c $*.c -o $@ -Wstrict-prototypes -Wno-trigraphs -pipe -ggdb $(CFLAGS) 15 | 16 | imx_usb: imx_usb.o imx_sdp.o imx_loader_config.o sdp.o sdps.o imx_sdp_simulation.o 17 | $(CC) -o $@ $@.o imx_sdp.o imx_loader_config.o sdp.o sdps.o imx_sdp_simulation.o $(LDFLAGS) $(USBLDFLAGS) 18 | 19 | imx_uart: imx_uart.o imx_sdp.o imx_loader_config.o sdp.o 20 | $(CC) -o $@ $@.o imx_sdp.o imx_loader_config.o sdp.o $(LDFLAGS) 21 | 22 | clean: 23 | del /f /q imx_usb imx_uart imx_usb.o imx_uart.o imx_sdp.o 24 | 25 | .PHONY: all clean install 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imx_loader 2 | 3 | i.MX/Vybrid recovery utility 4 | 5 | ## Description 6 | This utility allows to download and execute code on Freescale i.MX5/i.MX6/i.MX7 7 | and Vybrid SoCs through the Serial Download Protocol (SDP). Depending on 8 | the board, there is usually some kind of recovery button to bring the SoC 9 | into serial download boot mode, check documentation of your hardware. 10 | 11 | The utility support USB and UART as serial link. 12 | 13 | ## Installation 14 | 1. Clone 15 | 1. Make sure libusb (1.0) is available 16 | 1. Compile using make 17 | 18 | Two binaries are available, imx_usb and imx_uart for the two supported 19 | connections. 20 | 21 | ### Windows 22 | 23 | Two variants have been tested successfully to build imx_usb and imx_uart 24 | on Windows: 25 | 1. MinGW (using the Microsoft C runtime) 26 | 1. Visual Studio 2015 27 | 28 | #### MinGW 29 | 30 | MinGW allows to use the GNU toolchain (including GCC) to compile a native 31 | Microsoft Windows application. A MinGW specific make file (Makefile.mingw) 32 | is available which allows to build imx_usb/imx_uart with the native make 33 | port (mingw32-make.exe). After installing MinGW, make sure you have a 34 | compiled copy of libusb available and build imx_loader using: 35 | 36 | ``` 37 | mingw32-make -f Makefile.mingw LIBUSBPATH=C:\path\to\libusb 38 | ``` 39 | 40 | This dynamically links against libusb, hence make sure to ship the 41 | library libusb-1.0.dll along with imx_usb.exe. 42 | 43 | #### Visual Studio 44 | 45 | The subdirectory msvc/ contains the project files for Visual Studio 2015. 46 | Make sure you have the Visual C++ component installed. There is one solution 47 | containing two projects, one for imx_usb and one for imx_uart. The imx_usb 48 | project requires libusb to be present at ../../libusb (relative to the msvc) 49 | directory. If you use an alternative location or compile libusb from source 50 | too, you will have to alter the include/library path in the project settings. 51 | 52 | ### macOS 53 | 54 | libusb and pkg-config can be installed via Homebrew. 55 | 56 | If imx_usb fails to claim interface, com.apple.driver.usb.IOUSBHostHIDDevice 57 | needs to be unloaded so libusb can claim, run: 58 | 59 | ``` 60 | sudo kextunload -b com.apple.driver.usb.IOUSBHostHIDDevice 61 | ``` 62 | 63 | ## Usage 64 | Using USB, your device should be detected automatically using the USB 65 | VID/PID from imx_usb.conf. Using UART, the user has to specify a 66 | configuration file. This file is needed to use the correct protocol 67 | variant for the target device (transfer configuration). The 68 | configuration file can also contains work item(s). 69 | 70 | Work items can also be defined using the command line. By specifying a 71 | file in the command line, the utility automatically uses this file as 72 | a work item and reads parameter from its header: 73 | 74 | ``` 75 | ./imx_usb u-boot.imx 76 | ``` 77 | 78 | However, parameters can also specified manually, e.g. 79 | 80 | ``` 81 | ./imx_usb u-boot.imx -l0x3f400400 -s370796 -v 82 | ``` 83 | 84 | The UART link uses hardware flow control using RTS/CTS, so make sure 85 | those are available. The imx_uart utility will configure the target 86 | tty with the right baud rate (115200) and flow control settings: 87 | 88 | ``` 89 | ./imx_uart /dev/ttyUSB0 vybrid_usb_work.conf u-boot.imx 90 | ``` 91 | 92 | -------------------------------------------------------------------------------- /image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2008 Semihalf 3 | * 4 | * (C) Copyright 2000-2005 5 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 6 | * 7 | * SPDX-License-Identifier: GPL-2.0+ 8 | ******************************************************************** 9 | * NOTE: This header file defines an interface to U-Boot. Including 10 | * this (unmodified) header file in another file is considered normal 11 | * use of U-Boot, and does *not* fall under the heading of "derived 12 | * work". 13 | ******************************************************************** 14 | */ 15 | 16 | #ifndef __IMAGE_H__ 17 | #define __IMAGE_H__ 18 | 19 | #include 20 | typedef uint32_t __be32; 21 | 22 | /* 23 | * Operating System Codes 24 | * 25 | * The following are exposed to uImage header. 26 | * Do not change values for backward compatibility. 27 | */ 28 | enum { 29 | IH_OS_INVALID = 0, /* Invalid OS */ 30 | IH_OS_OPENBSD, /* OpenBSD */ 31 | IH_OS_NETBSD, /* NetBSD */ 32 | IH_OS_FREEBSD, /* FreeBSD */ 33 | IH_OS_4_4BSD, /* 4.4BSD */ 34 | IH_OS_LINUX, /* Linux */ 35 | IH_OS_SVR4, /* SVR4 */ 36 | IH_OS_ESIX, /* Esix */ 37 | IH_OS_SOLARIS, /* Solaris */ 38 | IH_OS_IRIX, /* Irix */ 39 | IH_OS_SCO, /* SCO */ 40 | IH_OS_DELL, /* Dell */ 41 | IH_OS_NCR, /* NCR */ 42 | IH_OS_LYNXOS, /* LynxOS */ 43 | IH_OS_VXWORKS, /* VxWorks */ 44 | IH_OS_PSOS, /* pSOS */ 45 | IH_OS_QNX, /* QNX */ 46 | IH_OS_U_BOOT, /* Firmware */ 47 | IH_OS_RTEMS, /* RTEMS */ 48 | IH_OS_ARTOS, /* ARTOS */ 49 | IH_OS_UNITY, /* Unity OS */ 50 | IH_OS_INTEGRITY, /* INTEGRITY */ 51 | IH_OS_OSE, /* OSE */ 52 | IH_OS_PLAN9, /* Plan 9 */ 53 | IH_OS_OPENRTOS, /* OpenRTOS */ 54 | 55 | IH_OS_COUNT, 56 | }; 57 | 58 | /* 59 | * CPU Architecture Codes (supported by Linux) 60 | * 61 | * The following are exposed to uImage header. 62 | * Do not change values for backward compatibility. 63 | */ 64 | enum { 65 | IH_ARCH_INVALID = 0, /* Invalid CPU */ 66 | IH_ARCH_ALPHA, /* Alpha */ 67 | IH_ARCH_ARM, /* ARM */ 68 | IH_ARCH_I386, /* Intel x86 */ 69 | IH_ARCH_IA64, /* IA64 */ 70 | IH_ARCH_MIPS, /* MIPS */ 71 | IH_ARCH_MIPS64, /* MIPS 64 Bit */ 72 | IH_ARCH_PPC, /* PowerPC */ 73 | IH_ARCH_S390, /* IBM S390 */ 74 | IH_ARCH_SH, /* SuperH */ 75 | IH_ARCH_SPARC, /* Sparc */ 76 | IH_ARCH_SPARC64, /* Sparc 64 Bit */ 77 | IH_ARCH_M68K, /* M68K */ 78 | IH_ARCH_NIOS, /* Nios-32 */ 79 | IH_ARCH_MICROBLAZE, /* MicroBlaze */ 80 | IH_ARCH_NIOS2, /* Nios-II */ 81 | IH_ARCH_BLACKFIN, /* Blackfin */ 82 | IH_ARCH_AVR32, /* AVR32 */ 83 | IH_ARCH_ST200, /* STMicroelectronics ST200 */ 84 | IH_ARCH_SANDBOX, /* Sandbox architecture (test only) */ 85 | IH_ARCH_NDS32, /* ANDES Technology - NDS32 */ 86 | IH_ARCH_OPENRISC, /* OpenRISC 1000 */ 87 | IH_ARCH_ARM64, /* ARM64 */ 88 | IH_ARCH_ARC, /* Synopsys DesignWare ARC */ 89 | IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */ 90 | IH_ARCH_XTENSA, /* Xtensa */ 91 | 92 | IH_ARCH_COUNT, 93 | }; 94 | 95 | /* 96 | * Image Types 97 | * 98 | * "Standalone Programs" are directly runnable in the environment 99 | * provided by U-Boot; it is expected that (if they behave 100 | * well) you can continue to work in U-Boot after return from 101 | * the Standalone Program. 102 | * "OS Kernel Images" are usually images of some Embedded OS which 103 | * will take over control completely. Usually these programs 104 | * will install their own set of exception handlers, device 105 | * drivers, set up the MMU, etc. - this means, that you cannot 106 | * expect to re-enter U-Boot except by resetting the CPU. 107 | * "RAMDisk Images" are more or less just data blocks, and their 108 | * parameters (address, size) are passed to an OS kernel that is 109 | * being started. 110 | * "Multi-File Images" contain several images, typically an OS 111 | * (Linux) kernel image and one or more data images like 112 | * RAMDisks. This construct is useful for instance when you want 113 | * to boot over the network using BOOTP etc., where the boot 114 | * server provides just a single image file, but you want to get 115 | * for instance an OS kernel and a RAMDisk image. 116 | * 117 | * "Multi-File Images" start with a list of image sizes, each 118 | * image size (in bytes) specified by an "uint32_t" in network 119 | * byte order. This list is terminated by an "(uint32_t)0". 120 | * Immediately after the terminating 0 follow the images, one by 121 | * one, all aligned on "uint32_t" boundaries (size rounded up to 122 | * a multiple of 4 bytes - except for the last file). 123 | * 124 | * "Firmware Images" are binary images containing firmware (like 125 | * U-Boot or FPGA images) which usually will be programmed to 126 | * flash memory. 127 | * 128 | * "Script files" are command sequences that will be executed by 129 | * U-Boot's command interpreter; this feature is especially 130 | * useful when you configure U-Boot to use a real shell (hush) 131 | * as command interpreter (=> Shell Scripts). 132 | * 133 | * The following are exposed to uImage header. 134 | * Do not change values for backward compatibility. 135 | */ 136 | 137 | enum { 138 | IH_TYPE_INVALID = 0, /* Invalid Image */ 139 | IH_TYPE_STANDALONE, /* Standalone Program */ 140 | IH_TYPE_KERNEL, /* OS Kernel Image */ 141 | IH_TYPE_RAMDISK, /* RAMDisk Image */ 142 | IH_TYPE_MULTI, /* Multi-File Image */ 143 | IH_TYPE_FIRMWARE, /* Firmware Image */ 144 | IH_TYPE_SCRIPT, /* Script file */ 145 | IH_TYPE_FILESYSTEM, /* Filesystem Image (any type) */ 146 | IH_TYPE_FLATDT, /* Binary Flat Device Tree Blob */ 147 | IH_TYPE_KWBIMAGE, /* Kirkwood Boot Image */ 148 | IH_TYPE_IMXIMAGE, /* Freescale IMXBoot Image */ 149 | IH_TYPE_UBLIMAGE, /* Davinci UBL Image */ 150 | IH_TYPE_OMAPIMAGE, /* TI OMAP Config Header Image */ 151 | IH_TYPE_AISIMAGE, /* TI Davinci AIS Image */ 152 | /* OS Kernel Image, can run from any load address */ 153 | IH_TYPE_KERNEL_NOLOAD, 154 | IH_TYPE_PBLIMAGE, /* Freescale PBL Boot Image */ 155 | IH_TYPE_MXSIMAGE, /* Freescale MXSBoot Image */ 156 | IH_TYPE_GPIMAGE, /* TI Keystone GPHeader Image */ 157 | IH_TYPE_ATMELIMAGE, /* ATMEL ROM bootable Image */ 158 | IH_TYPE_SOCFPGAIMAGE, /* Altera SOCFPGA Preloader */ 159 | IH_TYPE_X86_SETUP, /* x86 setup.bin Image */ 160 | IH_TYPE_LPC32XXIMAGE, /* x86 setup.bin Image */ 161 | IH_TYPE_LOADABLE, /* A list of typeless images */ 162 | IH_TYPE_RKIMAGE, /* Rockchip Boot Image */ 163 | IH_TYPE_RKSD, /* Rockchip SD card */ 164 | IH_TYPE_RKSPI, /* Rockchip SPI image */ 165 | IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ 166 | IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ 167 | IH_TYPE_FPGA, /* FPGA Image */ 168 | IH_TYPE_VYBRIDIMAGE, /* VYBRID .vyb Image */ 169 | IH_TYPE_TEE, /* Trusted Execution Environment OS Image */ 170 | IH_TYPE_FIRMWARE_IVT, /* Firmware Image with HABv4 IVT */ 171 | 172 | IH_TYPE_COUNT, /* Number of image types */ 173 | }; 174 | 175 | /* 176 | * Compression Types 177 | * 178 | * The following are exposed to uImage header. 179 | * Do not change values for backward compatibility. 180 | */ 181 | enum { 182 | IH_COMP_NONE = 0, /* No Compression Used */ 183 | IH_COMP_GZIP, /* gzip Compression Used */ 184 | IH_COMP_BZIP2, /* bzip2 Compression Used */ 185 | IH_COMP_LZMA, /* lzma Compression Used */ 186 | IH_COMP_LZO, /* lzo Compression Used */ 187 | IH_COMP_LZ4, /* lz4 Compression Used */ 188 | 189 | IH_COMP_COUNT, 190 | }; 191 | 192 | #define IH_MAGIC 0x27051956 /* Image Magic Number */ 193 | #define IH_NMLEN 32 /* Image Name Length */ 194 | 195 | /* Reused from common.h */ 196 | #define ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1)) 197 | 198 | /* 199 | * Legacy format image header, 200 | * all data in network byte order (aka natural aka bigendian). 201 | */ 202 | typedef struct image_header { 203 | __be32 ih_magic; /* Image Header Magic Number */ 204 | __be32 ih_hcrc; /* Image Header CRC Checksum */ 205 | __be32 ih_time; /* Image Creation Timestamp */ 206 | __be32 ih_size; /* Image Data Size */ 207 | __be32 ih_load; /* Data Load Address */ 208 | __be32 ih_ep; /* Entry Point Address */ 209 | __be32 ih_dcrc; /* Image Data CRC Checksum */ 210 | uint8_t ih_os; /* Operating System */ 211 | uint8_t ih_arch; /* CPU architecture */ 212 | uint8_t ih_type; /* Image Type */ 213 | uint8_t ih_comp; /* Compression Type */ 214 | uint8_t ih_name[IH_NMLEN]; /* Image Name */ 215 | } image_header_t; 216 | 217 | #endif /* __IMAGE_H__ */ 218 | -------------------------------------------------------------------------------- /imx_loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_loader common header file for imx_usb/imx_uart 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 | */ 18 | 19 | #ifndef __IMX_LOADER_H__ 20 | #define __IMX_LOADER_H__ 21 | 22 | #define IMX_LOADER_VERSION "0.2pre" 23 | 24 | #endif /* __IMX_LOADER_H__ */ 25 | -------------------------------------------------------------------------------- /imx_loader_config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_loader_config: 3 | * Configuration file parser for imx_usb/imx_uart loader 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "portable.h" 26 | #include "imx_sdp.h" 27 | #include "image.h" 28 | #include "sdp.h" 29 | #include "sdps.h" 30 | 31 | int get_val(const char** pp, int base) 32 | { 33 | int val = 0; 34 | const char *p = *pp; 35 | while (*p==' ') p++; 36 | if (*p=='0') { 37 | p++; 38 | if ((*p=='x')||(*p=='X')) { 39 | p++; 40 | base = 16; 41 | } 42 | } 43 | while (*p) { 44 | char c = *p++; 45 | if ((c >= '0')&&(c <= '9')) { 46 | c -= '0'; 47 | } else { 48 | c &= ~('a'-'A'); 49 | if ((c >= 'A')&&(c <= 'F')) c -= ('A'-10); 50 | else { 51 | p--; 52 | break; 53 | } 54 | } 55 | if (c >= base) { 56 | printf("Syntax error: %s\n", p-1); 57 | val = -1; 58 | break; 59 | } 60 | val = (val * base) + c; 61 | } 62 | while (*p==' ') p++; 63 | *pp = p; 64 | return val; 65 | } 66 | 67 | const char *move_string(char *dest, const char *src, unsigned cnt) 68 | { 69 | unsigned i = 0; 70 | while (i < cnt) { 71 | char c = *src++; 72 | if ((!c) || (c == ' ') || (c == 0x0d) || (c == '\n') || 73 | (c == '#') || (c == ':') || (c == ',')) { 74 | src--; 75 | break; 76 | } 77 | dest[i++] = c; 78 | } 79 | dest[i] = '\0'; 80 | return src; 81 | } 82 | 83 | char const *get_base_path(char const *argv0) 84 | { 85 | static char base_path[PATH_MAX]; 86 | char *e; 87 | 88 | strncpy(base_path, argv0, sizeof(base_path)); 89 | e = strrchr(base_path, PATH_SEPARATOR); 90 | #ifdef __unix__ 91 | if (!e) { 92 | readlink("/proc/self/exe", base_path,sizeof(base_path)); 93 | e = strrchr(base_path, PATH_SEPARATOR); 94 | } 95 | #endif 96 | if (e) { 97 | dbg_printf( "trailing slash == %p:%s\n", e, e); 98 | e[1] = 0; 99 | } else { 100 | dbg_printf( "no trailing slash\n"); 101 | } 102 | 103 | return base_path; 104 | } 105 | 106 | char const *get_global_conf_path(void) 107 | { 108 | #ifdef WIN32 109 | static char conf[PATH_MAX]; 110 | static char sep = PATH_SEPARATOR; 111 | const char *subdir = "imx_loader"; 112 | char const *progdata = getenv("ProgramData"); 113 | 114 | strncpy(conf, progdata, sizeof(conf)); 115 | strncat(conf, &sep, sizeof(conf)); 116 | strncat(conf, subdir, sizeof(conf)); 117 | return conf; 118 | #else 119 | char const *global_conf_path = SYSCONFDIR "/imx-loader.d/"; 120 | return global_conf_path; 121 | #endif 122 | } 123 | 124 | char const *conf_path_ok(char const *conf_path, char const *conf_file) 125 | { 126 | static char conf[PATH_MAX]; 127 | static char sep = PATH_SEPARATOR; 128 | 129 | strncpy(conf, conf_path, sizeof(conf)); 130 | strncat(conf, &sep, sizeof(conf) - strlen(conf) - 1); 131 | strncat(conf, conf_file, sizeof(conf) - strlen(conf) - 1); 132 | if (access(conf, R_OK) != -1) { 133 | printf("config file <%s>\n", conf); 134 | return conf; 135 | } 136 | return NULL; 137 | } 138 | 139 | char const *conf_file_name(char const *file, char const *base_path, char const *conf_path) 140 | { 141 | char const *conf; 142 | char path[PATH_MAX]; 143 | 144 | // First priority, conf path... (either -c, binary or /etc/imx-loader.d/) 145 | dbg_printf("checking with conf_path %s\n", conf_path); 146 | conf = conf_path_ok(conf_path, file); 147 | if (conf != NULL) 148 | return conf; 149 | 150 | // Second priority, base path, relative path of binary... 151 | dbg_printf("checking with base_path %s\n", base_path); 152 | conf = conf_path_ok(base_path, file); 153 | if (conf != NULL) 154 | return conf; 155 | 156 | // Third priority, working directory... 157 | getcwd(path, PATH_MAX); 158 | dbg_printf("checking with cwd %s\n", path); 159 | conf = conf_path_ok(path, file); 160 | if (conf != NULL) 161 | return conf; 162 | 163 | #ifndef WIN32 164 | // Fourth priority, conf path relative to base path... 165 | snprintf(path, sizeof(path), "%s/%s", base_path, REL_SYSCONFDIR "/imx-loader.d"); 166 | dbg_printf("checking with rel_base_path %s\n", path); 167 | conf = conf_path_ok(path, file); 168 | if (conf != NULL) 169 | return conf; 170 | #endif 171 | 172 | printf("%s not found\n", file); 173 | return NULL; 174 | } 175 | 176 | char const *skip(const char *p, char c) 177 | { 178 | while (*p==' ') p++; 179 | if (*p == c) { 180 | p++; 181 | } 182 | while (*p==' ') p++; 183 | return p; 184 | } 185 | 186 | int end_of_line(const char *p) 187 | { 188 | while (*p == ' ') p++; 189 | if ((!p[0]) || (*p == '#') || (*p == '\n') || (*p == '\r')) 190 | return 1; 191 | return 0; 192 | } 193 | 194 | 195 | void parse_mem_work(struct sdp_work *curr, const char *filename, const char *p) 196 | { 197 | struct mem_work *wp; 198 | struct mem_work **link; 199 | struct mem_work w; 200 | unsigned int i; 201 | const char *start = p; 202 | 203 | p = skip(p,':'); 204 | memset(&w, 0, sizeof(w)); 205 | if (strncmp(p, "read", 4) == 0) { 206 | p += 4; 207 | p = skip(p,','); 208 | i = MEM_TYPE_READ; 209 | } else if (strncmp(p, "write", 5) == 0) { 210 | p += 5; 211 | p = skip(p,','); 212 | i = MEM_TYPE_WRITE; 213 | } else if (strncmp(p, "modify", 6) == 0) { 214 | p += 6; 215 | p = skip(p,','); 216 | i = MEM_TYPE_MODIFY; 217 | } else { 218 | printf("%s: syntax error: %s {%s}\n", filename, p, start); 219 | } 220 | w.type = i; 221 | i = 0; 222 | for (;;) { 223 | w.vals[i] = get_val(&p, 16); 224 | if (i >= w.type) 225 | break; 226 | p = skip(p,','); 227 | if ((*p == 0) || (*p == '#')) { 228 | printf("%s: missing argment: %s {%s}\n", filename, p, start); 229 | return; 230 | } 231 | i++; 232 | } 233 | if (!end_of_line(p)) { 234 | printf("%s: syntax error: %s {%s}\n", filename, p, start); 235 | return; 236 | } 237 | wp = (struct mem_work *)malloc(sizeof(struct mem_work)); 238 | if (!wp) 239 | return; 240 | link = &curr->mem; 241 | while (*link) 242 | link = &(*link)->next; 243 | *wp = w; 244 | *link = wp; 245 | } 246 | 247 | void parse_file_work(struct sdp_work *curr, const char *filename, const char *p) 248 | { 249 | const char *start = p; 250 | 251 | p = move_string(curr->filename, p, sizeof(curr->filename) - 1); 252 | p = skip(p,':'); 253 | for (;;) { 254 | const char *q = p; 255 | if ((!*p) || (*p == '#') || (*p == '\n') || (*p == 0x0d)) 256 | break; 257 | if (strncmp(p, "dcd", 3) == 0) { 258 | p += 3; 259 | p = skip(p,','); 260 | curr->dcd = 1; 261 | } 262 | if (strncmp(p, "clear_dcd", 9) == 0) { 263 | p += 9; 264 | p = skip(p,','); 265 | curr->clear_dcd = 1; 266 | // printf("clear_dcd\n"); 267 | } 268 | if (strncmp(p, "clear_boot_data", 15) == 0) { 269 | p += 15; 270 | p = skip(p,','); 271 | curr->clear_boot_data = 1; 272 | // printf("clear_dcd\n"); 273 | } 274 | if (strncmp(p, "plug", 4) == 0) { 275 | p += 4; 276 | p = skip(p,','); 277 | curr->plug = 1; 278 | // printf("plug\n"); 279 | } 280 | if (strncmp(p, "load", 4) == 0) { 281 | p += 4; 282 | curr->load_addr = get_val(&p, 16); 283 | p = skip(p,','); 284 | } 285 | if (strncmp(p, "size", 4) == 0) { 286 | p += 4; 287 | curr->load_size = get_val(&p, 16); 288 | p = skip(p,','); 289 | } 290 | if (strncmp(p, "skip", 4) == 0) { 291 | p += 4; 292 | curr->load_skip = get_val(&p, 16); 293 | p = skip(p,','); 294 | } 295 | if (strncmp(p, "jump_direct", 11) == 0) { 296 | p += 11; 297 | curr->jump_mode = J_ADDR_DIRECT; 298 | curr->jump_addr = get_val(&p, 16); 299 | p = skip(p,','); 300 | } 301 | if (strncmp(p, "jump", 4) == 0) { 302 | p += 4; 303 | curr->jump_mode = J_ADDR_HEADER; 304 | curr->jump_addr = get_val(&p, 16); 305 | if (strncmp(p, "header2", 7) == 0) { 306 | p += 7; 307 | p = skip(p,','); 308 | curr->jump_mode = J_HEADER2; 309 | } else if (strncmp(p, "header", 6) == 0) { 310 | p += 6; 311 | p = skip(p,','); 312 | curr->jump_mode = J_HEADER; 313 | } 314 | p = skip(p,','); 315 | // printf("jump\n"); 316 | } 317 | if (q == p) { 318 | printf("%s: syntax error: %s {%s}\n", filename, p, start); 319 | break; 320 | } 321 | } 322 | } 323 | 324 | /* 325 | * #hid/bulk,[old_header,]max packet size, {ram start, ram size}(repeat valid ram areas) 326 | *hid,1024,0x10000000,1G,0x00907000,0x31000 327 | * 328 | */ 329 | void parse_transfer_type(struct sdp_dev *usb, const char *filename, const char *p) 330 | { 331 | int i; 332 | 333 | if (strncmp(p, "hid", 3) == 0) { 334 | p += 3; 335 | p = skip(p,','); 336 | usb->mode = MODE_HID; 337 | sdp_init_ops(usb); 338 | } else if (strncmp(p, "bulk", 4) == 0) { 339 | p += 4; 340 | p = skip(p,','); 341 | usb->mode = MODE_BULK; 342 | sdp_init_ops(usb); 343 | } else if (strncmp(p, "sdps", 4) == 0) { 344 | p += 4; 345 | p = skip(p,','); 346 | usb->mode = MODE_SDPS; 347 | sdps_init_ops(usb); 348 | } else { 349 | printf("%s: hid/bulk/sdps expected\n", filename); 350 | } 351 | if (strncmp(p, "no-hid-cmd", 10) == 0) { 352 | p += 10; 353 | p = skip(p,','); 354 | usb->no_hid_cmd = 1; 355 | } 356 | if (strncmp(p, "ep1", 3) == 0) { 357 | p += 3; 358 | p = skip(p,','); 359 | usb->use_ep1 = 1; 360 | } 361 | if (strncmp(p, "old_header", 10) == 0) { 362 | p += 10; 363 | p = skip(p,','); 364 | usb->header_type = HDR_MX51; 365 | } else if (strncmp(p, "uboot_header", 12) == 0) { 366 | p += 12; 367 | p = skip(p,','); 368 | usb->header_type = HDR_UBOOT; 369 | } else { 370 | usb->header_type = HDR_MX53; 371 | } 372 | usb->max_transfer = get_val(&p, 10); 373 | p = skip(p,','); 374 | usb->dcd_addr = get_val(&p, 16); 375 | p = skip(p,','); 376 | for (i = 0; i < 8; i++) { 377 | usb->ram[i].start = get_val(&p, 10); 378 | p = skip(p,','); 379 | usb->ram[i].size = get_val(&p, 10); 380 | if ((*p == 'G') || (*p == 'g')) { 381 | usb->ram[i].size <<= 30; 382 | p++; 383 | } else if ((*p == 'M') || (*p == 'm')) { 384 | usb->ram[i].size <<= 20; 385 | p++; 386 | } else if ((*p == 'K') || (*p == 'k')) { 387 | usb->ram[i].size <<= 10; 388 | p++; 389 | } 390 | p = skip(p,','); 391 | if ((*p == '#') || (*p == '\n') || (!*p)) 392 | break; 393 | } 394 | } 395 | 396 | struct sdp_dev *parse_conf(const char *filename) 397 | { 398 | char line[512]; 399 | FILE *xfile; 400 | const char *p; 401 | struct sdp_work *tail = NULL; 402 | struct sdp_work *curr = NULL; 403 | struct sdp_dev *usb = (struct sdp_dev *)malloc(sizeof(struct sdp_dev)); 404 | if (!usb) 405 | return NULL; 406 | memset(usb, 0, sizeof(struct sdp_dev)); 407 | 408 | xfile = fopen(filename, "rb" ); 409 | if (!xfile) { 410 | printf("Could not open file: {%s}\n", filename); 411 | free(usb); 412 | return NULL; 413 | } 414 | printf("parse %s\n", filename); 415 | 416 | while (fgets(line, sizeof(line), xfile) != NULL) { 417 | p = line; 418 | while (*p==' ') p++; 419 | if (p[0] == '#') 420 | continue; 421 | if (p[0] == 0) 422 | continue; 423 | if (p[0] == '\n') 424 | continue; 425 | if (p[0] == 0x0d) 426 | continue; 427 | if (!usb->name[0]) { 428 | p = move_string(usb->name, p, sizeof(usb->name) - 1); 429 | continue; 430 | } 431 | if (!usb->max_transfer) { 432 | parse_transfer_type(usb, filename, p); 433 | continue; 434 | } 435 | /* 436 | * #file:dcd,plug,load nnn,jump [nnn/header/header2] 437 | */ 438 | if (!curr) { 439 | curr = (struct sdp_work *)malloc(sizeof(struct sdp_work)); 440 | if (!curr) 441 | break; 442 | memset(curr, 0, sizeof(struct sdp_work)); 443 | if (!usb->work) 444 | usb->work = curr; 445 | if (tail) 446 | tail->next = curr; 447 | tail = curr; 448 | } 449 | 450 | if (p[0] == ':') { 451 | parse_mem_work(curr, filename, p); 452 | } else { 453 | parse_file_work(curr, filename, p); 454 | curr = NULL; 455 | } 456 | } 457 | return usb; 458 | } 459 | 460 | struct sdp_work *parse_cmd_args(int argc, char * const *argv) 461 | { 462 | int i = 0; 463 | struct sdp_work *prev = NULL; 464 | struct sdp_work *w = NULL; 465 | struct sdp_work *head = NULL; 466 | 467 | while (argc > i) { 468 | const char *p = argv[i]; 469 | if (*p == '-') { 470 | char c; 471 | p++; 472 | c = *p++; 473 | if (w == NULL) { 474 | printf("specify file first\n"); 475 | exit(1); 476 | } 477 | if (!*p) { 478 | i++; 479 | p = argv[i]; 480 | } 481 | if (c == 's') { 482 | w->load_size = get_val(&p, 10); 483 | if (!w->load_addr) 484 | w->load_addr = 0x10800000; 485 | w->plug = 0; 486 | w->jump_mode = 0; 487 | i++; 488 | continue; 489 | } 490 | if (c == 'l') { 491 | w->load_addr = get_val(&p, 16); 492 | w->plug = 0; 493 | w->jump_mode = 0; 494 | i++; 495 | continue; 496 | } 497 | fprintf(stderr, "Unknown option %s\n", p); 498 | exit(1); 499 | } 500 | 501 | // Initialize work structure.. 502 | w = malloc(sizeof(struct sdp_work)); 503 | memset(w, 0, sizeof(struct sdp_work)); 504 | strncpy(w->filename, argv[i], sizeof(w->filename) - 1); 505 | if (access(w->filename, R_OK) == -1) { 506 | fprintf(stderr, "cannot read from file %s\n", 507 | w->filename); 508 | exit(1); 509 | } 510 | 511 | 512 | if (head == NULL) { 513 | // Special settings for first work... 514 | w->dcd = 1; 515 | w->plug = 1; 516 | w->jump_mode = J_HEADER; 517 | head = w; 518 | } 519 | 520 | if (prev != NULL) 521 | prev->next = w; 522 | prev = w; 523 | 524 | i++; 525 | } 526 | 527 | return head; 528 | } 529 | -------------------------------------------------------------------------------- /imx_loader_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_loader_config: 3 | * Configuration file parser for imx_usb/imx_uart loader 4 | * 5 | * This library is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU Lesser General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef __IMX_LOADER_CONFIG_H__ 21 | #define __IMX_LOADER_CONFIG_H__ 22 | 23 | struct sdp_work; 24 | 25 | int get_val(const char** pp, int base); 26 | const char *move_string(char *dest, const char *src, unsigned cnt); 27 | 28 | char const *get_global_conf_path(void); 29 | char const *get_base_path(char const *argv0); 30 | char const *conf_file_name(char const *file, char const *base_path, char const *conf_path); 31 | struct sdp_dev *parse_conf(const char *filename); 32 | struct sdp_work *parse_cmd_args(int argc, char * const *argv); 33 | 34 | #endif /* __IMX_LOADER_CONFIG_H__ */ 35 | -------------------------------------------------------------------------------- /imx_sdp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_sdp: 3 | * Implementation of the Serial Download Protocol (SDP) for i.MX/Vybrid 4 | * series processors. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library 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 GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "portable.h" 32 | #include "imx_sdp.h" 33 | #include "image.h" 34 | 35 | #define FT_APP 0xaa 36 | #define FT_CSF 0xcc 37 | #define FT_DCD 0xee 38 | #define FT_LOAD_ONLY 0x00 39 | 40 | int debugmode = 0; 41 | 42 | #define get_min(a, b) (((a) < (b)) ? (a) : (b)) 43 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 44 | 45 | #ifndef offsetof 46 | #define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) 47 | //#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 48 | #endif 49 | 50 | struct load_desc { 51 | struct sdp_work *curr; 52 | FILE* xfile; 53 | unsigned fsize; 54 | int verify; 55 | unsigned char *buf_start; 56 | unsigned buf_size; 57 | unsigned buf_cnt; 58 | unsigned buf_offset; 59 | unsigned dladdr; 60 | unsigned max_length; 61 | unsigned plugin; 62 | unsigned header_addr; 63 | unsigned header_offset; 64 | unsigned char writeable_header[1024]; 65 | }; 66 | 67 | /* Boot data image indicator */ 68 | #define PLUGIN_IMAGE_FLAG_MASK (0x0001) /* bit 0 is plugin */ 69 | #define HDMI_IMAGE_FLAG_MASK (0x0002) /* bit 1 is HDMI */ 70 | 71 | struct boot_data { 72 | uint32_t dest; 73 | uint32_t image_len; 74 | uint32_t plugin; 75 | }; 76 | 77 | /* Command tags and parameters */ 78 | #define IVT_HEADER_TAG 0xD1 79 | #define IVT_VERSION 0x40 80 | #define IVT_VERSION_IMX8M 0x41 81 | #define DCD_HEADER_TAG 0xD2 82 | #define DCD_VERSION 0x40 83 | #define DCD_VERSION_IMX8M 0x41 84 | 85 | #pragma pack (1) 86 | struct ivt_header { 87 | uint8_t tag; 88 | uint16_t length; 89 | uint8_t version; 90 | }; 91 | #pragma pack () 92 | 93 | struct flash_header_v2 { 94 | struct ivt_header header; 95 | uint32_t start_addr; 96 | uint32_t reserv1; 97 | uint32_t dcd_ptr; 98 | uint32_t boot_data_ptr; /* struct boot_data * */ 99 | uint32_t self_ptr; /* struct flash_header_v2 *, this - boot_data.start = offset linked at */ 100 | uint32_t app_code_csf; 101 | uint32_t reserv2; 102 | }; 103 | 104 | #pragma pack (1) 105 | struct write_dcd_command { 106 | uint8_t tag; 107 | uint16_t length; 108 | uint8_t param; 109 | }; 110 | #pragma pack () 111 | 112 | struct dcd_v2 { 113 | struct ivt_header header; 114 | struct write_dcd_command write_dcd_command; 115 | unsigned char *addr_data; 116 | }; 117 | 118 | 119 | /* 120 | * MX51 header type 121 | */ 122 | struct flash_header_v1 { 123 | uint32_t app_start_addr; 124 | #define APP_BARKER 0xb1 125 | #define DCD_BARKER 0xb17219e9 126 | uint32_t app_barker; 127 | uint32_t csf_ptr; 128 | uint32_t dcd_ptr_ptr; 129 | uint32_t srk_ptr; 130 | uint32_t dcd_ptr; 131 | uint32_t app_dest_ptr; 132 | }; 133 | 134 | static void print_sdp_work(struct sdp_work *curr) 135 | { 136 | printf("== work item\n"); 137 | printf("filename %s\n", curr->filename); 138 | printf("load_size %d bytes\n", curr->load_size); 139 | printf("load_addr 0x%08x\n", curr->load_addr); 140 | printf("dcd %u\n", curr->dcd); 141 | printf("clear_dcd %u\n", curr->clear_dcd); 142 | printf("plug %u\n", curr->plug); 143 | printf("jump_mode %d\n", curr->jump_mode); 144 | printf("jump_addr 0x%08x\n", curr->jump_addr); 145 | printf("== end work item\n"); 146 | return; 147 | } 148 | 149 | static long get_file_size(FILE *xfile) 150 | { 151 | long size; 152 | fseek(xfile, 0, SEEK_END); 153 | size = ftell(xfile); 154 | rewind(xfile); 155 | // printf("filesize=%lx\n", size); 156 | return size; 157 | } 158 | 159 | static int do_response(struct sdp_dev *dev, int report, unsigned int *result, 160 | bool silent) 161 | { 162 | unsigned char tmp[64] = { 0 }; 163 | int last_trans, err; 164 | 165 | err = dev->ops->transfer(dev, report, tmp, sizeof(tmp), 4, &last_trans); 166 | if ((!silent && err) || debugmode) 167 | printf("report %d in err=%i, last_trans=%i %02x %02x %02x %02x\n", 168 | report, err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); 169 | 170 | /* At least 4 bytes required for a valid result */ 171 | if (last_trans < 4) 172 | return -1; 173 | 174 | /* 175 | * Most results are symetric, but likely are meant to be big endian 176 | * as everything else is... 177 | */ 178 | *result = BE32(*((unsigned int*)tmp)); 179 | 180 | return err; 181 | } 182 | 183 | static int do_command(struct sdp_dev *dev, unsigned char *cmd, int cmd_size, int retry) 184 | { 185 | int last_trans, err = -4; 186 | 187 | dbg_printf("sending command cmd=%02x %02x %02x %02x\n", cmd[0], cmd[1],cmd[2],cmd[3]); 188 | while (retry) { 189 | err = dev->ops->transfer(dev, 1, (unsigned char *)cmd, 190 | cmd_size, 0, &last_trans); 191 | if (err || debugmode) 192 | printf("%s err=%i, last_trans=%i\n", __func__, err, last_trans); 193 | if (!err) 194 | return 0; 195 | 196 | retry--; 197 | } 198 | 199 | return err; 200 | } 201 | 202 | static int read_memory(struct sdp_dev *dev, unsigned addr, unsigned char *dest, unsigned cnt) 203 | { 204 | unsigned char buf[MAX_PROTOCOL_SIZE]; 205 | int cmd_size; 206 | int retry = 0; 207 | int last_trans; 208 | int err; 209 | int rem; 210 | unsigned char tmp[64]; 211 | unsigned int sec; 212 | 213 | if (!dev->ops->fill_read_reg) 214 | return 0; 215 | cmd_size = dev->ops->fill_read_reg(buf, addr, cnt); 216 | if (cmd_size <= 0) 217 | return cmd_size; 218 | dbg_printf("%s: addr=%08x, cnt=%08x\n", __func__, addr, cnt); 219 | err = do_command(dev, buf, cmd_size, 5); 220 | if (err) 221 | return err; 222 | 223 | err = do_response(dev, 3, &sec, false); 224 | if (err) 225 | return err; 226 | 227 | rem = cnt; 228 | retry = 0; 229 | while (rem) { 230 | tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; 231 | err = dev->ops->transfer(dev, 4, tmp, 64, rem > 64 ? 64 : rem, &last_trans); 232 | if (err) { 233 | printf("r4 in err=%i, last_trans=%i %02x %02x %02x %02x cnt=%d rem=%d\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem); 234 | if (retry++ > 8) 235 | break; 236 | continue; 237 | } 238 | retry = 0; 239 | if ((last_trans > rem) || (last_trans > 64)) { 240 | if ((last_trans == 64) && (cnt == rem)) { 241 | /* Last transfer is expected to be too large for HID */ 242 | } else { 243 | printf("err: %02x %02x %02x %02x cnt=%d rem=%d last_trans=%i\n", tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem, last_trans); 244 | } 245 | last_trans = rem; 246 | if (last_trans > 64) 247 | last_trans = 64; 248 | } 249 | memcpy(dest, tmp, last_trans); 250 | dest += last_trans; 251 | rem -= last_trans; 252 | } 253 | dbg_printf("%s: %d addr=%08x, val=%02x %02x %02x %02x\n", __func__, err, addr, dest[0], dest[1], dest[2], dest[3]); 254 | return err; 255 | } 256 | 257 | static int write_memory(struct sdp_dev *dev, unsigned addr, unsigned val) 258 | { 259 | unsigned char buf[MAX_PROTOCOL_SIZE]; 260 | int cmd_size; 261 | int last_trans; 262 | int err = 0; 263 | unsigned char tmp[64] = { 0 }; 264 | unsigned int sec; 265 | 266 | if (!dev->ops->fill_write_reg) 267 | return 0; 268 | cmd_size = dev->ops->fill_write_reg(buf, addr, val); 269 | if (cmd_size <= 0) 270 | return cmd_size; 271 | dbg_printf("%s: addr=%08x, val=%08x\n", __func__, addr, val); 272 | err = do_command(dev, buf, cmd_size, 5); 273 | if (err) 274 | return err; 275 | 276 | err = do_response(dev, 3, &sec, false); 277 | if (err) 278 | return err; 279 | 280 | err = dev->ops->transfer(dev, 4, tmp, sizeof(tmp), 4, &last_trans); 281 | dbg_printf("report 4, err=%i, last_trans=%i %02x %02x %02x %02x %02x %02x %02x %02x\n", 282 | err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], 283 | tmp[4], tmp[5], tmp[6], tmp[7]); 284 | if (err) 285 | printf("w4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); 286 | return err; 287 | } 288 | 289 | static void perform_mem_work(struct sdp_dev *dev, struct mem_work *mem) 290 | { 291 | unsigned tmp, tmp2; 292 | 293 | while (mem) { 294 | switch (mem->type) { 295 | case MEM_TYPE_READ: 296 | read_memory(dev, mem->vals[0], (unsigned char *)&tmp, 4); 297 | printf("*%x is %x\n", mem->vals[0], tmp); 298 | break; 299 | case MEM_TYPE_WRITE: 300 | write_memory(dev, mem->vals[0], mem->vals[1]); 301 | printf("%x write %x\n", mem->vals[0], mem->vals[1]); 302 | break; 303 | case MEM_TYPE_MODIFY: 304 | read_memory(dev, mem->vals[0], (unsigned char *)&tmp, 4); 305 | tmp2 = (tmp & ~mem->vals[1]) | mem->vals[2]; 306 | printf("%x = %x to %x\n", mem->vals[0], tmp, tmp2); 307 | write_memory(dev, mem->vals[0], tmp2); 308 | break; 309 | } 310 | mem = mem->next; 311 | } 312 | } 313 | 314 | static int do_status(struct sdp_dev *dev) 315 | { 316 | unsigned char buf[MAX_PROTOCOL_SIZE]; 317 | int cmd_size; 318 | unsigned int hab_security, status; 319 | int retry = 0; 320 | int err; 321 | 322 | if (!dev->ops->fill_status) 323 | return 0; 324 | cmd_size = dev->ops->fill_status(buf); 325 | if (cmd_size <= 0) 326 | return cmd_size; 327 | err = do_command(dev, buf, cmd_size, 5); 328 | if (err) 329 | return err; 330 | 331 | while (retry < 5) { 332 | err = do_response(dev, 3, &hab_security, false); 333 | if (!err) 334 | break; 335 | 336 | retry++; 337 | } 338 | 339 | if (err) 340 | return err; 341 | 342 | printf("HAB security state: %s (0x%08x)\n", hab_security == HAB_SECMODE_PROD ? 343 | "production mode" : "development mode", hab_security); 344 | 345 | if (dev->mode == MODE_HID) { 346 | err = do_response(dev, 4, &status, false); 347 | if (err) 348 | return err; 349 | } 350 | 351 | return 0; 352 | } 353 | 354 | static int do_data_transfer(struct sdp_dev *dev, unsigned char *buf, int len) 355 | { 356 | int err; 357 | int retry = 10; 358 | int max = dev->max_transfer; 359 | int last_trans; 360 | int cnt; 361 | int transferSize = 0; 362 | 363 | while (retry) { 364 | cnt = get_min(len, max); 365 | err = dev->ops->transfer(dev, 2, buf, cnt, 0, &last_trans); 366 | if (!err) { 367 | if (cnt > last_trans) 368 | cnt = last_trans; 369 | if (!cnt) { 370 | printf("Nothing transferred, err=%i transferSize=%i\n", err, transferSize); 371 | return -EIO; 372 | } 373 | transferSize += cnt; 374 | buf += cnt; 375 | len -= cnt; 376 | if (!len) 377 | return transferSize; 378 | retry = 10; 379 | max = dev->max_transfer; 380 | continue; 381 | } 382 | 383 | printf("report 2 out err=%i, last_trans=%i len=0x%x max=0x%x retry=%i\n", 384 | err, last_trans, len, max, retry); 385 | 386 | if (max >= 16) { 387 | max >>= 1; 388 | max &= ~0x03; 389 | } else { 390 | max <<= 1; 391 | } 392 | 393 | /* Wait a few ms before retrying transfer */ 394 | msleep(10); 395 | retry--; 396 | } 397 | 398 | printf("Giving up\n"); 399 | return err; 400 | } 401 | 402 | static int write_dcd(struct sdp_dev *dev, struct dcd_v2 *dcd) 403 | { 404 | unsigned char buf[MAX_PROTOCOL_SIZE]; 405 | int cmd_size; 406 | int length = BE16(dcd->header.length); 407 | int err; 408 | unsigned transferSize=0; 409 | 410 | if (length > HAB_MAX_DCD_SIZE) { 411 | printf("DCD is too big (%d bytes)\n", length); 412 | return -1; 413 | } 414 | 415 | if (!dev->ops->fill_dl_dcd) 416 | return 0; 417 | cmd_size = dev->ops->fill_dl_dcd(buf, dev->dcd_addr, length); 418 | if (cmd_size <= 0) 419 | return cmd_size; 420 | 421 | printf("loading DCD table @%#x\n", dev->dcd_addr); 422 | err = do_command(dev, buf, cmd_size, 5); 423 | if (err) 424 | return err; 425 | 426 | err = do_data_transfer(dev, (unsigned char *)dcd, length); 427 | if (err < 0) 428 | return err; 429 | transferSize = err; 430 | 431 | printf("\n<<<%i, %i bytes>>>\n", length, transferSize); 432 | if (dev->mode == MODE_HID) { 433 | unsigned int sec, status; 434 | 435 | err = do_response(dev, 3, &sec, false); 436 | if (err) 437 | return err; 438 | 439 | err = do_response(dev, 4, &status, false); 440 | if (err) 441 | return err; 442 | 443 | if (status == 0x128a8a12UL) 444 | printf("succeeded"); 445 | else 446 | printf("failed"); 447 | printf(" (security 0x%08x, status 0x%08x)\n", sec, status); 448 | } else { 449 | do_status(dev); 450 | } 451 | return transferSize; 452 | } 453 | 454 | static int write_dcd_table_ivt(struct sdp_dev *dev, struct dcd_v2 *dcdhdr) 455 | { 456 | int length = BE16(dcdhdr->header.length); 457 | unsigned char *dcd = (unsigned char *)&dcdhdr->write_dcd_command; 458 | unsigned char *dcd_end; 459 | int err = 0; 460 | 461 | printf("main dcd length %x\n", length); 462 | dcd_end = ((unsigned char *)dcdhdr) + length; 463 | 464 | while (dcd < dcd_end) { 465 | unsigned s_length = (dcd[1] << 8) + dcd[2]; 466 | unsigned sub_tag = (dcd[0] << 24) + (dcd[3] & 0x7); 467 | unsigned flags = (dcd[3] & 0xf8); 468 | unsigned char *s_end = dcd + s_length; 469 | printf("sub dcd length %x\n", s_length); 470 | switch(sub_tag) { 471 | /* Write Data Command */ 472 | case 0xcc000004: 473 | if (flags & 0xe8) { 474 | printf("error: Write Data Command with unsupported flags, flags %x.\n", flags); 475 | return -1; 476 | } 477 | dcd += 4; 478 | if (s_end > dcd_end) { 479 | printf("error s_end(%p) > dcd_end(%p)\n", s_end, dcd_end); 480 | return -1; 481 | } 482 | while (dcd < s_end) { 483 | unsigned addr = (dcd[0] << 24) + (dcd[1] << 16) + (dcd[2] << 8) + dcd[3]; 484 | unsigned val = (dcd[4] << 24) + (dcd[5] << 16) + (dcd[6] << 8) + dcd[7]; 485 | dcd += 8; 486 | dbg_printf("write data *0x%08x = 0x%08x\n", addr, val); 487 | err = write_memory(dev, addr, val); 488 | if (err < 0) 489 | return err; 490 | } 491 | break; 492 | /* Check Data Command */ 493 | case 0xcf000004: { 494 | unsigned addr, count, mask, val; 495 | dcd += 4; 496 | addr = (dcd[0] << 24) + (dcd[1] << 16) + (dcd[2] << 8) + dcd[3]; 497 | mask = (dcd[4] << 24) + (dcd[5] << 16) + (dcd[6] << 8) + dcd[7]; 498 | count = 10000; 499 | switch (s_length) { 500 | case 12: 501 | dcd += 8; 502 | break; 503 | case 16: 504 | count = (dcd[8] << 24) + (dcd[9] << 16) + (dcd[10] << 8) + dcd[11]; 505 | dcd += 12; 506 | break; 507 | default: 508 | printf("error s_end(%p) > dcd_end(%p)\n", s_end, dcd_end); 509 | return -1; 510 | } 511 | dbg_printf("Check Data Command, at addr %x, mask %x\n",addr, mask); 512 | while (count) { 513 | val = 0; 514 | err = read_memory(dev, addr, (unsigned char*)&val, 4); 515 | if (err < 0) { 516 | printf("Check Data Command(%x) error(%d) @%x=%x mask %x\n", flags, err, addr, val, mask); 517 | return err; 518 | } 519 | if ((flags == 0x00) && ((val & mask) == 0) ) 520 | break; 521 | else if ((flags == 0x08) && ((val & mask) != mask) ) 522 | break; 523 | else if ((flags == 0x10) && ((val & mask) == mask) ) 524 | break; 525 | else if ((flags == 0x18) && ((val & mask) != 0) ) 526 | break; 527 | else if (flags & 0xe0) { 528 | printf("error: Check Data Command with unsupported flags, flags %x.\n", flags); 529 | return -1; 530 | } 531 | count--; 532 | } 533 | if (!count) 534 | printf("!!!Check Data Command(%x) expired without condition met @%x=%x mask %x\n", flags, addr, val, mask); 535 | else 536 | printf("Check Data Command(%x) success @%x=%x mask %x\n", flags, addr, val, mask); 537 | 538 | break; 539 | } 540 | default: 541 | printf("Unknown sub tag, dcd[0] 0x%2x, dcd[3] 0x%2x\n", dcd[0], dcd[3]); 542 | return -1; 543 | } 544 | } 545 | return err; 546 | } 547 | 548 | static int get_dcd_range_old(struct flash_header_v1 *hdr, 549 | unsigned char *file_start, unsigned cnt, 550 | unsigned char **pstart, unsigned char **pend) 551 | { 552 | unsigned char *dcd_end; 553 | unsigned m_length; 554 | #define cvt_dest_to_src_old (((unsigned char *)&hdr->dcd_ptr) - hdr->dcd_ptr_ptr) 555 | unsigned char* dcd; 556 | unsigned val; 557 | unsigned char* file_end = file_start + cnt; 558 | 559 | if (!hdr->dcd_ptr) { 560 | printf("No dcd table, barker=%x\n", hdr->app_barker); 561 | *pstart = *pend = ((unsigned char *)hdr) + sizeof(struct flash_header_v1); 562 | return 0; //nothing to do 563 | } 564 | dcd = hdr->dcd_ptr + cvt_dest_to_src_old; 565 | if ((dcd < file_start) || ((dcd + 8) > file_end)) { 566 | printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); 567 | return -1; 568 | } 569 | val = (dcd[0] << 0) + (dcd[1] << 8) + (dcd[2] << 16) + (dcd[3] << 24); 570 | if (val != DCD_BARKER) { 571 | printf("Unknown tag\n"); 572 | return -1; 573 | } 574 | dcd += 4; 575 | m_length = (dcd[0] << 0) + (dcd[1] << 8) + (dcd[2] << 16) + (dcd[3] << 24); 576 | printf("main dcd length %x\n", m_length); 577 | dcd += 4; 578 | dcd_end = dcd + m_length; 579 | if (dcd_end > file_end) { 580 | printf("bad dcd length %08x\n", m_length); 581 | return -1; 582 | } 583 | *pstart = dcd; 584 | *pend = dcd_end; 585 | return 0; 586 | } 587 | 588 | static int write_dcd_table_old(struct sdp_dev *dev, struct flash_header_v1 *hdr, unsigned char *file_start, unsigned cnt) 589 | { 590 | unsigned val; 591 | unsigned char *dcd_end; 592 | unsigned char* dcd; 593 | int err = get_dcd_range_old(hdr, file_start, cnt, &dcd, &dcd_end); 594 | if (err < 0) 595 | return err; 596 | 597 | while (dcd < dcd_end) { 598 | unsigned type = (dcd[0] << 0) + (dcd[1] << 8) + (dcd[2] << 16) + (dcd[3] << 24); 599 | unsigned addr = (dcd[4] << 0) + (dcd[5] << 8) + (dcd[6] << 16) + (dcd[7] << 24); 600 | val = (dcd[8] << 0) + (dcd[9] << 8) + (dcd[10] << 16) + (dcd[11] << 24); 601 | dcd += 12; 602 | if (type!=4) { 603 | printf("!!!unknown type=%08x *0x%08x = 0x%08x\n", type, addr, val); 604 | } else { 605 | printf("type=%08x *0x%08x = 0x%08x\n", type, addr, val); 606 | err = write_memory(dev, addr, val); 607 | if (err < 0) 608 | return err; 609 | } 610 | } 611 | return err; 612 | } 613 | 614 | static void diff_long(unsigned char *src1, unsigned char *src2, unsigned cnt, unsigned skip) 615 | { 616 | unsigned char buf[8*9 + 2]; 617 | unsigned *s1 = (unsigned *)src1; 618 | unsigned *s2 = (unsigned *)src2; 619 | unsigned i, j; 620 | while (cnt >= 4) { 621 | unsigned char *p = buf; 622 | unsigned max = get_min(cnt >> 2, 8); 623 | for (i = 0; i < (skip >> 2); i++) { 624 | for (j=0; j < 9; j++) 625 | *p++ = ' '; 626 | } 627 | for (; i < max; i++) { 628 | unsigned s1v = *s1++; 629 | unsigned diff = s1v ^ *s2++; 630 | unsigned c; 631 | *p++ = ' '; 632 | if (i == 4) 633 | *p++ = ' '; 634 | for (j = 0; j < 8; j++) { 635 | unsigned changed = diff & 0xf0000000; 636 | c = ' '; 637 | if (changed) { 638 | if ((s1v & changed) == 0) 639 | c = '^'; 640 | else if ((s1v & changed) == changed) 641 | c = 'v'; 642 | else 643 | c = '-'; 644 | } 645 | *p++ = c; 646 | diff <<= 4; 647 | s1v <<= 4; 648 | } 649 | } 650 | *p = 0; 651 | printf(" %s\n", buf); 652 | cnt -= max << 2; 653 | } 654 | } 655 | 656 | void dump_long(unsigned char *src, unsigned cnt, unsigned addr, unsigned skip) 657 | { 658 | unsigned *p = (unsigned *)src; 659 | int i = skip >> 2; 660 | 661 | while (cnt >= 4) { 662 | printf("%08x:", addr); 663 | while (skip >= 4) { 664 | printf(" "); 665 | skip -= 4; 666 | } 667 | while (cnt >= 4) { 668 | printf((i==4) ? " %08x":" %08x", p[0]); 669 | p++; 670 | cnt -= 4; 671 | addr += 4; 672 | i++; 673 | if (i==8) 674 | break; 675 | } 676 | printf("\n"); 677 | i = 0; 678 | } 679 | } 680 | 681 | void dump_bytes(unsigned char *src, unsigned cnt, unsigned addr) 682 | { 683 | unsigned char *p = src; 684 | int i; 685 | while (cnt >= 16) { 686 | printf("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", addr, 687 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); 688 | p += 16; 689 | cnt -= 16; 690 | addr += 16; 691 | } 692 | if (cnt) { 693 | printf("%08x:", addr); 694 | i = 0; 695 | while (cnt) { 696 | printf(" %02x", p[0]); 697 | p++; 698 | cnt--; 699 | i++; 700 | if (cnt) if (i == 4) { 701 | i = 0; 702 | printf(" "); 703 | } 704 | } 705 | printf("\n"); 706 | } 707 | } 708 | 709 | static void fetch_data(struct load_desc *ld, unsigned foffset, unsigned char **p, unsigned *cnt) 710 | { 711 | unsigned skip = foffset - ld->header_offset; 712 | unsigned buf_cnt = ld->buf_cnt; 713 | 714 | if ((ld->curr->jump_mode >= J_ADDR_HEADER) && 715 | (skip < sizeof(ld->writeable_header))) { 716 | *p = &ld->writeable_header[skip]; 717 | *cnt = sizeof(ld->writeable_header) - skip; 718 | return; 719 | } 720 | skip = foffset - ld->buf_offset; 721 | if (skip >= buf_cnt) { 722 | fseek(ld->xfile, foffset, SEEK_SET); 723 | ld->buf_offset = foffset; 724 | buf_cnt = ld->buf_cnt = fread(ld->buf_start, 1, ld->buf_size, ld->xfile); 725 | skip = 0; 726 | } 727 | if ((foffset < ld->header_offset) && 728 | (ld->header_offset < ld->buf_offset + buf_cnt)) 729 | buf_cnt = ld->header_offset - ld->buf_offset; 730 | *p = &ld->buf_start[skip]; 731 | *cnt = buf_cnt - skip; 732 | } 733 | 734 | static int verify_memory(struct sdp_dev *dev, struct load_desc *ld, unsigned foffset, 735 | unsigned size) 736 | { 737 | int mismatch = 0; 738 | unsigned verified = 0; 739 | unsigned total = size; 740 | unsigned addr = ld->dladdr; 741 | 742 | while (size) { 743 | unsigned char *p; 744 | unsigned cnt; 745 | unsigned char mem_buf[64]; 746 | int align_cnt = foffset & 0x3f; 747 | unsigned offset = foffset; 748 | 749 | fetch_data(ld, foffset, &p, &cnt); 750 | if (align_cnt) { 751 | align_cnt = 64 - align_cnt; 752 | if (cnt > align_cnt) 753 | cnt = align_cnt; 754 | } 755 | if (cnt <= 0) { 756 | printf("Unexpected end of file, size=0x%x, cnt=%i\n", size, cnt); 757 | return -1; 758 | } 759 | if (cnt > size) 760 | cnt = size; 761 | size -= cnt; 762 | foffset += cnt; 763 | while (cnt) { 764 | int ret; 765 | unsigned request = get_min(cnt, sizeof(mem_buf)); 766 | 767 | ret = read_memory(dev, addr, mem_buf, request); 768 | if (ret < 0) { 769 | printf("verified 0x%x of 0x%x before usb error\n", verified, total); 770 | return ret; 771 | } 772 | if (memcmp(p, mem_buf, request)) { 773 | unsigned char * m = mem_buf; 774 | if (!mismatch) 775 | printf("!!!!mismatch\n"); 776 | mismatch++; 777 | 778 | while (request) { 779 | unsigned skip = addr & 0x1f; 780 | unsigned max = 0x20 - skip; 781 | unsigned req = get_min(request, (int)max); 782 | if (memcmp(p, m, req)) { 783 | dump_long(p, req, offset, skip); 784 | dump_long(m, req, addr, skip); 785 | diff_long(p, m, req, skip); 786 | } 787 | p += req; 788 | m+= req; 789 | offset += req; 790 | addr += req; 791 | cnt -= req; 792 | request -= req; 793 | } 794 | if (mismatch >= 5) 795 | return -1; 796 | } 797 | p += request; 798 | offset += request; 799 | addr += request; 800 | cnt -= request; 801 | verified += request; 802 | } 803 | } 804 | if (!mismatch) 805 | printf("Verify success\n"); 806 | return mismatch ? -1 : 0; 807 | } 808 | 809 | static int load_file(struct sdp_dev *dev, struct load_desc *ld, unsigned foffset, 810 | unsigned fsize, unsigned char type) 811 | { 812 | unsigned char buf[MAX_PROTOCOL_SIZE]; 813 | int cmd_size; 814 | int err; 815 | unsigned transferSize=0; 816 | unsigned char *p; 817 | unsigned cnt; 818 | unsigned char combine_buf[1024]; 819 | 820 | if (!dev->no_hid_cmd) { 821 | if (!dev->ops->fill_write_file) 822 | return 0; 823 | cmd_size = dev->ops->fill_write_file(buf, ld->dladdr, fsize, type); 824 | if (cmd_size <= 0) 825 | return cmd_size; 826 | dbg_printf("%s:cmd_size=%x\n", __func__, cmd_size); 827 | dbg_dump_long(buf, cmd_size, 0, 0); 828 | do_command(dev, buf, cmd_size, 5); 829 | } 830 | 831 | if (dev->mode == MODE_BULK) { 832 | unsigned int sec; 833 | err = do_response(dev, 3, &sec, false); 834 | if (err) 835 | return err; 836 | } 837 | 838 | while (transferSize < fsize) { 839 | unsigned remaining = (fsize-transferSize); 840 | 841 | fetch_data(ld, foffset, &p, &cnt); 842 | /* Avoid short packets, they may signal end of transfer */ 843 | if (cnt < sizeof(combine_buf)) { 844 | unsigned next_cnt; 845 | 846 | memcpy(combine_buf, p, cnt); 847 | while (cnt < sizeof(combine_buf)) { 848 | fetch_data(ld, foffset + cnt, &p, &next_cnt); 849 | if (!next_cnt) 850 | break; 851 | if (next_cnt > sizeof(combine_buf) - cnt) 852 | next_cnt = sizeof(combine_buf) - cnt; 853 | memcpy(&combine_buf[cnt], p, next_cnt); 854 | cnt += next_cnt; 855 | } 856 | p = combine_buf; 857 | } else { 858 | cnt &= -sizeof(combine_buf); /* round down to multiple of 1024 */ 859 | } 860 | if (cnt > remaining) 861 | cnt = remaining; 862 | if (!cnt) 863 | break; 864 | if (cnt > dev->max_transfer) 865 | cnt = dev->max_transfer; 866 | dbg_printf("%s:foffset=%x, cnt=%x, remaining=%x\n", __func__, foffset, cnt, remaining); 867 | dbg_dump_long(p, cnt, ld->dladdr + transferSize, 0); 868 | err = do_data_transfer(dev, p, cnt); 869 | if (err < 0) { 870 | printf("%s:foffset=%x, cnt=%x, remaining=%x, err=%d\n", __func__, foffset, cnt, remaining, err); 871 | return err; 872 | } 873 | if (!err) 874 | break; 875 | transferSize += err; 876 | foffset += err; 877 | } 878 | printf("\n<<<%i, %i bytes>>>\n", fsize, transferSize); 879 | if (dev->mode == MODE_HID) { 880 | unsigned int sec, status; 881 | 882 | err = do_response(dev, 3, &sec, false); 883 | if (err) 884 | return err; 885 | 886 | err = do_response(dev, 4, &status, false); 887 | if (err) 888 | return err; 889 | 890 | if (status == 0x88888888UL) 891 | printf("succeeded"); 892 | else 893 | printf("failed"); 894 | printf(" (security 0x%08x, status 0x%08x)\n", sec, status); 895 | } else if (dev->mode == MODE_BULK) { 896 | do_status(dev); 897 | } 898 | return transferSize; 899 | } 900 | 901 | static int jump(struct sdp_dev *dev, unsigned int header_addr) 902 | { 903 | unsigned char buf[MAX_PROTOCOL_SIZE]; 904 | int cmd_size; 905 | int err; 906 | unsigned int sec, status; 907 | 908 | if (!dev->ops->fill_jump) 909 | return 0; 910 | cmd_size = dev->ops->fill_jump(buf, header_addr); 911 | if (cmd_size <= 0) 912 | return cmd_size; 913 | printf("jumping to 0x%08x\n", header_addr); 914 | err = do_command(dev, buf, cmd_size, 5); 915 | if (err) 916 | return err; 917 | 918 | err = do_response(dev, 3, &sec, false); 919 | if (err) 920 | return err; 921 | 922 | err = do_response(dev, 4, &status, true); 923 | /* 924 | * Documentation says: "This report is sent by device only in case of 925 | * an error jumping to the given address..." 926 | * If Report 4 fails, this is a good sign 927 | * If Report 4 responds, there has been something gone wrong... 928 | */ 929 | if (!err) { 930 | printf("failed (security 0x%08x, status 0x%08x)\n", sec, status); 931 | return err; 932 | } 933 | 934 | return 0; 935 | } 936 | 937 | static int load_file_from_desc(struct sdp_dev *dev, struct sdp_work *curr, 938 | struct load_desc *ld) 939 | { 940 | int ret; 941 | unsigned file_base; 942 | unsigned char type; 943 | unsigned skip = 0; 944 | unsigned fsize; 945 | unsigned transferSize=0; 946 | unsigned cnt; 947 | 948 | if (!ld->dladdr) { 949 | printf("\nunknown load address\n"); 950 | return -3; 951 | } 952 | 953 | type = (curr->plug || curr->jump_mode) ? FT_APP : FT_LOAD_ONLY; 954 | if (dev->mode == MODE_BULK && type == FT_APP) { 955 | /* 956 | * There is no jump command. boot ROM requires the download 957 | * to start at header address 958 | */ 959 | ld->dladdr = ld->header_addr; 960 | } 961 | if (ld->verify) { 962 | if ((type == FT_APP) && (dev->mode != MODE_HID)) { 963 | type = FT_LOAD_ONLY; 964 | ld->verify = 2; 965 | } 966 | } 967 | file_base = ld->header_addr - ld->header_offset; 968 | if (file_base > ld->dladdr) { 969 | ld->max_length -= (file_base - ld->dladdr); 970 | ld->dladdr = file_base; 971 | } 972 | dbg_printf("skip=%x cnt=%x dladdr=%x file_base=%x fsize=%x max_length=%x\n", skip, ld->buf_cnt, ld->dladdr, file_base, ld->fsize, ld->max_length); 973 | skip = ld->dladdr - file_base; 974 | fsize = ld->fsize; 975 | if (skip > fsize) { 976 | printf("skip(0x%08x) > fsize(0x%08x) file_base=0x%08x, header_offset=0x%x\n", 977 | skip, fsize, file_base, ld->header_offset); 978 | ret = -4; 979 | goto cleanup; 980 | } 981 | fsize -= skip; 982 | if (fsize > ld->max_length) 983 | fsize = ld->max_length; 984 | printf("\nloading binary file(%s) to %08x, skip=%x, fsize=%x type=%x\n", curr->filename, ld->dladdr, skip, fsize, type); 985 | 986 | ret = load_file(dev, ld, skip, fsize, type); 987 | if (ret < 0) 988 | goto cleanup; 989 | transferSize = ret; 990 | 991 | if (ld->verify) { 992 | ret = verify_memory(dev, ld, skip, fsize); 993 | if (ret < 0) 994 | goto cleanup; 995 | if (ld->verify == 2) { 996 | cnt = fsize; 997 | if (cnt > 64) 998 | cnt = 64; 999 | /* 1000 | * This will set the right header address 1001 | * for bulk mode, which has no jump command 1002 | */ 1003 | ret = load_file(dev, ld, ld->header_offset, cnt, 1004 | FT_APP); 1005 | if (ret < 0) 1006 | goto cleanup; 1007 | 1008 | } 1009 | } 1010 | 1011 | ret = (fsize <= transferSize) ? 0 : -16; 1012 | cleanup: 1013 | return ret; 1014 | } 1015 | 1016 | static int is_header(struct sdp_dev *dev, unsigned char *p) 1017 | { 1018 | switch (dev->header_type) { 1019 | case HDR_MX51: 1020 | { 1021 | struct flash_header_v1 *hdr = (struct flash_header_v1 *)p; 1022 | if (hdr->app_barker == 0xb1) 1023 | return 1; 1024 | break; 1025 | } 1026 | case HDR_MX53: 1027 | { 1028 | struct flash_header_v2 *hdr = (struct flash_header_v2 *)p; 1029 | struct ivt_header *ivt = &hdr->header; 1030 | if (ivt->tag == IVT_HEADER_TAG && 1031 | (ivt->version == IVT_VERSION || ivt->version == IVT_VERSION_IMX8M)) 1032 | return 1; 1033 | } 1034 | case HDR_UBOOT: 1035 | { 1036 | image_header_t *image = (image_header_t *)p; 1037 | if (BE32(image->ih_magic) == IH_MAGIC) 1038 | return 1; 1039 | } 1040 | } 1041 | return 0; 1042 | } 1043 | 1044 | static void init_header(struct sdp_dev *dev, struct load_desc *ld) 1045 | { 1046 | struct sdp_work *curr = ld->curr; 1047 | 1048 | memset(ld->writeable_header, 0, sizeof(ld->writeable_header)); 1049 | 1050 | switch (dev->header_type) { 1051 | case HDR_MX51: 1052 | { 1053 | struct flash_header_v1 *hdr = (struct flash_header_v1 *)ld->writeable_header; 1054 | unsigned char *p = (unsigned char *)(hdr + 1); 1055 | unsigned size; 1056 | unsigned extra_space = ((sizeof(struct flash_header_v1) + 4 - 1) | 0x3f) + 1; 1057 | 1058 | ld->max_length += extra_space; 1059 | size = ld->max_length; 1060 | 1061 | hdr->app_start_addr = curr->jump_addr; 1062 | hdr->app_barker = APP_BARKER; 1063 | hdr->dcd_ptr_ptr = ld->header_addr + offsetof(struct flash_header_v1, dcd_ptr); 1064 | hdr->app_dest_ptr = ld->dladdr; 1065 | 1066 | *p++ = (unsigned char)size; 1067 | size >>= 8; 1068 | *p++ = (unsigned char)size; 1069 | size >>= 8; 1070 | *p++ = (unsigned char)size; 1071 | size >>= 8; 1072 | *p = (unsigned char)size; 1073 | break; 1074 | } 1075 | case HDR_MX53: 1076 | { 1077 | struct flash_header_v2 *hdr = (struct flash_header_v2 *)ld->writeable_header; 1078 | struct boot_data *bd = (struct boot_data *)(hdr+1); 1079 | unsigned extra_space = ((sizeof(struct flash_header_v2) + sizeof(struct boot_data) - 1) | 0x3f) + 1; 1080 | 1081 | hdr->header.tag = IVT_HEADER_TAG; 1082 | hdr->header.length = BE16(sizeof(*hdr)); 1083 | hdr->header.version = IVT_VERSION; 1084 | hdr->start_addr = curr->jump_addr; 1085 | hdr->boot_data_ptr = ld->header_addr + sizeof(*hdr); 1086 | hdr->self_ptr = ld->header_addr; 1087 | bd->dest = ld->dladdr; 1088 | ld->max_length += extra_space; 1089 | bd->image_len = ld->max_length; 1090 | break; 1091 | } 1092 | case HDR_UBOOT: 1093 | { 1094 | break; 1095 | } 1096 | } 1097 | } 1098 | 1099 | /* 1100 | * Apply/load DCD table for v1 and v2 flash headers 1101 | * 1102 | * Returns 0 if successful or if there was no DCD table to download 1103 | * Returns -1 if the DCD table is invalid 1104 | */ 1105 | static int perform_dcd(struct sdp_dev *dev, unsigned char *p, unsigned char *file_start, unsigned cnt) 1106 | { 1107 | int ret = 0; 1108 | switch (dev->header_type) { 1109 | case HDR_MX51: 1110 | { 1111 | struct flash_header_v1 *hdr = (struct flash_header_v1 *)p; 1112 | ret = write_dcd_table_old(dev, hdr, file_start, cnt); 1113 | dbg_printf("dcd_ptr=0x%08x\n", hdr->dcd_ptr); 1114 | if (ret < 0) 1115 | return ret; 1116 | break; 1117 | } 1118 | case HDR_MX53: 1119 | { 1120 | #define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self_ptr) 1121 | struct flash_header_v2 *hdr = (struct flash_header_v2 *)p; 1122 | unsigned char* file_end = file_start + cnt; 1123 | unsigned char *dcd_end, *dcd_start; 1124 | struct dcd_v2 *dcd; 1125 | int length; 1126 | 1127 | if (!hdr->dcd_ptr) { 1128 | printf("No DCD table\n"); 1129 | return 0; //nothing to do 1130 | } 1131 | 1132 | dcd_start = hdr->dcd_ptr + cvt_dest_to_src; 1133 | if ((dcd_start < file_start) || (dcd_start + 4) > file_end) { 1134 | printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); 1135 | return -1; 1136 | } 1137 | 1138 | dcd = (struct dcd_v2 *)dcd_start; 1139 | if (dcd->header.tag != DCD_HEADER_TAG || 1140 | dcd->header.version != DCD_VERSION) { 1141 | printf("Unknown DCD header tag/version\n"); 1142 | return -1; 1143 | } 1144 | 1145 | length = BE16(dcd->header.length); 1146 | if (length == 0) { 1147 | printf("No DCD table, skip\n"); 1148 | return 0; 1149 | } 1150 | 1151 | /* Check whether DCD length is longer than file */ 1152 | dcd_end = ((unsigned char *)dcd) + length; 1153 | if (dcd_end > file_end) { 1154 | printf("Bad dcd length 0x%08x\n", length); 1155 | return -1; 1156 | } 1157 | 1158 | if (dev->mode == MODE_HID) { 1159 | ret = write_dcd(dev, dcd); 1160 | } else { 1161 | // For processors that don't support the WRITE_DCD command (i.MX5x) 1162 | ret = write_dcd_table_ivt(dev, dcd); 1163 | } 1164 | dbg_printf("dcd_ptr=0x%08x\n", hdr->dcd_ptr); 1165 | if (ret < 0) 1166 | return ret; 1167 | break; 1168 | } 1169 | } 1170 | return 0; 1171 | } 1172 | 1173 | static int clear_dcd_ptr(struct sdp_dev *dev, unsigned char *p) 1174 | { 1175 | switch (dev->header_type) { 1176 | case HDR_MX51: 1177 | { 1178 | struct flash_header_v1 *hdr = (struct flash_header_v1 *)p; 1179 | if (hdr->dcd_ptr) { 1180 | printf("clear dcd_ptr=0x%08x\n", hdr->dcd_ptr); 1181 | hdr->dcd_ptr = 0; 1182 | } 1183 | break; 1184 | } 1185 | case HDR_MX53: 1186 | { 1187 | struct flash_header_v2 *hdr = (struct flash_header_v2 *)p; 1188 | if (hdr->dcd_ptr) { 1189 | printf("clear dcd_ptr=0x%08x\n", hdr->dcd_ptr); 1190 | hdr->dcd_ptr = 0; 1191 | } 1192 | break; 1193 | } 1194 | } 1195 | return 0; 1196 | } 1197 | 1198 | static int get_dl_start(struct sdp_dev *dev, unsigned char *p, 1199 | struct load_desc *ld, unsigned int clear_boot_data) 1200 | { 1201 | unsigned char* file_end = ld->buf_start + ld->buf_cnt; 1202 | switch (dev->header_type) { 1203 | case HDR_MX51: 1204 | { 1205 | struct flash_header_v1 *hdr = (struct flash_header_v1 *)p; 1206 | unsigned char *dcd_end; 1207 | unsigned char* dcd; 1208 | int err = get_dcd_range_old(hdr, ld->buf_start, ld->buf_cnt, &dcd, &dcd_end); 1209 | ld->dladdr = hdr->app_dest_ptr; 1210 | ld->header_addr = hdr->dcd_ptr_ptr - offsetof(struct flash_header_v1, dcd_ptr); 1211 | ld->plugin = 0; 1212 | if (err >= 0) { 1213 | ld->max_length = dcd_end[0] | (dcd_end[1] << 8) | (dcd_end[2] << 16) | (dcd_end[3] << 24); 1214 | } 1215 | break; 1216 | } 1217 | case HDR_MX53: 1218 | { 1219 | struct boot_data *bd; 1220 | unsigned char* p1; 1221 | uint32_t *bd1; 1222 | unsigned offset; 1223 | struct flash_header_v2 *hdr = (struct flash_header_v2 *)p; 1224 | 1225 | ld->dladdr = hdr->self_ptr; 1226 | ld->header_addr = hdr->self_ptr; 1227 | p1 = (hdr->boot_data_ptr + cvt_dest_to_src); 1228 | 1229 | if ((p1 < ld->buf_start) || ((p1 + 4) > file_end)) { 1230 | printf("bad boot_data_ptr %08x\n", hdr->boot_data_ptr); 1231 | return -1; 1232 | } 1233 | bd = (struct boot_data *)p1; 1234 | ld->dladdr = bd->dest; 1235 | ld->max_length = bd->image_len; 1236 | ld->plugin = bd->plugin; 1237 | offset = ((unsigned char *)&bd->plugin) - p; 1238 | if (offset <= sizeof(ld->writeable_header) - 4) { 1239 | bd1 = (uint32_t *)(ld->writeable_header + offset); 1240 | *bd1 = 0; 1241 | } else { 1242 | printf("Can't clear plugin flag\n"); 1243 | } 1244 | if (clear_boot_data) { 1245 | printf("Setting boot_data_ptr to 0\n"); 1246 | hdr->boot_data_ptr = 0; 1247 | } 1248 | break; 1249 | } 1250 | case HDR_UBOOT: 1251 | { 1252 | image_header_t *hdr = (image_header_t *)p; 1253 | ld->dladdr = BE32(hdr->ih_load) - sizeof(image_header_t); 1254 | ld->header_addr = ld->dladdr; 1255 | } 1256 | } 1257 | return 0; 1258 | } 1259 | 1260 | static unsigned offset_search_list[] = {0, 0x400, 0x8400}; 1261 | 1262 | static int process_header(struct sdp_dev *dev, struct sdp_work *curr, 1263 | struct load_desc *ld) 1264 | { 1265 | int ret; 1266 | unsigned header_max = 0x800 + curr->load_skip; 1267 | unsigned header_inc = 0; 1268 | unsigned search_index = 0; 1269 | int header_cnt = 0; 1270 | unsigned char *p; 1271 | int hdmi_ivt = 0; 1272 | int found = 0; 1273 | 1274 | while (1) { 1275 | if (header_inc) { 1276 | ld->header_offset += header_inc; 1277 | if (ld->header_offset >= header_max) 1278 | break; 1279 | } else { 1280 | if (search_index >= ARRAY_SIZE(offset_search_list)) 1281 | break; 1282 | ld->header_offset = curr->load_skip + offset_search_list[search_index++]; 1283 | } 1284 | if ((ld->header_offset < ld->buf_offset) || 1285 | (ld->header_offset - ld->buf_offset + 32 > ld->buf_cnt)) { 1286 | fseek(ld->xfile, ld->header_offset, SEEK_SET); 1287 | ld->buf_offset = ld->header_offset; 1288 | ld->buf_cnt = fread(ld->buf_start, 1, ld->buf_size, ld->xfile); 1289 | if (ld->buf_cnt < 32) 1290 | break; 1291 | } 1292 | p = ld->buf_start + ld->header_offset - ld->buf_offset; 1293 | if (!is_header(dev, p)) 1294 | continue; 1295 | dbg_printf("%s: header_offset=%x, %02x%02x%02x%02x\n", __func__, 1296 | ld->header_offset, p[3], p[2], p[1], p[0]); 1297 | 1298 | memcpy(ld->writeable_header, p, 1299 | sizeof(ld->writeable_header)); 1300 | ret = get_dl_start(dev, p, ld, curr->clear_boot_data); 1301 | if (ret < 0) { 1302 | printf("!!get_dl_start returned %i\n", ret); 1303 | return ret; 1304 | } 1305 | if (curr->dcd) { 1306 | ret = perform_dcd(dev, p, ld->buf_start, ld->buf_cnt); 1307 | #if 1 1308 | clear_dcd_ptr(dev, ld->writeable_header); 1309 | #endif 1310 | if (ret < 0) { 1311 | printf("!!perform_dcd returned %i\n", ret); 1312 | return ret; 1313 | } 1314 | curr->dcd = 0; 1315 | if ((!curr->jump_mode) && (!curr->plug)) { 1316 | printf("!!dcd done, nothing else requested\n"); 1317 | return 0; 1318 | } 1319 | } 1320 | if (curr->clear_dcd) { 1321 | ret = clear_dcd_ptr(dev, ld->writeable_header); 1322 | if (ret < 0) { 1323 | printf("!!clear_dcd returned %i\n", ret); 1324 | return ret; 1325 | } 1326 | } 1327 | if (ld->plugin & HDMI_IMAGE_FLAG_MASK) { 1328 | if (!hdmi_ivt) { 1329 | hdmi_ivt++; 1330 | header_inc = 0x1c00 - 0x1000 + ld->max_length; 1331 | header_max = ld->header_offset + header_inc + 0x400; 1332 | continue; 1333 | } 1334 | header_inc = ld->dladdr - ld->header_addr + ld->max_length + 0x400; 1335 | header_max = ld->header_offset + header_inc + 0x400; 1336 | continue; 1337 | } 1338 | if ((ld->plugin & PLUGIN_IMAGE_FLAG_MASK) && (!curr->plug) && (!header_cnt)) { 1339 | header_cnt++; 1340 | header_max = ld->header_offset + ld->max_length + 0x400; 1341 | printf("header_max=%x\n", header_max); 1342 | header_inc = 4; 1343 | } else { 1344 | if (!ld->plugin) 1345 | curr->plug = 0; 1346 | if (curr->jump_mode == J_HEADER2) { 1347 | if (!found) { 1348 | found++; 1349 | ld->header_offset += ld->dladdr - ld->header_addr + ld->max_length; 1350 | header_inc = 0x400; 1351 | header_max = ld->header_offset + 0x400 * 128; 1352 | continue; 1353 | } 1354 | } 1355 | return 0; 1356 | } 1357 | } 1358 | printf("header not found %x:%x, %x\n", ld->header_offset, *(unsigned int *)p, ld->buf_cnt); 1359 | return -EINVAL; 1360 | } 1361 | 1362 | static int do_download(struct sdp_dev *dev, struct sdp_work *curr, int verify) 1363 | { 1364 | int ret; 1365 | struct load_desc ld = {0}; 1366 | 1367 | print_sdp_work(curr); 1368 | ld.curr = curr; 1369 | ld.verify = verify; 1370 | ld.xfile = fopen(curr->filename, "rb" ); 1371 | if (!ld.xfile) { 1372 | printf("\nerror, can not open input file: %s\n", curr->filename); 1373 | return -5; 1374 | } 1375 | ld.buf_size = (1024*16); 1376 | ld.buf_start = malloc(ld.buf_size); 1377 | if (!ld.buf_start) { 1378 | printf("\nerror, out of memory\n"); 1379 | ret = -2; 1380 | goto cleanup; 1381 | } 1382 | ld.fsize = get_file_size(ld.xfile); 1383 | ld.max_length = ld.fsize; 1384 | if (ld.max_length > curr->load_skip) { 1385 | ld.max_length -= curr->load_skip; 1386 | } else { 1387 | printf("error, skipping past end of file\n"); 1388 | ret = -1; 1389 | goto cleanup; 1390 | } 1391 | if (curr->load_size && (ld.max_length > curr->load_size)) 1392 | ld.max_length = curr->load_size; 1393 | if (curr->dcd || curr->clear_dcd || curr->plug || (curr->jump_mode >= J_HEADER)) { 1394 | ret = process_header(dev, curr, &ld); 1395 | if (ret < 0) 1396 | goto cleanup; 1397 | if ((!curr->jump_mode) && (!curr->plug)) { 1398 | /* nothing else requested */ 1399 | ret = 0; 1400 | goto cleanup; 1401 | } 1402 | } else { 1403 | ld.dladdr = curr->load_addr; 1404 | ld.header_addr = ld.dladdr + ld.max_length; 1405 | ld.header_offset = curr->load_skip + ld.max_length; 1406 | if (curr->jump_mode == J_ADDR_HEADER) { 1407 | unsigned cnt = ld.max_length; 1408 | 1409 | init_header(dev, &ld); 1410 | /* If the header is at EOF, fsize needs increased */ 1411 | ld.fsize += ld.max_length - cnt; 1412 | dbg_dump_long((unsigned char *)ld.writeable_header, ld.max_length - cnt, ld.header_addr, 0); 1413 | } else if (curr->jump_mode == J_ADDR_DIRECT) { 1414 | ld.header_addr = curr->jump_addr; 1415 | ld.header_offset = 0; 1416 | } 1417 | } 1418 | if (ld.plugin && (!curr->plug)) { 1419 | printf("Only plugin header found\n"); 1420 | ret = -1; 1421 | goto cleanup; 1422 | } 1423 | ret = load_file_from_desc(dev, curr, &ld); 1424 | /* 1425 | * Any command will initiate jump for bulk devices, no need to 1426 | * explicitly send a jump command 1427 | */ 1428 | if (dev->mode == MODE_HID && (curr->plug || curr->jump_mode)) { 1429 | ret = jump(dev, ld.header_addr); 1430 | if (ret < 0) 1431 | goto cleanup; 1432 | } 1433 | 1434 | cleanup: 1435 | fclose(ld.xfile); 1436 | free(ld.buf_start); 1437 | return ret; 1438 | } 1439 | 1440 | int do_work(struct sdp_dev *p_id, struct sdp_work **work, int verify) 1441 | { 1442 | struct sdp_work *curr = *work; 1443 | int err = 0; 1444 | 1445 | err = do_status(p_id); 1446 | if (err) { 1447 | fprintf(stderr, "status failed\n"); 1448 | return err; 1449 | } 1450 | 1451 | while (curr) { 1452 | /* Do current job */ 1453 | if (curr->mem) 1454 | perform_mem_work(p_id, curr->mem); 1455 | if (curr->filename[0]) 1456 | err = do_download(p_id, curr, verify); 1457 | if (err) { 1458 | fprintf(stderr, "do_download failed, err=%d\n", err); 1459 | do_status(p_id); 1460 | break; 1461 | } 1462 | 1463 | /* Check if more work is to do... */ 1464 | if (!curr->next) { 1465 | /* 1466 | * If only one job, but with a plug-in is specified 1467 | * reexecute the same job, but this time download the 1468 | * image. This allows to specify a single file with 1469 | * plugin and image, and imx_usb will download & run 1470 | * the plugin first and then the image. 1471 | * NOTE: If the file does not contain a plugin, 1472 | * DoIRomDownload->process_header will set curr->plug 1473 | * to 0, so we won't download the same image twice... 1474 | */ 1475 | if (curr->plug) { 1476 | curr->plug = 0; 1477 | } else { 1478 | curr = NULL; 1479 | break; 1480 | } 1481 | } else { 1482 | curr = curr->next; 1483 | } 1484 | 1485 | /* 1486 | * Check if device is still here, otherwise return 1487 | * with work (retry) 1488 | */ 1489 | err = do_status(p_id); 1490 | if (err < 0) { 1491 | err = 0; 1492 | break; 1493 | } 1494 | } 1495 | 1496 | *work = curr; 1497 | 1498 | return err; 1499 | } 1500 | 1501 | -------------------------------------------------------------------------------- /imx_sdp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_sdp: 3 | * Interface of the Serial Download Protocol (SDP) for i.MX/Vybrid 4 | * series processors. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library 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 GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef __IMX_SDP_H__ 22 | #define __IMX_SDP_H__ 23 | 24 | #include 25 | 26 | struct ram_area { 27 | unsigned start; 28 | unsigned size; 29 | }; 30 | 31 | struct mem_work { 32 | struct mem_work *next; 33 | unsigned type; 34 | #define MEM_TYPE_READ 0 35 | #define MEM_TYPE_WRITE 1 36 | #define MEM_TYPE_MODIFY 2 37 | unsigned vals[3]; 38 | }; 39 | 40 | struct sdp_work; 41 | struct sdp_work { 42 | struct sdp_work *next; 43 | struct mem_work *mem; 44 | char filename[256]; 45 | unsigned char dcd; 46 | unsigned char clear_dcd; //means clear dcd_ptr 47 | unsigned char clear_boot_data; //means clear boot data ptr 48 | unsigned char plug; 49 | #define J_ADDR_DIRECT 1 50 | #define J_ADDR_HEADER 2 51 | #define J_HEADER 3 52 | #define J_HEADER2 4 53 | unsigned char jump_mode; 54 | unsigned load_addr; 55 | unsigned jump_addr; 56 | unsigned load_size; 57 | unsigned load_skip; 58 | }; 59 | 60 | struct sdp_dev; 61 | 62 | struct protocol_ops { 63 | int (*fill_read_reg)(unsigned char *buf, unsigned addr, unsigned cnt); 64 | int (*fill_write_reg)(unsigned char *buf, unsigned addr, unsigned cnt); 65 | int (*fill_status)(unsigned char *buf); 66 | int (*fill_dl_dcd)(unsigned char *buf, unsigned dcd_addr, int length); 67 | int (*fill_write_file)(unsigned char *buf, unsigned dladdr, unsigned fsize, unsigned char type); 68 | int (*fill_jump)(unsigned char *buf, unsigned header_addr); 69 | int (*get_cmd_addr_cnt)(unsigned char *buf, uint16_t *cmd, uint32_t *addr, uint32_t *cnt); 70 | /* 71 | * dev - SDP devce (this structure) 72 | * report - HID Report 73 | * p - pointer to buffer 74 | * size - size of buffer (used for send and USB receive length) 75 | * expected - the expected amount of data (used for UART receive) 76 | * last_trans - the actually transfered bytes 77 | */ 78 | int (*transfer)(struct sdp_dev *dev, int report, unsigned char *p, unsigned int size, 79 | unsigned int expected, int* last_trans); 80 | }; 81 | 82 | struct sdp_dev { 83 | char name[64]; 84 | unsigned short max_transfer; 85 | #define MODE_HID 0 86 | #define MODE_BULK 1 87 | #define MODE_SDPS 2 88 | unsigned char mode; 89 | #define HDR_NONE 0 90 | #define HDR_MX51 1 91 | #define HDR_MX53 2 92 | #define HDR_UBOOT 3 93 | unsigned char header_type; 94 | unsigned dcd_addr; 95 | struct ram_area ram[8]; 96 | struct sdp_work *work; 97 | struct protocol_ops *ops; 98 | void *priv; 99 | unsigned char use_ep1; 100 | unsigned char no_hid_cmd; 101 | }; 102 | 103 | #define HAB_SECMODE_PROD 0x12343412 104 | #define HAB_SECMODE_DEV 0x56787856 105 | 106 | /* 107 | * Section 8.7.2 of the i.MX6DQ/UL/SoloX RM: 108 | * The maximum size of the DCD limited to 1768 bytes. 109 | */ 110 | #define HAB_MAX_DCD_SIZE 1768 111 | #define MAX_PROTOCOL_SIZE 32 112 | 113 | #define CMD_INVAL 0x00 114 | #define CMD_READ_REG 0x0101 115 | #define CMD_WRITE_REG 0x0202 116 | #define CMD_WRITE_FILE 0x0404 117 | #define CMD_ERROR_STATUS 0x0505 118 | #define CMD_WRITE_DCD 0x0a0a 119 | #define CMD_JUMP_ADDRESS 0x0b0b 120 | 121 | void dump_long(unsigned char *src, unsigned cnt, unsigned addr, unsigned skip); 122 | void dump_bytes(unsigned char *src, unsigned cnt, unsigned addr); 123 | 124 | int do_work(struct sdp_dev *p_id, struct sdp_work **work, int verify); 125 | 126 | #endif /* __IMX_SDP_H__ */ 127 | -------------------------------------------------------------------------------- /imx_sdp_simulation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_sdp_simulation: 3 | * A simple client side implementation of the Serial Download Protocol (SDP) 4 | * for testing. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library 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 GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "portable.h" 26 | #include "imx_sdp.h" 27 | #include "image.h" 28 | 29 | struct sim_memory *head; 30 | struct sim_memory { 31 | struct sim_memory *next; 32 | unsigned int addr; 33 | unsigned int len; 34 | unsigned char *buf; 35 | int offset; 36 | }; 37 | 38 | int do_simulation(struct sdp_dev *dev, int report, unsigned char *p, unsigned int count, 39 | unsigned int expected, int* last_trans) 40 | { 41 | static unsigned char cur_cmd[MAX_PROTOCOL_SIZE]; 42 | static struct sim_memory *cur_mem; 43 | unsigned int offset; 44 | unsigned mem_addr; 45 | int cmd_size; 46 | uint16_t cmd; 47 | uint32_t addr; 48 | uint32_t cnt; 49 | 50 | if (!dev->ops->get_cmd_addr_cnt) 51 | return -EINVAL; 52 | switch (report) { 53 | case 1: 54 | cmd_size = dev->ops->get_cmd_addr_cnt(p, &cmd, &addr, &cnt); 55 | /* Copy command */ 56 | memcpy(cur_cmd, p, cmd_size); 57 | printf("cmd: %04x\n", cmd); 58 | switch (cmd) { 59 | case CMD_WRITE_FILE: 60 | case CMD_WRITE_DCD: 61 | if (!head) { 62 | cur_mem = head = malloc(sizeof(*cur_mem)); 63 | } else { 64 | cur_mem = head; 65 | while (cur_mem->next) 66 | cur_mem = cur_mem->next; 67 | 68 | cur_mem->next = malloc(sizeof(*cur_mem)); 69 | cur_mem = cur_mem->next; 70 | } 71 | 72 | cur_mem->next = NULL; 73 | cur_mem->addr = addr; 74 | cur_mem->len = cnt; 75 | cur_mem->buf = malloc(cur_mem->len); 76 | cur_mem->offset = 0; 77 | break; 78 | case CMD_READ_REG: 79 | cur_mem = head; 80 | while (cur_mem) { 81 | if (cur_mem->addr <= addr && 82 | cur_mem->addr + cur_mem->len > addr) { 83 | break; 84 | } 85 | 86 | cur_mem = cur_mem->next; 87 | } 88 | break; 89 | } 90 | break; 91 | case 2: 92 | /* Data phase, ignore */ 93 | memcpy(cur_mem->buf + cur_mem->offset, p, count); 94 | cur_mem->offset += count; 95 | break; 96 | case 3: 97 | /* Simulate security configuration open */ 98 | *((unsigned int *)p) = BE32(0x56787856); 99 | break; 100 | case 4: 101 | dev->ops->get_cmd_addr_cnt(cur_cmd, &cmd, &addr, &cnt); 102 | /* Return sensible status */ 103 | switch (cmd) { 104 | case CMD_WRITE_FILE: 105 | *((unsigned int *)p) = BE32(0x88888888UL); 106 | break; 107 | case CMD_WRITE_DCD: 108 | *((unsigned int *)p) = BE32(0x128a8a12UL); 109 | break; 110 | case CMD_READ_REG: 111 | cur_mem = head; 112 | mem_addr = addr; 113 | while (cur_mem) { 114 | if (cur_mem->addr <= mem_addr && 115 | cur_mem->addr + cur_mem->len > mem_addr) { 116 | if ((mem_addr + count) > (cur_mem->addr + cur_mem->len)) 117 | return -EIO; 118 | break; 119 | } 120 | cur_mem = cur_mem->next; 121 | } 122 | if (!cur_mem) 123 | return -EIO; 124 | offset = mem_addr - cur_mem->addr; 125 | memcpy(p, cur_mem->buf + offset, cnt); 126 | break; 127 | case CMD_JUMP_ADDRESS: 128 | /* A successful jump returns nothing on Report 4 */ 129 | return -7; 130 | } 131 | break; 132 | default: 133 | break; 134 | } 135 | 136 | return 0; 137 | } 138 | 139 | void do_simulation_cleanup(void) 140 | { 141 | struct sim_memory *cur_mem = head; 142 | 143 | while (cur_mem) { 144 | struct sim_memory *free_mem = cur_mem; 145 | cur_mem = cur_mem->next; 146 | free(free_mem); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /imx_sdp_simulation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_sdp_simulation: 3 | * A simple client side implementation of the Serial Download Protocol (SDP) 4 | * for testing. 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library 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 GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | 21 | #ifndef __IMX_SDP_SIMULATION_H__ 22 | #define __IMX_SDP_SIMULATION_H__ 23 | 24 | int do_simulation(struct sdp_dev *dev, int report, unsigned char *p, unsigned int cnt, 25 | unsigned int expected, int* last_trans); 26 | void do_simulation_cleanup(void); 27 | 28 | #endif /* __IMX_SDP_SIMULATION_H__ */ 29 | -------------------------------------------------------------------------------- /imx_uart.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_uart: 3 | * 4 | * Program to download and execute an image over the serial boot protocol 5 | * on i.MX series processors. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library 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 GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | #ifndef WIN32 35 | #include 36 | 37 | #include 38 | #endif 39 | 40 | #include "portable.h" 41 | #include "imx_sdp.h" 42 | #include "imx_loader.h" 43 | #include "imx_loader_config.h" 44 | 45 | extern int debugmode; 46 | 47 | #define get_min(a, b) (((a) < (b)) ? (a) : (b)) 48 | 49 | int transfer_uart(struct sdp_dev *dev, int report, unsigned char *p, unsigned size, 50 | unsigned int expected, int* last_trans) 51 | { 52 | int fd = *(int *)dev->priv; 53 | 54 | if (report < 3) { 55 | *last_trans = write(fd, p, size); 56 | } else { 57 | // Read... 58 | int ret; 59 | *last_trans = 0; 60 | while (*last_trans < (int)expected) 61 | { 62 | ret = read(fd, p, expected - *last_trans); 63 | if (ret < 0) 64 | return ret; 65 | 66 | // err is transfered bytes... 67 | *last_trans += ret; 68 | p += ret; 69 | } 70 | } 71 | 72 | return 0; 73 | } 74 | 75 | #ifndef WIN32 76 | int uart_connect(int *uart_fd, char const *tty, int usertscts, int associate, struct termios *orig) 77 | #else 78 | int uart_connect(int *uart_fd, char const *tty, int usertscts, int associate, DCB* orig) 79 | #endif 80 | { 81 | int err = 0, count = 0; 82 | int retry = 10; 83 | #ifndef WIN32 84 | int flags = O_RDWR | O_NOCTTY | O_SYNC; 85 | struct termios key; 86 | #else 87 | int flags = O_RDWR | _O_BINARY; 88 | DCB dcb; 89 | COMMTIMEOUTS timeouts; 90 | HANDLE handle; 91 | #endif 92 | char magic[] = { 0x23, 0x45, 0x45, 0x23 }; 93 | char magic_response[4]; 94 | char *buf; 95 | #ifndef WIN32 96 | memset(&key,0,sizeof(key)); 97 | #endif 98 | memset(&magic_response,0,sizeof(magic_response)); 99 | 100 | *uart_fd = open(tty, flags); 101 | if (*uart_fd < 0) { 102 | printf("tty %s\n", tty); 103 | fprintf(stdout, "open() failed: %s\n", strerror(errno)); 104 | return *uart_fd; 105 | } 106 | 107 | #ifndef WIN32 108 | // Get original terminal settings 109 | err = tcgetattr(*uart_fd, orig); 110 | 111 | // 8 data bits 112 | key.c_cflag |= CS8; 113 | key.c_cflag |= CLOCAL | CREAD; 114 | if (usertscts) 115 | key.c_cflag |= CRTSCTS; 116 | key.c_cflag |= B115200; 117 | 118 | // Enable blocking read, 0.5s timeout... 119 | key.c_lflag &= ~ICANON; // Set non-canonical mode 120 | key.c_cc[VTIME] = 5; 121 | 122 | err = tcsetattr(*uart_fd, TCSANOW, &key); 123 | if (err < 0) { 124 | fprintf(stdout, "tcsetattr() failed: %s\n", strerror(errno)); 125 | close(*uart_fd); 126 | return err; 127 | } 128 | 129 | err = tcflush(*uart_fd, TCIOFLUSH); 130 | #else 131 | handle=(HANDLE)_get_osfhandle(*uart_fd); 132 | 133 | orig->DCBlength=sizeof(DCB); 134 | 135 | GetCommState(handle,orig); 136 | 137 | memset(&dcb,0,sizeof(DCB)); 138 | 139 | dcb.DCBlength=sizeof(DCB); 140 | dcb.fBinary=TRUE; 141 | dcb.fParity=FALSE; 142 | dcb.BaudRate=CBR_115200; 143 | dcb.ByteSize=8; 144 | 145 | if (usertscts) 146 | { 147 | dcb.fRtsControl=RTS_CONTROL_ENABLE; 148 | dcb.fOutxCtsFlow=TRUE; 149 | } 150 | 151 | if (!SetCommState(handle,&dcb)) 152 | { 153 | fprintf(stdout, "SetCommState() failed: %d\n", GetLastError()); 154 | close(*uart_fd); 155 | return err; 156 | } 157 | 158 | memset(&timeouts,0,sizeof(COMMTIMEOUTS)); 159 | 160 | timeouts.ReadIntervalTimeout=MAXDWORD; 161 | timeouts.ReadTotalTimeoutMultiplier=MAXDWORD; 162 | timeouts.ReadTotalTimeoutConstant=500; 163 | 164 | if (!SetCommTimeouts(handle,&timeouts)) 165 | { 166 | fprintf(stdout, "SetCommTimeouts() failed: %d\n", GetLastError()); 167 | close(*uart_fd); 168 | return err; 169 | } 170 | 171 | if (!PurgeComm(handle,PURGE_TXABORT|PURGE_RXABORT)) 172 | { 173 | fprintf(stdout, "PurgeComm() failed: %d\n", GetLastError()); 174 | close(*uart_fd); 175 | return err; 176 | } 177 | 178 | 179 | #endif 180 | if (!associate) 181 | return err; 182 | 183 | // Association phase, send and receive 0x23454523 184 | printf("starting associating phase"); 185 | while(retry--) { 186 | #ifndef WIN32 187 | // Flush again before retrying 188 | err = tcflush(*uart_fd, TCIOFLUSH); 189 | #endif 190 | 191 | write(*uart_fd, magic, sizeof(magic)); 192 | 193 | buf = magic_response; 194 | 195 | count = 0; 196 | while (count < 4) { 197 | err = read(*uart_fd, buf, 4 - count); 198 | 199 | /* read timeout.. */ 200 | if (err <= 0) 201 | break; 202 | 203 | count += err; 204 | buf += err; 205 | } 206 | 207 | if (!memcmp(magic, magic_response, sizeof(magic_response))) 208 | break; 209 | 210 | printf("."); 211 | fflush(stdout); 212 | #ifndef WIN32 213 | err = tcflush(*uart_fd, TCIOFLUSH); 214 | #endif 215 | msleep(1000); 216 | } 217 | 218 | printf("\n"); 219 | fflush(stdout); 220 | 221 | if (!retry) { 222 | fprintf(stderr, "associating phase failed, make sure the device" 223 | " is in recovery mode\n"); 224 | close(*uart_fd); 225 | return -2; 226 | } 227 | 228 | if (memcmp(magic, magic_response, sizeof(magic_response))) { 229 | fprintf(stderr, "magic missmatch, response was 0x%08x\n", 230 | *(uint32_t *)magic_response); 231 | close(*uart_fd); 232 | return -3; 233 | } 234 | 235 | fprintf(stderr, "association phase succeeded, response was 0x%08x\n", 236 | *(uint32_t *)magic_response); 237 | 238 | return 0; 239 | } 240 | 241 | #ifndef WIN32 242 | void uart_close(int *uart_fd, struct termios *orig) 243 | #else 244 | void uart_close(int *uart_fd, DCB* orig) 245 | #endif 246 | { 247 | #ifndef WIN32 248 | int err; 249 | 250 | // Restore original terminal settings 251 | err = tcsetattr(*uart_fd, TCSAFLUSH, orig); 252 | if (err < 0) 253 | fprintf(stdout, "tcsetattr() failed: %s\n", strerror(errno)); 254 | #else 255 | HANDLE handle; 256 | 257 | handle=(HANDLE)_get_osfhandle(*uart_fd); 258 | 259 | SetCommState(handle,orig); 260 | #endif 261 | 262 | close(*uart_fd); 263 | } 264 | 265 | void print_usage(void) 266 | { 267 | printf("Usage: imx_uart [OPTIONS...] UART CONFIG [JOBS...]\n" 268 | #ifndef WIN32 269 | " e.g. imx_uart -n /dev/ttyUSB0 vybrid_usb_work.conf u-boot.imx\n" 270 | #else 271 | " e.g. imx_uart -n COM1: vybrid_uart_work.conf eboot.img\n" 272 | #endif 273 | "Load data on target connected to UART using serial download protocol as\n" 274 | "configured in CONFIG file.\n" 275 | "\n" 276 | "Where OPTIONS are\n" 277 | " -h --help Show this help\n" 278 | " -v --verify Verify downloaded data\n" 279 | " -n --no-rtscts Do not use RTS/CTS flow control\n" 280 | " Default is to use RTS/CTS, Vybrid requires them\n" 281 | " -N --no-association Do not do serial Association Phase\n" 282 | " -d --debugmode Enable debug logs\n" 283 | "\n" 284 | "And where [JOBS...] are\n" 285 | " FILE [-lLOADADDR] [-sSIZE] ...\n" 286 | "Multiple jobs can be configured. The first job is treated special, load\n" 287 | "address, jump address, and length are read from the IVT header. If no job\n" 288 | "is specified, the jobs defined in the target specific configuration file\n" 289 | "is being used.\n"); 290 | } 291 | 292 | int parse_opts(int argc, char * const *argv, char const **ttyfile, 293 | char const **conffile, int *verify, int *usertscts, 294 | int *associate, struct sdp_work **cmd_head) 295 | { 296 | char c; 297 | *conffile = NULL; 298 | *ttyfile = NULL; 299 | 300 | static struct option long_options[] = { 301 | {"help", no_argument, 0, 'h' }, 302 | {"verify", no_argument, 0, 'v' }, 303 | {"version", no_argument, 0, 'V' }, 304 | {"debugmode", no_argument, 0, 'd' }, 305 | {"no-rtscts", no_argument, 0, 'n' }, 306 | {"no-association", no_argument, 0, 'N' }, 307 | {0, 0, 0, 0 }, 308 | }; 309 | 310 | while ((c = getopt_long(argc, argv, "+hdvVnN", long_options, NULL)) != -1) { 311 | switch (c) 312 | { 313 | case 'h': 314 | case '?': 315 | print_usage(); 316 | return 1; 317 | case 'd': 318 | debugmode = 1; /* global extern */ 319 | break; 320 | case 'n': 321 | *usertscts = 0; 322 | break; 323 | case 'N': 324 | *associate = 0; 325 | break; 326 | case 'v': 327 | *verify = 1; 328 | break; 329 | case 'V': 330 | printf("imx_usb " IMX_LOADER_VERSION "\n"); 331 | return 1; 332 | } 333 | } 334 | 335 | // Options parsed, get mandatory arguments... 336 | if (optind >= argc) { 337 | fprintf(stderr, "non optional argument UART is missing\n"); 338 | return -1; 339 | } 340 | 341 | *ttyfile = argv[optind]; 342 | optind++; 343 | 344 | if (optind >= argc) { 345 | fprintf(stderr, "non optional argument CONFIG is missing\n"); 346 | return -1; 347 | } 348 | 349 | *conffile = argv[optind]; 350 | optind++; 351 | 352 | if (optind < argc) { 353 | // Parse optional job arguments... 354 | *cmd_head = parse_cmd_args(argc - optind, &argv[optind]); 355 | } 356 | 357 | return 0; 358 | } 359 | 360 | void sdps_init_ops(struct sdp_dev *dev) 361 | { 362 | printf("sdps not supported\n"); 363 | exit(1); 364 | } 365 | 366 | #define ARRAY_SIZE(w) sizeof(w)/sizeof(w[0]) 367 | 368 | int main(int argc, char * const argv[]) 369 | { 370 | struct sdp_dev *p_id; 371 | int err = 0; 372 | int verify = 0; 373 | int usertscts = 1; 374 | int associate = 1; 375 | int uart_fd; 376 | struct sdp_work *curr; 377 | char const *conf; 378 | char const *ttyfile; 379 | char const *conffilepath; 380 | char const *conffile; 381 | char const *basepath; 382 | #ifndef WIN32 383 | struct termios orig; 384 | #else 385 | DCB orig; 386 | #endif 387 | 388 | curr=NULL; 389 | 390 | err = parse_opts(argc, argv, &ttyfile, &conffilepath, &verify, 391 | &usertscts, &associate, &curr); 392 | 393 | if (err < 0) 394 | return EXIT_FAILURE; 395 | else if (err > 0) 396 | return EXIT_SUCCESS; 397 | 398 | // Get machine specific configuration file.. 399 | if ((conffile = strrchr(conffilepath, PATH_SEPARATOR)) == NULL) { 400 | // Only a file was given as configuration 401 | basepath = get_base_path(argv[0]); 402 | conffile = conffilepath; 403 | } else { 404 | // A whole path is given as configuration 405 | basepath = get_base_path(conffilepath); 406 | conffile++; // Filename starts after slash 407 | } 408 | 409 | conf = conf_file_name(conffile, basepath, get_global_conf_path()); 410 | if (conf == NULL) 411 | return -1; 412 | 413 | p_id = parse_conf(conf); 414 | if (!p_id) 415 | return -1; 416 | 417 | // Open UART and start associating phase... 418 | err = uart_connect(&uart_fd, ttyfile, usertscts, associate, &orig); 419 | 420 | if (err < 0) 421 | return EXIT_FAILURE; 422 | 423 | p_id->ops->transfer = &transfer_uart; 424 | 425 | // UART private pointer is TTY file descriptor... 426 | p_id->priv = &uart_fd; 427 | 428 | // By default, use work from config file... 429 | if (curr == NULL) 430 | curr = p_id->work; 431 | 432 | err = do_work(p_id, &curr, verify); 433 | dbg_printf("do_work finished with err=%d, curr=%p\n", err, curr); 434 | 435 | uart_close(&uart_fd, &orig); 436 | return err; 437 | } 438 | -------------------------------------------------------------------------------- /imx_usb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * imx_usb: 3 | * 4 | * Program to download and execute an image over the USB boot protocol 5 | * on i.MX series processors. 6 | * 7 | * This library is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU Lesser General Public 9 | * License as published by the Free Software Foundation; either 10 | * version 2.1 of the License, or (at your option) any later version. 11 | * 12 | * This library 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 GNU 15 | * Lesser General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public 18 | * License along with this library; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef __FreeBSD__ 33 | #include 34 | #else 35 | #include 36 | #endif 37 | 38 | #include "portable.h" 39 | #include "imx_sdp.h" 40 | #include "imx_sdp_simulation.h" 41 | #include "imx_loader.h" 42 | #include "imx_loader_config.h" 43 | 44 | struct mach_id; 45 | struct mach_id { 46 | struct mach_id *next; 47 | struct mach_id *nextbatch; 48 | unsigned short vid; 49 | unsigned short pid; 50 | char file_name[256]; 51 | }; 52 | 53 | static void print_devs(libusb_device **devs) 54 | { 55 | int j, k, l; 56 | int i = 0; 57 | for (;;) { 58 | struct libusb_device_descriptor desc; 59 | struct libusb_config_descriptor *config; 60 | libusb_device *dev = devs[i++]; 61 | if (!dev) 62 | break; 63 | int r = libusb_get_device_descriptor(dev, &desc); 64 | if (r < 0) { 65 | fprintf(stderr, "failed to get device descriptor"); 66 | return; 67 | } 68 | 69 | libusb_get_config_descriptor(dev, 0, &config); 70 | 71 | printf("%04x:%04x (bus %d, device %d) bNumInterfaces:%i\n", 72 | desc.idVendor, desc.idProduct, 73 | libusb_get_bus_number(dev), libusb_get_device_address(dev), 74 | config->bNumInterfaces); 75 | for (j = 0; j < config->bNumInterfaces; j++) { 76 | const struct libusb_interface *inter = &config->interface[j]; 77 | printf(" alternates:%i\n", inter->num_altsetting); 78 | for (k = 0; k < inter->num_altsetting; k++) { 79 | const struct libusb_interface_descriptor *interdesc = &inter->altsetting[k]; 80 | printf(" Interface Number: %i, Number of endpoints: %i\n", 81 | interdesc->bInterfaceNumber, interdesc->bNumEndpoints); 82 | for (l = 0; l < interdesc->bNumEndpoints; l++) { 83 | const struct libusb_endpoint_descriptor *epdesc = &interdesc->endpoint[l]; 84 | printf(" Descriptor Type: %x, EP Address: %i, wMaxPacketSize: %i\n", 85 | epdesc->bDescriptorType, epdesc->bEndpointAddress, epdesc->wMaxPacketSize); 86 | } 87 | } 88 | } 89 | libusb_free_config_descriptor(config); 90 | } 91 | } 92 | 93 | static struct mach_id *parse_imx_mach(const char **pp) 94 | { 95 | unsigned short vid; 96 | unsigned short pid; 97 | struct mach_id *curr = NULL; 98 | const char *p = *pp; 99 | 100 | while (*p==' ') p++; 101 | if (p[0] == '#') 102 | return NULL; 103 | vid = get_val(&p, 16); 104 | if (p[0] != ':') { 105 | printf("Syntax error(missing ':'): %s [%s]\n", p, *pp); 106 | return NULL; 107 | } 108 | p++; 109 | pid = get_val(&p, 16); 110 | if (p[0] != ',') { 111 | printf("Syntax error(missing ','): %s [%s]\n", p, *pp); 112 | return NULL; 113 | } 114 | p++; 115 | while (*p==' ') p++; 116 | if (!(vid && pid)) { 117 | printf("vid/pid cannot be 0: %s [%s]\n", p, *pp); 118 | return NULL; 119 | } 120 | curr = (struct mach_id *)malloc(sizeof(struct mach_id)); 121 | curr->next = NULL; 122 | curr->nextbatch = NULL; 123 | curr->vid = vid; 124 | curr->pid = pid; 125 | p = move_string(curr->file_name, p, sizeof(curr->file_name) - 1); 126 | 127 | *pp = p; 128 | return curr; 129 | } 130 | 131 | /* 132 | * Parse USB specific machine configuration 133 | */ 134 | static struct mach_id *parse_imx_conf(char const *filename) 135 | { 136 | char line[512]; 137 | struct mach_id *head = NULL; 138 | struct mach_id *tail = NULL; 139 | struct mach_id *curr = NULL; 140 | const char *p; 141 | 142 | FILE* xfile = fopen(filename, "rb" ); 143 | if (!xfile) { 144 | printf("Could not open file: %s\n", filename); 145 | return NULL; 146 | } 147 | 148 | while (fgets(line, sizeof(line), xfile) != NULL) { 149 | p = line; 150 | curr = parse_imx_mach(&p); 151 | if (!curr) 152 | continue; 153 | 154 | if (!head) 155 | head = curr; 156 | if (tail) 157 | tail->next = curr; 158 | tail = curr; 159 | printf("vid=0x%04x pid=0x%04x file_name=%s\n", curr->vid, curr->pid, curr->file_name); 160 | 161 | while (p[0] == ',') { 162 | p++; 163 | // Second machine in batch... 164 | curr->nextbatch = parse_imx_mach(&p); 165 | curr = curr->nextbatch; 166 | printf("-> vid=0x%04x pid=0x%04x file_name=%s\n", curr->vid, curr->pid, curr->file_name); 167 | } 168 | } 169 | 170 | fclose(xfile); 171 | return head; 172 | } 173 | 174 | static struct mach_id * imx_device(unsigned short vid, unsigned short pid, struct mach_id *p) 175 | { 176 | // printf("%s: vid=%x pid=%x\n", __func__, vid, pid); 177 | while (p) { 178 | if ((p->vid == vid) && (p->pid == pid)) 179 | return p; 180 | p = p->next; 181 | } 182 | return NULL; 183 | } 184 | 185 | 186 | static libusb_device *find_imx_dev(libusb_device **devs, struct mach_id **pp_id, struct mach_id *list, int bus, int address) 187 | { 188 | int i = 0; 189 | struct mach_id *p; 190 | for (;;) { 191 | struct libusb_device_descriptor desc; 192 | libusb_device *dev = devs[i++]; 193 | if (!dev) 194 | break; 195 | if ((bus >= 0 && libusb_get_bus_number(dev) != bus) || 196 | (address >= 0 && libusb_get_device_address(dev) != address)) 197 | continue; 198 | int r = libusb_get_device_descriptor(dev, &desc); 199 | if (r < 0) { 200 | fprintf(stderr, "failed to get device descriptor"); 201 | return NULL; 202 | } 203 | p = imx_device(desc.idVendor, desc.idProduct, list); 204 | if (p) { 205 | *pp_id = p; 206 | return dev; 207 | } 208 | } 209 | fprintf(stderr, "no matching USB device found\n"); 210 | *pp_id = NULL; 211 | return NULL; 212 | } 213 | 214 | // HID Class-Specific Requests values. See section 7.2 of the HID specifications 215 | #define HID_GET_REPORT 0x01 216 | #define HID_GET_IDLE 0x02 217 | #define HID_GET_PROTOCOL 0x03 218 | #define HID_SET_REPORT 0x09 219 | #define HID_SET_IDLE 0x0A 220 | #define HID_SET_PROTOCOL 0x0B 221 | #define HID_REPORT_TYPE_INPUT 0x01 222 | #define HID_REPORT_TYPE_OUTPUT 0x02 223 | #define HID_REPORT_TYPE_FEATURE 0x03 224 | #define CTRL_IN LIBUSB_ENDPOINT_IN |LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE 225 | #define CTRL_OUT LIBUSB_ENDPOINT_OUT|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE 226 | 227 | #define EP_IN 0x80 228 | 229 | 230 | /* 231 | * For HID class drivers, 4 reports are used to implement 232 | * Serial Download protocol(SDP) 233 | * Report 1 (control out endpoint) 16 byte SDP comand 234 | * (total of 17 bytes with 1st byte report id of 0x01 235 | * Report 2 (control out endpoint) data associated with report 1 commands 236 | * (max size of 1025 with 1st byte of 0x02) 237 | * Report 3 (interrupt in endpoint) HAB security state 238 | * (max size of 5 bytes with 1st byte of 0x03) 239 | * (0x12343412 production) 240 | * (0x56787856 engineering) 241 | * Report 4 (interrupt in endpoint) date associated with report 1 commands 242 | * (max size of 65 bytes with 1st byte of 0x04) 243 | * 244 | */ 245 | static int transfer_hid(struct sdp_dev *dev, int report, unsigned char *p, unsigned int cnt, 246 | unsigned int expected, int* last_trans) 247 | { 248 | unsigned char tmp[1028]; 249 | int err; 250 | struct libusb_device_handle *h = (struct libusb_device_handle *)dev->priv; 251 | 252 | if (cnt > dev->max_transfer) 253 | cnt = dev->max_transfer; 254 | dbg_printf("report=%i, cnt=%x\n", report, cnt); 255 | #ifdef DEBUG 256 | if (report < 3) 257 | dump_bytes(p, cnt, 0); 258 | #endif 259 | tmp[0] = (unsigned char)report; 260 | if (report < 3) { 261 | memcpy(&tmp[1], p, cnt); 262 | if (report == 2) 263 | cnt = dev->max_transfer; 264 | if (!dev->use_ep1) { 265 | err = libusb_control_transfer(h, 266 | CTRL_OUT, 267 | HID_SET_REPORT, 268 | (HID_REPORT_TYPE_OUTPUT << 8) | report, 269 | 0, 270 | tmp, cnt + 1, 1000); 271 | *last_trans = (err > 0) ? err - 1 : 0; 272 | } else { 273 | *last_trans = 0; 274 | err = libusb_interrupt_transfer(h, 1, 275 | tmp, cnt + 1, last_trans, 1000); 276 | if (err < 0) { 277 | printf("%s: read error(%i)(%s), cnt=%i, last_trans=%i, %02x %02x %02x %02x\n", 278 | __func__, err, libusb_strerror(err), 279 | cnt, *last_trans, p[0], p[1], p[2], p[3]); 280 | } 281 | if (*last_trans) 282 | *last_trans -= 1; 283 | dbg_printf("%s: last_trans=%d\n", __func__, *last_trans); 284 | } 285 | if (err > 0) 286 | err = 0; 287 | } else { 288 | *last_trans = 0; 289 | memset(&tmp[1], 0, cnt); 290 | err = libusb_interrupt_transfer(h, 1 + EP_IN, tmp, cnt + 1, last_trans, 1000); 291 | dbg_printf("libusb_interrupt_transfer, err=%d, trans=%d\n", err, 292 | *last_trans); 293 | if (err >= 0) { 294 | if (tmp[0] == (unsigned char)report) { 295 | if (*last_trans > 1) { 296 | *last_trans -= 1; 297 | memcpy(p, &tmp[1], *last_trans); 298 | } 299 | } else { 300 | printf("Unexpected report %i err=%i, cnt=%i, last_trans=%i, %02x %02x %02x %02x\n", 301 | tmp[0], err, cnt, *last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); 302 | err = 0; 303 | } 304 | } 305 | } 306 | #ifdef DEBUG 307 | if (report >= 3) 308 | dump_bytes(p, cnt, 0); 309 | #endif 310 | return err; 311 | } 312 | 313 | /* 314 | * For Bulk class drivers, the device is configured as 315 | * EP0IN, EP0OUT control transfer 316 | * EP1OUT - bulk out 317 | * (max packet size of 512 bytes) 318 | * EP2IN - bulk in 319 | * (max packet size of 512 bytes) 320 | */ 321 | 322 | static int transfer_bulk(struct sdp_dev *dev, int report, unsigned char *p, unsigned int cnt, 323 | unsigned int expected, int* last_trans) 324 | { 325 | int err; 326 | struct libusb_device_handle *h = (struct libusb_device_handle *)dev->priv; 327 | if (cnt > dev->max_transfer) 328 | cnt = dev->max_transfer; 329 | #ifdef DEBUG 330 | printf("report=%i\n", report); 331 | if (report < 3) 332 | dump_bytes(p, cnt, 0); 333 | #endif 334 | *last_trans = 0; 335 | err = libusb_bulk_transfer(h, (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); 336 | 337 | #ifdef DEBUG 338 | if (report >= 3) 339 | dump_bytes(p, cnt, 0); 340 | #endif 341 | return err; 342 | } 343 | 344 | int transfer_simulation(struct sdp_dev *dev, int report, unsigned char *p, unsigned int cnt, 345 | unsigned int expected, int* last_trans) 346 | { 347 | int err = 0; 348 | if (cnt > dev->max_transfer) 349 | cnt = dev->max_transfer; 350 | 351 | printf("report=%i, cnt=%d\n", report, cnt); 352 | switch (report) { 353 | case 1: 354 | case 2: 355 | dump_bytes(p, cnt, 0); 356 | break; 357 | case 3: 358 | case 4: 359 | memset(p, 0, cnt); 360 | break; 361 | } 362 | 363 | err = do_simulation(dev, report, p, cnt, expected, last_trans); 364 | 365 | /* On error, do not transmit anything */ 366 | if (err) 367 | *last_trans = 0; 368 | else 369 | *last_trans = cnt; 370 | 371 | return err; 372 | } 373 | 374 | #define ARRAY_SIZE(w) sizeof(w)/sizeof(w[0]) 375 | void print_usage(void) 376 | { 377 | printf("Usage: imx_usb [OPTIONS...] [JOBS...]\n" 378 | " e.g. imx_usb -v u-boot.imx\n" 379 | "Load data on target connected to USB using serial download protocol. The target\n" 380 | "type is detected using USB ID, an appropriate configuration file.\n" 381 | "\n" 382 | "Where OPTIONS are\n" 383 | " -h --help Show this help\n" 384 | " -v --verify Verify downloaded data\n" 385 | " -d --debugmode Enable debug logs\n" 386 | " -c --configdir=DIR Reading configuration directory from non standard\n" 387 | " directory.\n" 388 | " -b --bus=NUM Filter bus number.\n" 389 | " -D --device=NUM Filter device address.\n" 390 | " -S --sim=VID:PID Simulate a device of VID:PID\n" 391 | "\n" 392 | "And where [JOBS...] are\n" 393 | " FILE [-lLOADADDR] [-sSIZE] ...\n" 394 | "Multiple jobs can be configured. The first job is treated special, load\n" 395 | "address, jump address, and length are read from the IVT header. If no job\n" 396 | "is specified, the jobs defined in the target specific configuration file\n" 397 | "is being used.\n"); 398 | } 399 | 400 | int do_simulation_dev(char const *base_path, char const *conf_path, 401 | struct mach_id *list, int verify, struct sdp_work *cmd_head, 402 | char const *vidpid) 403 | { 404 | int err; 405 | struct mach_id *mach; 406 | struct sdp_dev *p_id; 407 | struct sdp_work *curr = NULL; 408 | char const *conf; 409 | unsigned short vid, pid; 410 | 411 | sscanf(vidpid, "%hx:%hx", &vid, &pid); 412 | printf("Simulating with vid=0x%04hx pid=0x%04hx\n", vid, pid); 413 | 414 | mach = imx_device(vid, pid, list); 415 | if (!mach) { 416 | fprintf(stderr, "Could not find device vid=0x%04x pid=0x%04x\n", 417 | vid, pid); 418 | return -1; 419 | } 420 | 421 | // Get machine specific configuration file.. 422 | conf = conf_file_name(mach->file_name, base_path, conf_path); 423 | if (conf == NULL) 424 | return -1; 425 | 426 | p_id = parse_conf(conf); 427 | if (!p_id) 428 | return -1; 429 | 430 | p_id->ops->transfer = &transfer_simulation; 431 | curr = p_id->work; 432 | 433 | // Prefer work from command line, disable batch mode... 434 | if (cmd_head) { 435 | curr = cmd_head; 436 | mach->nextbatch = NULL; 437 | } 438 | 439 | err = do_work(p_id, &curr, verify); 440 | dbg_printf("do_work finished with err=%d, curr=%p\n", err, curr); 441 | 442 | do_simulation_cleanup(); 443 | 444 | return err; 445 | } 446 | 447 | int do_autodetect_dev(char const *base_path, char const *conf_path, 448 | struct mach_id *list, int verify, struct sdp_work *cmd_head, 449 | int bus, int address) 450 | { 451 | struct sdp_dev *p_id; 452 | struct mach_id *mach; 453 | libusb_device **devs; 454 | libusb_device *dev; 455 | int err = 0; 456 | ssize_t cnt; 457 | struct sdp_work *curr = NULL; 458 | libusb_device_handle *h = NULL; 459 | char const *conf; 460 | int retry; 461 | int config = 0; 462 | 463 | err = libusb_init(NULL); 464 | if (err < 0) 465 | return err; 466 | 467 | cnt = libusb_get_device_list(NULL, &devs); 468 | if (cnt < 0) { 469 | err = LIBUSB_ERROR_NO_DEVICE; 470 | goto out_deinit_usb; 471 | } 472 | 473 | if (debugmode) 474 | print_devs(devs); 475 | dev = find_imx_dev(devs, &mach, list, bus, address); 476 | if (!dev) { 477 | err = LIBUSB_ERROR_NO_DEVICE; 478 | goto out_deinit_usb; 479 | } 480 | 481 | while (mach) { 482 | // Get machine specific configuration file.. 483 | conf = conf_file_name(mach->file_name, base_path, conf_path); 484 | if (conf == NULL) { 485 | err = LIBUSB_ERROR_OTHER; 486 | break; 487 | } 488 | 489 | p_id = parse_conf(conf); 490 | if (!p_id) { 491 | err = LIBUSB_ERROR_OTHER; 492 | break; 493 | } 494 | 495 | p_id->ops->transfer = (p_id->mode == MODE_BULK) ? &transfer_bulk : 496 | &transfer_hid; 497 | curr = p_id->work; 498 | 499 | // Prefer work from command line, disable batch mode... 500 | if (cmd_head) { 501 | curr = cmd_head; 502 | mach->nextbatch = NULL; 503 | } 504 | 505 | if (curr == NULL) { 506 | fprintf(stderr, "no job found\n"); 507 | err = LIBUSB_ERROR_OTHER; 508 | break; 509 | } 510 | 511 | // Wait for device... 512 | printf("Trying to open device vid=0x%04x pid=0x%04x", mach->vid, mach->pid); 513 | fflush(stdout); 514 | for (retry = 0; retry < 50; retry++) { 515 | h = NULL; 516 | err = libusb_open(dev, &h); 517 | if (h) 518 | break; 519 | 520 | msleep(500); 521 | if (retry % 2) 522 | printf("."); 523 | fflush(stdout); 524 | } 525 | printf("\n"); 526 | if (!h) { 527 | err = LIBUSB_ERROR_NO_DEVICE; 528 | fprintf(stderr, "Could not open device vid=0x%04x pid=0x%04x\n", 529 | mach->vid, mach->pid); 530 | break; 531 | } 532 | 533 | // USB private pointer is libusb device handle... 534 | p_id->priv = h; 535 | 536 | libusb_get_configuration(h, &config); 537 | dbg_printf("bConfigurationValue = 0x%x\n", config); 538 | 539 | if (libusb_kernel_driver_active(h, 0)) 540 | libusb_detach_kernel_driver(h, 0); 541 | 542 | err = libusb_claim_interface(h, 0); 543 | if (err) { 544 | fprintf(stderr, "claim interface failed\n"); 545 | break; 546 | } 547 | printf("Interface 0 claimed\n"); 548 | 549 | err = do_work(p_id, &curr, verify); 550 | dbg_printf("do_work finished with err=%d, curr=%p\n", err, curr); 551 | 552 | libusb_release_interface(h, 0); 553 | libusb_close(h); 554 | 555 | if (err) 556 | break; 557 | 558 | // We might have to retry the same machine in case of plugin... 559 | if (!curr) 560 | mach = mach->nextbatch; 561 | } 562 | libusb_free_device_list(devs, 1); 563 | 564 | out_deinit_usb: 565 | libusb_exit(NULL); 566 | 567 | return err; 568 | } 569 | 570 | static const struct option long_options[] = { 571 | {"help", no_argument, 0, 'h' }, 572 | {"debugmode", no_argument, 0, 'd' }, 573 | {"verify", no_argument, 0, 'v' }, 574 | {"version", no_argument, 0, 'V' }, 575 | {"configdir", required_argument, 0, 'c' }, 576 | {"bus", required_argument, 0, 'b' }, 577 | {"device", required_argument, 0, 'D' }, 578 | {"sim", required_argument, 0, 'S' }, 579 | {0, 0, 0, 0 }, 580 | }; 581 | 582 | int main(int argc, char * const argv[]) 583 | { 584 | int err, c; 585 | int verify = 0; 586 | struct sdp_work *cmd_head = NULL; 587 | char const *conf; 588 | char const *base_path = get_base_path(argv[0]); 589 | char const *conf_path = get_global_conf_path(); 590 | char const *sim_vidpid = NULL; 591 | int bus = -1; 592 | int address = -1; 593 | 594 | while ((c = getopt_long(argc, argv, "+hdvVc:b:D:S:", long_options, NULL)) != -1) { 595 | switch (c) 596 | { 597 | case 'h': 598 | case '?': 599 | print_usage(); 600 | return EXIT_SUCCESS; 601 | case 'd': 602 | debugmode = 1; /* global extern */ 603 | break; 604 | case 'v': 605 | verify = 1; 606 | break; 607 | case 'V': 608 | printf("imx_usb " IMX_LOADER_VERSION "\n"); 609 | return EXIT_SUCCESS; 610 | case 'c': 611 | conf_path = optarg; 612 | break; 613 | case 'b': 614 | bus = atoi(optarg); 615 | break; 616 | case 'D': 617 | address = atoi(optarg); 618 | break; 619 | case 'S': 620 | sim_vidpid = optarg; 621 | break; 622 | } 623 | } 624 | 625 | if (optind < argc) { 626 | // Parse optional job arguments... 627 | cmd_head = parse_cmd_args(argc - optind, &argv[optind]); 628 | } 629 | 630 | // Get list of machines... 631 | conf = conf_file_name("imx_usb.conf", base_path, conf_path); 632 | if (conf == NULL) 633 | return EXIT_FAILURE; 634 | 635 | struct mach_id *list = parse_imx_conf(conf); 636 | if (!list) 637 | return EXIT_FAILURE; 638 | 639 | if (sim_vidpid) 640 | err = do_simulation_dev(base_path, conf_path, list, verify, 641 | cmd_head, sim_vidpid); 642 | else 643 | err = do_autodetect_dev(base_path, conf_path, list, verify, 644 | cmd_head, bus, address); 645 | if (err < 0) 646 | return EXIT_FAILURE; 647 | 648 | return EXIT_SUCCESS; 649 | } 650 | -------------------------------------------------------------------------------- /imx_usb.conf: -------------------------------------------------------------------------------- 1 | #vid:pid, config_file 2 | 0x066f:0x3780, mx23_usb_work.conf 3 | 0x15a2:0x004f, mx28_usb_work.conf 4 | 0x15a2:0x0052, mx50_usb_work.conf 5 | 0x15a2:0x0054, mx6_usb_work.conf 6 | 0x15a2:0x0061, mx6_usb_work.conf 7 | 0x15a2:0x0063, mx6_usb_work.conf 8 | 0x15a2:0x0071, mx6_usb_work.conf 9 | 0x15a2:0x007d, mx6_usb_work.conf 10 | 0x15a2:0x0080, mx6ull_usb_work.conf 11 | 0x1fc9:0x0128, mx6_usb_work.conf 12 | 0x15a2:0x0076, mx7_usb_work.conf 13 | 0x1fc9:0x0126, mx7ulp_usb_work.conf 14 | 0x15a2:0x0041, mx51_usb_work.conf 15 | 0x15a2:0x004e, mx53_usb_work.conf 16 | 0x15a2:0x006a, vybrid_usb_work.conf 17 | 0x066f:0x37ff, linux_gadget.conf 18 | 0x1b67:0x4fff, mx6_usb_sdp_spl.conf 19 | 0x0525:0xb4a4, mx6_usb_sdp_spl.conf 20 | 0x1fc9:0x012b, mx8mq_usb_work.conf 21 | 0x1fc9:0x0134, mx8mm_usb_work.conf 22 | 0x1fc9:0x013e, mx8mn_usb_work.conf 23 | 0x3016:0x1001, mx8m_usb_sdp_spl.conf 24 | -------------------------------------------------------------------------------- /msvc/getopt.c: -------------------------------------------------------------------------------- 1 | /* Getopt for Microsoft C 2 | This code is a modification of the Free Software Foundation, Inc. 3 | Getopt library for parsing command line argument the purpose was 4 | to provide a Microsoft Visual C friendly derivative. This code 5 | provides functionality for both Unicode and Multibyte builds. 6 | 7 | Date: 02/03/2011 - Ludvik Jerabek - Initial Release 8 | Version: 1.0 9 | Comment: Supports getopt, getopt_long, and getopt_long_only 10 | and POSIXLY_CORRECT environment flag 11 | License: LGPL 12 | 13 | Revisions: 14 | 15 | 02/03/2011 - Ludvik Jerabek - Initial Release 16 | 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 17 | 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs 18 | 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception 19 | 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB 20 | 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file 21 | 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 22 | 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features 23 | 24 | **DISCLAIMER** 25 | THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 26 | EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 28 | PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE 29 | EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT 30 | APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY 31 | DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY 32 | USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST 33 | PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON 34 | YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE 35 | EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 36 | */ 37 | 38 | #ifndef _CRT_SECURE_NO_WARNINGS 39 | #define _CRT_SECURE_NO_WARNINGS 40 | #endif 41 | 42 | #include 43 | #include 44 | #include 45 | #include "getopt.h" 46 | 47 | #ifdef __cplusplus 48 | #define _GETOPT_THROW throw() 49 | #else 50 | #define _GETOPT_THROW 51 | #endif 52 | 53 | int optind = 1; 54 | int opterr = 1; 55 | int optopt = '?'; 56 | enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER }; 57 | 58 | // 59 | // 60 | // Ansi structures and functions follow 61 | // 62 | // 63 | 64 | static struct _getopt_data_a 65 | { 66 | int optind; 67 | int opterr; 68 | int optopt; 69 | char *optarg; 70 | int __initialized; 71 | char *__nextchar; 72 | enum ENUM_ORDERING __ordering; 73 | int __posixly_correct; 74 | int __first_nonopt; 75 | int __last_nonopt; 76 | } getopt_data_a; 77 | char *optarg_a; 78 | 79 | static void exchange_a(char **argv, struct _getopt_data_a *d) 80 | { 81 | int bottom = d->__first_nonopt; 82 | int middle = d->__last_nonopt; 83 | int top = d->optind; 84 | char *tem; 85 | while (top > middle && middle > bottom) 86 | { 87 | if (top - middle > middle - bottom) 88 | { 89 | int len = middle - bottom; 90 | register int i; 91 | for (i = 0; i < len; i++) 92 | { 93 | tem = argv[bottom + i]; 94 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 95 | argv[top - (middle - bottom) + i] = tem; 96 | } 97 | top -= len; 98 | } 99 | else 100 | { 101 | int len = top - middle; 102 | register int i; 103 | for (i = 0; i < len; i++) 104 | { 105 | tem = argv[bottom + i]; 106 | argv[bottom + i] = argv[middle + i]; 107 | argv[middle + i] = tem; 108 | } 109 | bottom += len; 110 | } 111 | } 112 | d->__first_nonopt += (d->optind - d->__last_nonopt); 113 | d->__last_nonopt = d->optind; 114 | } 115 | static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct) 116 | { 117 | d->__first_nonopt = d->__last_nonopt = d->optind; 118 | d->__nextchar = NULL; 119 | d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT"); 120 | if (optstring[0] == '-') 121 | { 122 | d->__ordering = RETURN_IN_ORDER; 123 | ++optstring; 124 | } 125 | else if (optstring[0] == '+') 126 | { 127 | d->__ordering = REQUIRE_ORDER; 128 | ++optstring; 129 | } 130 | else if (d->__posixly_correct) 131 | d->__ordering = REQUIRE_ORDER; 132 | else 133 | d->__ordering = PERMUTE; 134 | return optstring; 135 | } 136 | int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct) 137 | { 138 | int print_errors = d->opterr; 139 | if (argc < 1) 140 | return -1; 141 | d->optarg = NULL; 142 | if (d->optind == 0 || !d->__initialized) 143 | { 144 | if (d->optind == 0) 145 | d->optind = 1; 146 | optstring = _getopt_initialize_a (optstring, d, posixly_correct); 147 | d->__initialized = 1; 148 | } 149 | else if (optstring[0] == '-' || optstring[0] == '+') 150 | optstring++; 151 | if (optstring[0] == ':') 152 | print_errors = 0; 153 | if (d->__nextchar == NULL || *d->__nextchar == '\0') 154 | { 155 | if (d->__last_nonopt > d->optind) 156 | d->__last_nonopt = d->optind; 157 | if (d->__first_nonopt > d->optind) 158 | d->__first_nonopt = d->optind; 159 | if (d->__ordering == PERMUTE) 160 | { 161 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) 162 | exchange_a ((char **) argv, d); 163 | else if (d->__last_nonopt != d->optind) 164 | d->__first_nonopt = d->optind; 165 | while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) 166 | d->optind++; 167 | d->__last_nonopt = d->optind; 168 | } 169 | if (d->optind != argc && !strcmp(argv[d->optind], "--")) 170 | { 171 | d->optind++; 172 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) 173 | exchange_a((char **) argv, d); 174 | else if (d->__first_nonopt == d->__last_nonopt) 175 | d->__first_nonopt = d->optind; 176 | d->__last_nonopt = argc; 177 | d->optind = argc; 178 | } 179 | if (d->optind == argc) 180 | { 181 | if (d->__first_nonopt != d->__last_nonopt) 182 | d->optind = d->__first_nonopt; 183 | return -1; 184 | } 185 | if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) 186 | { 187 | if (d->__ordering == REQUIRE_ORDER) 188 | return -1; 189 | d->optarg = argv[d->optind++]; 190 | return 1; 191 | } 192 | d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-')); 193 | } 194 | if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1]))))) 195 | { 196 | char *nameend; 197 | unsigned int namelen; 198 | const struct option_a *p; 199 | const struct option_a *pfound = NULL; 200 | struct option_list 201 | { 202 | const struct option_a *p; 203 | struct option_list *next; 204 | } *ambig_list = NULL; 205 | int exact = 0; 206 | int indfound = -1; 207 | int option_index; 208 | for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++); 209 | namelen = (unsigned int)(nameend - d->__nextchar); 210 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 211 | if (!strncmp(p->name, d->__nextchar, namelen)) 212 | { 213 | if (namelen == (unsigned int)strlen(p->name)) 214 | { 215 | pfound = p; 216 | indfound = option_index; 217 | exact = 1; 218 | break; 219 | } 220 | else if (pfound == NULL) 221 | { 222 | pfound = p; 223 | indfound = option_index; 224 | } 225 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) 226 | { 227 | struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); 228 | newp->p = p; 229 | newp->next = ambig_list; 230 | ambig_list = newp; 231 | } 232 | } 233 | if (ambig_list != NULL && !exact) 234 | { 235 | if (print_errors) 236 | { 237 | struct option_list first; 238 | first.p = pfound; 239 | first.next = ambig_list; 240 | ambig_list = &first; 241 | fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); 242 | do 243 | { 244 | fprintf (stderr, " '--%s'", ambig_list->p->name); 245 | ambig_list = ambig_list->next; 246 | } 247 | while (ambig_list != NULL); 248 | fputc ('\n', stderr); 249 | } 250 | d->__nextchar += strlen(d->__nextchar); 251 | d->optind++; 252 | d->optopt = 0; 253 | return '?'; 254 | } 255 | if (pfound != NULL) 256 | { 257 | option_index = indfound; 258 | d->optind++; 259 | if (*nameend) 260 | { 261 | if (pfound->has_arg) 262 | d->optarg = nameend + 1; 263 | else 264 | { 265 | if (print_errors) 266 | { 267 | if (argv[d->optind - 1][1] == '-') 268 | { 269 | fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name); 270 | } 271 | else 272 | { 273 | fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name); 274 | } 275 | } 276 | d->__nextchar += strlen(d->__nextchar); 277 | d->optopt = pfound->val; 278 | return '?'; 279 | } 280 | } 281 | else if (pfound->has_arg == 1) 282 | { 283 | if (d->optind < argc) 284 | d->optarg = argv[d->optind++]; 285 | else 286 | { 287 | if (print_errors) 288 | { 289 | fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name); 290 | } 291 | d->__nextchar += strlen(d->__nextchar); 292 | d->optopt = pfound->val; 293 | return optstring[0] == ':' ? ':' : '?'; 294 | } 295 | } 296 | d->__nextchar += strlen(d->__nextchar); 297 | if (longind != NULL) 298 | *longind = option_index; 299 | if (pfound->flag) 300 | { 301 | *(pfound->flag) = pfound->val; 302 | return 0; 303 | } 304 | return pfound->val; 305 | } 306 | if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL) 307 | { 308 | if (print_errors) 309 | { 310 | if (argv[d->optind][1] == '-') 311 | { 312 | fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar); 313 | } 314 | else 315 | { 316 | fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar); 317 | } 318 | } 319 | d->__nextchar = (char *)""; 320 | d->optind++; 321 | d->optopt = 0; 322 | return '?'; 323 | } 324 | } 325 | { 326 | char c = *d->__nextchar++; 327 | char *temp = (char*)strchr(optstring, c); 328 | if (*d->__nextchar == '\0') 329 | ++d->optind; 330 | if (temp == NULL || c == ':' || c == ';') 331 | { 332 | if (print_errors) 333 | { 334 | fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c); 335 | } 336 | d->optopt = c; 337 | return '?'; 338 | } 339 | if (temp[0] == 'W' && temp[1] == ';') 340 | { 341 | char *nameend; 342 | const struct option_a *p; 343 | const struct option_a *pfound = NULL; 344 | int exact = 0; 345 | int ambig = 0; 346 | int indfound = 0; 347 | int option_index; 348 | if (longopts == NULL) 349 | goto no_longs; 350 | if (*d->__nextchar != '\0') 351 | { 352 | d->optarg = d->__nextchar; 353 | d->optind++; 354 | } 355 | else if (d->optind == argc) 356 | { 357 | if (print_errors) 358 | { 359 | fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c); 360 | } 361 | d->optopt = c; 362 | if (optstring[0] == ':') 363 | c = ':'; 364 | else 365 | c = '?'; 366 | return c; 367 | } 368 | else 369 | d->optarg = argv[d->optind++]; 370 | for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++); 371 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 372 | if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar)) 373 | { 374 | if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name)) 375 | { 376 | pfound = p; 377 | indfound = option_index; 378 | exact = 1; 379 | break; 380 | } 381 | else if (pfound == NULL) 382 | { 383 | pfound = p; 384 | indfound = option_index; 385 | } 386 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) 387 | ambig = 1; 388 | } 389 | if (ambig && !exact) 390 | { 391 | if (print_errors) 392 | { 393 | fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg); 394 | } 395 | d->__nextchar += strlen(d->__nextchar); 396 | d->optind++; 397 | return '?'; 398 | } 399 | if (pfound != NULL) 400 | { 401 | option_index = indfound; 402 | if (*nameend) 403 | { 404 | if (pfound->has_arg) 405 | d->optarg = nameend + 1; 406 | else 407 | { 408 | if (print_errors) 409 | { 410 | fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name); 411 | } 412 | d->__nextchar += strlen(d->__nextchar); 413 | return '?'; 414 | } 415 | } 416 | else if (pfound->has_arg == 1) 417 | { 418 | if (d->optind < argc) 419 | d->optarg = argv[d->optind++]; 420 | else 421 | { 422 | if (print_errors) 423 | { 424 | fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name); 425 | } 426 | d->__nextchar += strlen(d->__nextchar); 427 | return optstring[0] == ':' ? ':' : '?'; 428 | } 429 | } 430 | else 431 | d->optarg = NULL; 432 | d->__nextchar += strlen(d->__nextchar); 433 | if (longind != NULL) 434 | *longind = option_index; 435 | if (pfound->flag) 436 | { 437 | *(pfound->flag) = pfound->val; 438 | return 0; 439 | } 440 | return pfound->val; 441 | } 442 | no_longs: 443 | d->__nextchar = NULL; 444 | return 'W'; 445 | } 446 | if (temp[1] == ':') 447 | { 448 | if (temp[2] == ':') 449 | { 450 | if (*d->__nextchar != '\0') 451 | { 452 | d->optarg = d->__nextchar; 453 | d->optind++; 454 | } 455 | else 456 | d->optarg = NULL; 457 | d->__nextchar = NULL; 458 | } 459 | else 460 | { 461 | if (*d->__nextchar != '\0') 462 | { 463 | d->optarg = d->__nextchar; 464 | d->optind++; 465 | } 466 | else if (d->optind == argc) 467 | { 468 | if (print_errors) 469 | { 470 | fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c); 471 | } 472 | d->optopt = c; 473 | if (optstring[0] == ':') 474 | c = ':'; 475 | else 476 | c = '?'; 477 | } 478 | else 479 | d->optarg = argv[d->optind++]; 480 | d->__nextchar = NULL; 481 | } 482 | } 483 | return c; 484 | } 485 | } 486 | int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct) 487 | { 488 | int result; 489 | getopt_data_a.optind = optind; 490 | getopt_data_a.opterr = opterr; 491 | result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct); 492 | optind = getopt_data_a.optind; 493 | optarg_a = getopt_data_a.optarg; 494 | optopt = getopt_data_a.optopt; 495 | return result; 496 | } 497 | int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW 498 | { 499 | return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0); 500 | } 501 | int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW 502 | { 503 | return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0); 504 | } 505 | int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW 506 | { 507 | return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0); 508 | } 509 | int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) 510 | { 511 | return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0); 512 | } 513 | int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) 514 | { 515 | return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0); 516 | } 517 | 518 | // 519 | // 520 | // Unicode Structures and Functions 521 | // 522 | // 523 | 524 | static struct _getopt_data_w 525 | { 526 | int optind; 527 | int opterr; 528 | int optopt; 529 | wchar_t *optarg; 530 | int __initialized; 531 | wchar_t *__nextchar; 532 | enum ENUM_ORDERING __ordering; 533 | int __posixly_correct; 534 | int __first_nonopt; 535 | int __last_nonopt; 536 | } getopt_data_w; 537 | wchar_t *optarg_w; 538 | 539 | static void exchange_w(wchar_t **argv, struct _getopt_data_w *d) 540 | { 541 | int bottom = d->__first_nonopt; 542 | int middle = d->__last_nonopt; 543 | int top = d->optind; 544 | wchar_t *tem; 545 | while (top > middle && middle > bottom) 546 | { 547 | if (top - middle > middle - bottom) 548 | { 549 | int len = middle - bottom; 550 | register int i; 551 | for (i = 0; i < len; i++) 552 | { 553 | tem = argv[bottom + i]; 554 | argv[bottom + i] = argv[top - (middle - bottom) + i]; 555 | argv[top - (middle - bottom) + i] = tem; 556 | } 557 | top -= len; 558 | } 559 | else 560 | { 561 | int len = top - middle; 562 | register int i; 563 | for (i = 0; i < len; i++) 564 | { 565 | tem = argv[bottom + i]; 566 | argv[bottom + i] = argv[middle + i]; 567 | argv[middle + i] = tem; 568 | } 569 | bottom += len; 570 | } 571 | } 572 | d->__first_nonopt += (d->optind - d->__last_nonopt); 573 | d->__last_nonopt = d->optind; 574 | } 575 | static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct) 576 | { 577 | d->__first_nonopt = d->__last_nonopt = d->optind; 578 | d->__nextchar = NULL; 579 | d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT"); 580 | if (optstring[0] == L'-') 581 | { 582 | d->__ordering = RETURN_IN_ORDER; 583 | ++optstring; 584 | } 585 | else if (optstring[0] == L'+') 586 | { 587 | d->__ordering = REQUIRE_ORDER; 588 | ++optstring; 589 | } 590 | else if (d->__posixly_correct) 591 | d->__ordering = REQUIRE_ORDER; 592 | else 593 | d->__ordering = PERMUTE; 594 | return optstring; 595 | } 596 | int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct) 597 | { 598 | int print_errors = d->opterr; 599 | if (argc < 1) 600 | return -1; 601 | d->optarg = NULL; 602 | if (d->optind == 0 || !d->__initialized) 603 | { 604 | if (d->optind == 0) 605 | d->optind = 1; 606 | optstring = _getopt_initialize_w (optstring, d, posixly_correct); 607 | d->__initialized = 1; 608 | } 609 | else if (optstring[0] == L'-' || optstring[0] == L'+') 610 | optstring++; 611 | if (optstring[0] == L':') 612 | print_errors = 0; 613 | if (d->__nextchar == NULL || *d->__nextchar == L'\0') 614 | { 615 | if (d->__last_nonopt > d->optind) 616 | d->__last_nonopt = d->optind; 617 | if (d->__first_nonopt > d->optind) 618 | d->__first_nonopt = d->optind; 619 | if (d->__ordering == PERMUTE) 620 | { 621 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) 622 | exchange_w((wchar_t **) argv, d); 623 | else if (d->__last_nonopt != d->optind) 624 | d->__first_nonopt = d->optind; 625 | while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) 626 | d->optind++; 627 | d->__last_nonopt = d->optind; 628 | } 629 | if (d->optind != argc && !wcscmp(argv[d->optind], L"--")) 630 | { 631 | d->optind++; 632 | if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) 633 | exchange_w((wchar_t **) argv, d); 634 | else if (d->__first_nonopt == d->__last_nonopt) 635 | d->__first_nonopt = d->optind; 636 | d->__last_nonopt = argc; 637 | d->optind = argc; 638 | } 639 | if (d->optind == argc) 640 | { 641 | if (d->__first_nonopt != d->__last_nonopt) 642 | d->optind = d->__first_nonopt; 643 | return -1; 644 | } 645 | if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) 646 | { 647 | if (d->__ordering == REQUIRE_ORDER) 648 | return -1; 649 | d->optarg = argv[d->optind++]; 650 | return 1; 651 | } 652 | d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-')); 653 | } 654 | if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1]))))) 655 | { 656 | wchar_t *nameend; 657 | unsigned int namelen; 658 | const struct option_w *p; 659 | const struct option_w *pfound = NULL; 660 | struct option_list 661 | { 662 | const struct option_w *p; 663 | struct option_list *next; 664 | } *ambig_list = NULL; 665 | int exact = 0; 666 | int indfound = -1; 667 | int option_index; 668 | for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++); 669 | namelen = (unsigned int)(nameend - d->__nextchar); 670 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 671 | if (!wcsncmp(p->name, d->__nextchar, namelen)) 672 | { 673 | if (namelen == (unsigned int)wcslen(p->name)) 674 | { 675 | pfound = p; 676 | indfound = option_index; 677 | exact = 1; 678 | break; 679 | } 680 | else if (pfound == NULL) 681 | { 682 | pfound = p; 683 | indfound = option_index; 684 | } 685 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) 686 | { 687 | struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); 688 | newp->p = p; 689 | newp->next = ambig_list; 690 | ambig_list = newp; 691 | } 692 | } 693 | if (ambig_list != NULL && !exact) 694 | { 695 | if (print_errors) 696 | { 697 | struct option_list first; 698 | first.p = pfound; 699 | first.next = ambig_list; 700 | ambig_list = &first; 701 | fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); 702 | do 703 | { 704 | fwprintf (stderr, L" '--%s'", ambig_list->p->name); 705 | ambig_list = ambig_list->next; 706 | } 707 | while (ambig_list != NULL); 708 | fputwc (L'\n', stderr); 709 | } 710 | d->__nextchar += wcslen(d->__nextchar); 711 | d->optind++; 712 | d->optopt = 0; 713 | return L'?'; 714 | } 715 | if (pfound != NULL) 716 | { 717 | option_index = indfound; 718 | d->optind++; 719 | if (*nameend) 720 | { 721 | if (pfound->has_arg) 722 | d->optarg = nameend + 1; 723 | else 724 | { 725 | if (print_errors) 726 | { 727 | if (argv[d->optind - 1][1] == L'-') 728 | { 729 | fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name); 730 | } 731 | else 732 | { 733 | fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name); 734 | } 735 | } 736 | d->__nextchar += wcslen(d->__nextchar); 737 | d->optopt = pfound->val; 738 | return L'?'; 739 | } 740 | } 741 | else if (pfound->has_arg == 1) 742 | { 743 | if (d->optind < argc) 744 | d->optarg = argv[d->optind++]; 745 | else 746 | { 747 | if (print_errors) 748 | { 749 | fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name); 750 | } 751 | d->__nextchar += wcslen(d->__nextchar); 752 | d->optopt = pfound->val; 753 | return optstring[0] == L':' ? L':' : L'?'; 754 | } 755 | } 756 | d->__nextchar += wcslen(d->__nextchar); 757 | if (longind != NULL) 758 | *longind = option_index; 759 | if (pfound->flag) 760 | { 761 | *(pfound->flag) = pfound->val; 762 | return 0; 763 | } 764 | return pfound->val; 765 | } 766 | if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL) 767 | { 768 | if (print_errors) 769 | { 770 | if (argv[d->optind][1] == L'-') 771 | { 772 | fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar); 773 | } 774 | else 775 | { 776 | fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar); 777 | } 778 | } 779 | d->__nextchar = (wchar_t *)L""; 780 | d->optind++; 781 | d->optopt = 0; 782 | return L'?'; 783 | } 784 | } 785 | { 786 | wchar_t c = *d->__nextchar++; 787 | wchar_t *temp = (wchar_t*)wcschr(optstring, c); 788 | if (*d->__nextchar == L'\0') 789 | ++d->optind; 790 | if (temp == NULL || c == L':' || c == L';') 791 | { 792 | if (print_errors) 793 | { 794 | fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c); 795 | } 796 | d->optopt = c; 797 | return L'?'; 798 | } 799 | if (temp[0] == L'W' && temp[1] == L';') 800 | { 801 | wchar_t *nameend; 802 | const struct option_w *p; 803 | const struct option_w *pfound = NULL; 804 | int exact = 0; 805 | int ambig = 0; 806 | int indfound = 0; 807 | int option_index; 808 | if (longopts == NULL) 809 | goto no_longs; 810 | if (*d->__nextchar != L'\0') 811 | { 812 | d->optarg = d->__nextchar; 813 | d->optind++; 814 | } 815 | else if (d->optind == argc) 816 | { 817 | if (print_errors) 818 | { 819 | fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c); 820 | } 821 | d->optopt = c; 822 | if (optstring[0] == L':') 823 | c = L':'; 824 | else 825 | c = L'?'; 826 | return c; 827 | } 828 | else 829 | d->optarg = argv[d->optind++]; 830 | for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++); 831 | for (p = longopts, option_index = 0; p->name; p++, option_index++) 832 | if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar)) 833 | { 834 | if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name)) 835 | { 836 | pfound = p; 837 | indfound = option_index; 838 | exact = 1; 839 | break; 840 | } 841 | else if (pfound == NULL) 842 | { 843 | pfound = p; 844 | indfound = option_index; 845 | } 846 | else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) 847 | ambig = 1; 848 | } 849 | if (ambig && !exact) 850 | { 851 | if (print_errors) 852 | { 853 | fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg); 854 | } 855 | d->__nextchar += wcslen(d->__nextchar); 856 | d->optind++; 857 | return L'?'; 858 | } 859 | if (pfound != NULL) 860 | { 861 | option_index = indfound; 862 | if (*nameend) 863 | { 864 | if (pfound->has_arg) 865 | d->optarg = nameend + 1; 866 | else 867 | { 868 | if (print_errors) 869 | { 870 | fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name); 871 | } 872 | d->__nextchar += wcslen(d->__nextchar); 873 | return L'?'; 874 | } 875 | } 876 | else if (pfound->has_arg == 1) 877 | { 878 | if (d->optind < argc) 879 | d->optarg = argv[d->optind++]; 880 | else 881 | { 882 | if (print_errors) 883 | { 884 | fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name); 885 | } 886 | d->__nextchar += wcslen(d->__nextchar); 887 | return optstring[0] == L':' ? L':' : L'?'; 888 | } 889 | } 890 | else 891 | d->optarg = NULL; 892 | d->__nextchar += wcslen(d->__nextchar); 893 | if (longind != NULL) 894 | *longind = option_index; 895 | if (pfound->flag) 896 | { 897 | *(pfound->flag) = pfound->val; 898 | return 0; 899 | } 900 | return pfound->val; 901 | } 902 | no_longs: 903 | d->__nextchar = NULL; 904 | return L'W'; 905 | } 906 | if (temp[1] == L':') 907 | { 908 | if (temp[2] == L':') 909 | { 910 | if (*d->__nextchar != L'\0') 911 | { 912 | d->optarg = d->__nextchar; 913 | d->optind++; 914 | } 915 | else 916 | d->optarg = NULL; 917 | d->__nextchar = NULL; 918 | } 919 | else 920 | { 921 | if (*d->__nextchar != L'\0') 922 | { 923 | d->optarg = d->__nextchar; 924 | d->optind++; 925 | } 926 | else if (d->optind == argc) 927 | { 928 | if (print_errors) 929 | { 930 | fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c); 931 | } 932 | d->optopt = c; 933 | if (optstring[0] == L':') 934 | c = L':'; 935 | else 936 | c = L'?'; 937 | } 938 | else 939 | d->optarg = argv[d->optind++]; 940 | d->__nextchar = NULL; 941 | } 942 | } 943 | return c; 944 | } 945 | } 946 | int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct) 947 | { 948 | int result; 949 | getopt_data_w.optind = optind; 950 | getopt_data_w.opterr = opterr; 951 | result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct); 952 | optind = getopt_data_w.optind; 953 | optarg_w = getopt_data_w.optarg; 954 | optopt = getopt_data_w.optopt; 955 | return result; 956 | } 957 | int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW 958 | { 959 | return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0); 960 | } 961 | int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW 962 | { 963 | return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0); 964 | } 965 | int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW 966 | { 967 | return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0); 968 | } 969 | int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) 970 | { 971 | return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0); 972 | } 973 | int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) 974 | { 975 | return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0); 976 | } -------------------------------------------------------------------------------- /msvc/getopt.h: -------------------------------------------------------------------------------- 1 | /* Getopt for Microsoft C 2 | This code is a modification of the Free Software Foundation, Inc. 3 | Getopt library for parsing command line argument the purpose was 4 | to provide a Microsoft Visual C friendly derivative. This code 5 | provides functionality for both Unicode and Multibyte builds. 6 | 7 | Date: 02/03/2011 - Ludvik Jerabek - Initial Release 8 | Version: 1.0 9 | Comment: Supports getopt, getopt_long, and getopt_long_only 10 | and POSIXLY_CORRECT environment flag 11 | License: LGPL 12 | 13 | Revisions: 14 | 15 | 02/03/2011 - Ludvik Jerabek - Initial Release 16 | 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 17 | 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs 18 | 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception 19 | 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB 20 | 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file 21 | 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 22 | 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features 23 | 24 | **DISCLAIMER** 25 | THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 26 | EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 28 | PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE 29 | EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT 30 | APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY 31 | DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY 32 | USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST 33 | PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON 34 | YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE 35 | EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 36 | */ 37 | #ifndef __GETOPT_H_ 38 | #define __GETOPT_H_ 39 | 40 | #ifdef _GETOPT_API 41 | #undef _GETOPT_API 42 | #endif 43 | 44 | #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) 45 | #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" 46 | #elif defined(STATIC_GETOPT) 47 | #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") 48 | #define _GETOPT_API 49 | #elif defined(EXPORTS_GETOPT) 50 | #pragma message("Exporting getopt library") 51 | #define _GETOPT_API __declspec(dllexport) 52 | #else 53 | #pragma message("Importing getopt library") 54 | #define _GETOPT_API __declspec(dllimport) 55 | #endif 56 | 57 | // Change behavior for C\C++ 58 | #ifdef __cplusplus 59 | #define _BEGIN_EXTERN_C extern "C" { 60 | #define _END_EXTERN_C } 61 | #define _GETOPT_THROW throw() 62 | #else 63 | #define _BEGIN_EXTERN_C 64 | #define _END_EXTERN_C 65 | #define _GETOPT_THROW 66 | #endif 67 | 68 | // Standard GNU options 69 | #define null_argument 0 /*Argument Null*/ 70 | #define no_argument 0 /*Argument Switch Only*/ 71 | #define required_argument 1 /*Argument Required*/ 72 | #define optional_argument 2 /*Argument Optional*/ 73 | 74 | // Shorter Options 75 | #define ARG_NULL 0 /*Argument Null*/ 76 | #define ARG_NONE 0 /*Argument Switch Only*/ 77 | #define ARG_REQ 1 /*Argument Required*/ 78 | #define ARG_OPT 2 /*Argument Optional*/ 79 | 80 | #include 81 | #include 82 | 83 | _BEGIN_EXTERN_C 84 | 85 | extern _GETOPT_API int optind; 86 | extern _GETOPT_API int opterr; 87 | extern _GETOPT_API int optopt; 88 | 89 | // Ansi 90 | struct option_a 91 | { 92 | const char* name; 93 | int has_arg; 94 | int *flag; 95 | char val; 96 | }; 97 | extern _GETOPT_API char *optarg_a; 98 | extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; 99 | extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; 100 | extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; 101 | 102 | // Unicode 103 | struct option_w 104 | { 105 | const wchar_t* name; 106 | int has_arg; 107 | int *flag; 108 | wchar_t val; 109 | }; 110 | extern _GETOPT_API wchar_t *optarg_w; 111 | extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; 112 | extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; 113 | extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; 114 | 115 | _END_EXTERN_C 116 | 117 | #undef _BEGIN_EXTERN_C 118 | #undef _END_EXTERN_C 119 | #undef _GETOPT_THROW 120 | #undef _GETOPT_API 121 | 122 | #ifdef _UNICODE 123 | #define getopt getopt_w 124 | #define getopt_long getopt_long_w 125 | #define getopt_long_only getopt_long_only_w 126 | #define option option_w 127 | #define optarg optarg_w 128 | #else 129 | #define getopt getopt_a 130 | #define getopt_long getopt_long_a 131 | #define getopt_long_only getopt_long_only_a 132 | #define option option_a 133 | #define optarg optarg_a 134 | #endif 135 | #endif // __GETOPT_H_ 136 | -------------------------------------------------------------------------------- /msvc/imx_loader.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imx_uart", "imx_uart.vcxproj", "{E97E957F-CB34-4A96-B2AF-D2E7D902B27E}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imx_usb", "imx_usb.vcxproj", "{1D2B783C-E033-49B3-ACD1-8AA3C5A51774}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Debug|Win32.Build.0 = Debug|Win32 20 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Debug|x64.ActiveCfg = Debug|Win32 21 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Release|Win32.ActiveCfg = Release|Win32 22 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Release|Win32.Build.0 = Release|Win32 23 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E}.Release|x64.ActiveCfg = Release|Win32 24 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Debug|Win32.Build.0 = Debug|Win32 26 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Debug|x64.ActiveCfg = Debug|Win32 27 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Release|Win32.ActiveCfg = Release|Win32 28 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Release|Win32.Build.0 = Release|Win32 29 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774}.Release|x64.ActiveCfg = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /msvc/imx_uart.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {E97E957F-CB34-4A96-B2AF-D2E7D902B27E} 15 | Win32Proj 16 | imx_loaderuart_loader 17 | 8.1 18 | 19 | 20 | 21 | Application 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | imx_uart 46 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(MSBuildProjectDirectory) 47 | $(SolutionDir)$(ProjectName)\$(Configuration)\ 48 | $(ProjectName)\$(Configuration)\ 49 | 50 | 51 | false 52 | imx_uart 53 | $(SolutionDir)$(ProjectName)\$(Configuration)\ 54 | $(ProjectName)\$(Configuration)\ 55 | 56 | 57 | 58 | 59 | 60 | Level3 61 | Disabled 62 | WIN32;STATIC_GETOPT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 63 | _UNICODE 64 | $(MSBuildProjectDirectory);%(AdditionalIncludeDirectories) 65 | 66 | 67 | Console 68 | true 69 | 70 | 71 | 72 | 73 | Level3 74 | 75 | 76 | MaxSpeed 77 | true 78 | true 79 | WIN32;STATIC_GETOPT;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 80 | _UNICODE 81 | $(MSBuildProjectDirectory);%(AdditionalIncludeDirectories) 82 | 83 | 84 | Console 85 | true 86 | true 87 | true 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /msvc/imx_usb.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {1D2B783C-E033-49B3-ACD1-8AA3C5A51774} 15 | Win32Proj 16 | imx_loaderuart_loader 17 | 8.1 18 | 19 | 20 | 21 | Application 22 | true 23 | v140 24 | Unicode 25 | 26 | 27 | Application 28 | false 29 | v140 30 | true 31 | Unicode 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | imx_usb 46 | $(SolutionDir)$(ProjectName)\$(Configuration)\ 47 | $(ProjectName)\$(Configuration)\ 48 | 49 | 50 | false 51 | imx_usb 52 | $(SolutionDir)$(ProjectName)\$(Configuration)\ 53 | $(ProjectName)\$(Configuration)\ 54 | 55 | 56 | 57 | 58 | 59 | Level3 60 | Disabled 61 | WIN32;STATIC_GETOPT;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 62 | _UNICODE 63 | ..\..\libusb\include;$(MSBuildProjectDirectory) 64 | MultiThreadedDebug 65 | 66 | 67 | Console 68 | true 69 | ..\..\libusb\MS32\dll\ 70 | libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Level3 80 | 81 | 82 | MaxSpeed 83 | true 84 | true 85 | IMXCONFDIR=$(APPDATA)\imx_loader\;WIN32;STATIC_GETOPT;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 86 | _UNICODE 87 | ..\..\libusb\include;$(MSBuildProjectDirectory) 88 | MultiThreaded 89 | 90 | 91 | Console 92 | true 93 | true 94 | true 95 | libusb-1.0.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 96 | ..\..\libusb\MS32\dll\ 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /mx50_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx50 2 | #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) 3 | hid,64,0xf8006400,0xf8006400,128M 4 | #file:dcd,plug,load nnn,jump [nnn/header/header2] 5 | #jump nnn - new header is placed after last downloaded word 6 | # entire file is loaded before jump, needs load nnn as well 7 | # i.e. file:load nnn,jump nnn 8 | #jump header - only length parameter is downloaded 9 | # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified 10 | # header2 - uses 2nd header found(error if none) 11 | #plug - without jump uses header but clears plug flag to stop after plug execution 12 | 13 | SPL:dcd 14 | u-boot.bin:load 0x77800000 15 | SPL:load 0xF8006400, jump header 16 | -------------------------------------------------------------------------------- /mx51_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx51 2 | #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) 3 | bulk,old_header,64,0x1ffe2000,0x90000000,512M,0x1ffe2000,0x16000 4 | #file:dcd,plug,load nnn,jump [nnn/header/header2] 5 | #jump nnn - new header is placed after last downloaded word 6 | # entire file is loaded before jump, needs load nnn as well 7 | # i.e. file:load nnn,jump nnn 8 | #jump header - only length parameter is downloaded 9 | # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified 10 | # header2 - uses 2nd header found(error if none) 11 | #plug - without jump uses header but clears plug flag to stop after plug execution 12 | 13 | #../u-boot-watchie/u-boot.bin:dcd,plug,jump header 14 | 15 | ../imx_utils/mx51_ddr_init_xm.bin:dcd,plug,jump header 16 | ../u-boot-watchie/mx51_ubl_ecspi.bin:load 0x93f00000 17 | ../imx_utils/mx51_ecspi_ram_write_xm.bin:dcd,plug,jump header 18 | -------------------------------------------------------------------------------- /mx53_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx53 2 | #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) 3 | bulk,512,0xf8006000,0x70000000,512M,0xf8006000,0x12000 4 | #file:dcd,plug,load nnn,jump [nnn/header/header2] 5 | #jump nnn - new header is placed after last downloaded word 6 | # entire file is loaded before jump, needs load nnn as well 7 | # i.e. file:load nnn,jump nnn 8 | #jump header - only length parameter is downloaded 9 | # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified 10 | # header2 - uses 2nd header found(error if none) 11 | #plug - without jump uses header but clears plug flag to stop after plug execution 12 | 13 | #../u-boot-watchie/u-boot.bin:dcd,plug,jump header 14 | 15 | ../imx_utils/mx53_ddr_init_xm.bin:dcd,plug 16 | ../u-boot-watchie/mx53_ubl_ecspi.bin:load 0x73f00000 17 | ../imx_utils/mx53_ecspi_ram_write_xm.bin:jump header2 18 | -------------------------------------------------------------------------------- /mx6_usb_sdp_spl.conf: -------------------------------------------------------------------------------- 1 | mx6_spl_sdp 2 | #hid/bulk,[old_header,]max packet size, {ram start, ram size}(repeat valid ram areas) 3 | #In SPL, we typically load u-boot.img which has a U-boot header... 4 | hid,uboot_header,1024,0x10000000,1G,0x00907000,0x31000 5 | -------------------------------------------------------------------------------- /mx6_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx6_qsb 2 | #hid/bulk,[old_header,]max packet size, dcd_addr, {ram start, ram size}(repeat valid ram areas) 3 | hid,1024,0x910000,0x10000000,1G,0x00900000,0x40000 4 | #file:dcd,plug,load nnn,jump [nnn/header/header2] 5 | #jump nnn - header is after last downloaded word 6 | # entire file is loaded before jump, needs load nnn as well 7 | # i.e. file:load nnn,jump nnn 8 | #jump header - only length parameter is downloaded 9 | # header - uses existing header(error if none), but clears plug and dcd values unless plug also specified 10 | # header2 - uses 2nd header found(error if none) 11 | #jump_direct nnn - nnn is address of header or script commands 12 | # This does not build a header like jump nnn will. 13 | #plug - without jump uses header but clears plug flag to stop after plug execution 14 | #load nnn - load entire file to address 15 | #size nnn - limit file size to load 16 | #skip nnn - ignore the 1st nnn bytes from file 17 | #../u-boot-imx6/u-boot.bin:dcd,plug,jump header 18 | #:modify,020e02a8,7,1 19 | #:modify,020e00bc,7,4 20 | #:read,020e02a8 21 | #:read,020e00bc 22 | #:read,020c4078 23 | #:modify,020c407c,0,0f000000 24 | #:modify,020c4080,0,c00 25 | #:read,020c4084 26 | #../imx_utils/mx6_ddr_init_xm.bin:dcd 27 | #../u-boot-imx6/u-boot.bin:load 0x13effc00 28 | #../u-boot-imx6/u-boot.imx:load 0x13f00000 29 | #../u-boot-dirk/u-boot.imx:load 0x13f00000 30 | #u-boot-6w.bin:load 0x13effc00 31 | #u-boot_1103.bin:load 0x13effc00 32 | #u-boot_1103.bin:jump header 33 | #../imx_utils/mx6_ecspi_ram_write_xm.bin:clear_dcd,plug 34 | #../imx6_obds/output/mx61/bin/diag-obds-mx61qsb-rev1.bin:jump header 35 | -------------------------------------------------------------------------------- /mx6ull_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx6ull 2 | #hid/bulk,[old_header,]max packet size, dcd_addr, {ram start, ram size}(repeat valid ram areas) 3 | hid,1024,0x910000,0x80000000,2G,0x00900000,0x20000 4 | #../u-boot-imx6/u-boot.imx:dcd 5 | #../u-boot-imx6/u-boot.imx:load 0x83f00000 6 | #../imx_utils/mx6_ecspi_ram_write_xm.bin:clear_dcd,plug 7 | -------------------------------------------------------------------------------- /mx7_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx7 2 | #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) 3 | hid,1024,0x910000,0x80000000,1G,0x00900000,0x20000 4 | #file:dcd,plug,load nnn,jump [nnn/header/header2] 5 | #jump nnn - header is after last downloaded word 6 | # entire file is loaded before jump, needs load nnn as well 7 | # i.e. file:load nnn,jump nnn 8 | #jump header - only length parameter is downloaded 9 | #header - uses existing header(error if none), but clears plug and dcd values unless plug also specified 10 | #header2 - uses 2nd header found(error if none) 11 | #plug - without jump uses header but clears plug flag to stop after plug execution 12 | #load nnn - load entire file to address 13 | #../u-boot-imx6/u-boot.bin:dcd,plug,jump header 14 | #:modify,020e02a8,7,1 15 | #:modify,020e00bc,7,4 16 | #:read,020e02a8 17 | #:read,020e00bc 18 | #:read,020c4078 19 | #:modify,020c407c,0,0f000000 20 | #:modify,020c4080,0,c00 21 | #:read,020c4084 22 | #../imx_utils/mx6_ddr_init_xm.bin:dcd 23 | #../u-boot-imx6/u-boot.bin:load 0x13effc00 24 | #../u-boot-imx6/u-boot.imx:load 0x13f00000 25 | #../u-boot-dirk/u-boot.imx:load 0x13f00000 26 | #u-boot-6w.bin:load 0x13effc00 27 | #u-boot_1103.bin:load 0x13effc00 28 | #u-boot_1103.bin:jump header 29 | #../imx_utils/mx6_ecspi_ram_write_xm.bin:clear_dcd,plug 30 | #../imx6_obds/output/mx61/bin/diag-obds-mx61qsb-rev1.bin:jump header 31 | -------------------------------------------------------------------------------- /mx7ulp_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx7ulp 2 | #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) 3 | hid,1024,0x2f020000,0x60000000,1G,0x900000,0x40000 4 | -------------------------------------------------------------------------------- /mx8m_usb_sdp_spl.conf: -------------------------------------------------------------------------------- 1 | mx8m_spl_sdp 2 | #hid/bulk,[old_header,]max packet size, {ram start, ram size}(repeat valid ram areas) 3 | #In SPL, we typically load u-boot.img which has a U-boot header... 4 | hid,1024,0x910000,0x40000000,1G,0x00900000,0x40000 5 | 6 | #0x60000 - 0x8400 = 0x57c00, +0x3000=5ac00 (FIT image) 7 | ../u-boot-imx6/u-boot.bin:load 0x40200000 8 | # Uncomment the line below for i.MX8MQ platforms 9 | ../u-boot-imx6/bl31-iMX8MQ.bin:load 0x00910000,jump 0x910000 10 | # Uncomment the line below for i.MX8MM platforms 11 | #../u-boot-imx6/bl31-iMX8MM.bin:load 0x00920000,jump 0x920000 12 | # Uncomment the line below for i.MX8MN platforms 13 | #../u-boot-imx6/bl31-iMX8MN.bin:load 0x00960000,jump 0x960000 14 | -------------------------------------------------------------------------------- /mx8mm_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx8mm_qsb 2 | #hid/bulk,[old_header,]max packet size, dcd_addr, {ram start, ram size}(repeat valid ram areas) 3 | hid,1024,0x910000,0x40000000,1G,0x00900000,0x40000 4 | #load/run SPL 5 | ../u-boot-imx6/flash.bin:dcd,clear_dcd,plug,jump header 6 | -------------------------------------------------------------------------------- /mx8mn_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx8mn 2 | #hid/bulk/sdps,[old_header,]max packet size, dcd_addr, {ram start, ram size}(repeat valid ram areas) 3 | sdps,no-hid-cmd,ep1,1020,0x910000,0x40000000,1G,0x00900000,0x40000 4 | #load/run SPL 5 | ../u-boot-imx6/flash.bin:dcd,clear_dcd,plug,jump header 6 | -------------------------------------------------------------------------------- /mx8mq_usb_work.conf: -------------------------------------------------------------------------------- 1 | mx8_qsb 2 | #hid/bulk,[old_header,]max packet size, dcd_addr, {ram start, ram size}(repeat valid ram areas) 3 | hid,1024,0x910000,0x40000000,1G,0x00900000,0x40000 4 | #load/run SPL 5 | ../u-boot-imx6/flash.bin:dcd,clear_dcd,plug,jump header 6 | #0x60000 - 0x8400 = 0x57c00, +0x3000=5ac00 (FIT image) 7 | #../u-boot-imx6/u-boot.bin:load 0x40200000 8 | #../u-boot-imx6/bl31-iMX8MQ.bin:load 0x00910000,jump 0x910000 9 | -------------------------------------------------------------------------------- /portable.h: -------------------------------------------------------------------------------- 1 | #ifndef __PORTABLE_H__ 2 | #define __PORTABLE_H__ 3 | 4 | extern int debugmode; 5 | 6 | #ifndef WIN32 7 | #define dbg_printf(fmt, args...) do{ if(debugmode) fprintf(stderr, fmt, ## args); } while(0) 8 | #define dbg_dump_long(src, cnt, addr, skip) do{ if(debugmode) dump_long(src, cnt, addr, skip); } while(0) 9 | #else 10 | 11 | #ifdef DEBUG 12 | #define dbg_printf(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) 13 | #define dbg_dump_long(src, cnt, addr, skip) dump_long(src, cnt, addr, skip) 14 | #else 15 | #define dbg_dump_long(src, cnt, addr, skip) 16 | #define dbg_printf(fmt, ...) /* Don't do anything in release builds */ 17 | #endif 18 | #endif 19 | 20 | #ifndef _MSC_VER 21 | #include 22 | #endif 23 | #ifdef WIN32 24 | #include 25 | #include 26 | #include 27 | #endif 28 | #ifdef __linux__ 29 | #include 30 | #endif 31 | #ifdef __APPLE__ 32 | #include 33 | #endif 34 | #ifdef __FreeBSD__ 35 | #include 36 | #endif 37 | 38 | #ifndef WIN32 39 | #define PATH_SEPARATOR '/' 40 | #define msleep(ms) usleep((ms) * 1000) 41 | #else 42 | #define PATH_MAX MAX_PATH 43 | #define PATH_SEPARATOR '\\' 44 | #define msleep(ms) Sleep(ms) 45 | #endif 46 | 47 | #ifdef _MSC_VER 48 | #define R_OK 04 49 | 50 | #define open(filename,oflag) _open(filename,oflag) 51 | #define write(fd,buffer,count) _write(fd,buffer,count) 52 | #define read(fd,buffer,count) _read(fd,buffer,count) 53 | #define close(fd) _close(fd) 54 | #define access(filename,oflag) _access(filename,oflag) 55 | #define getcwd(buffer, maxlen) _getcwd(buffer, maxlen) 56 | #endif 57 | 58 | #ifdef __GNUC__ 59 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 60 | #define BE32(x) __builtin_bswap32(x) 61 | #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) 62 | #define BE16(x) __builtin_bswap16(x) 63 | #else 64 | #define BE16(x) \ 65 | ({ \ 66 | typeof(x) __x = (x); \ 67 | (((__x << 8) & 0xffff) | ((__x >> 8) & 0xff)); \ 68 | }) 69 | #endif 70 | #else 71 | #define BE32(x) x 72 | #define BE16(x) x 73 | #endif 74 | #elif _MSC_VER // assume little endian... 75 | #define BE32(x) _byteswap_ulong(x) 76 | #define BE16(x) _byteswap_ushort(x) 77 | #endif 78 | 79 | #endif /* __PORTABLE_H__ */ 80 | -------------------------------------------------------------------------------- /sdp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "imx_sdp.h" 8 | #include "portable.h" 9 | 10 | #pragma pack (1) 11 | struct sdp_command { 12 | uint16_t cmd; 13 | uint32_t addr; 14 | uint8_t format; 15 | uint32_t cnt; 16 | uint32_t data; 17 | uint8_t rsvd; 18 | }; 19 | #pragma pack () 20 | 21 | #define SDP_READ_REG 0x0101 22 | #define SDP_WRITE_REG 0x0202 23 | #define SDP_WRITE_FILE 0x0404 24 | #define SDP_ERROR_STATUS 0x0505 25 | #define SDP_WRITE_DCD 0x0a0a 26 | #define SDP_JUMP_ADDRESS 0x0b0b 27 | 28 | static int sdp_fill_read_reg(unsigned char *buf, unsigned addr, unsigned cnt) 29 | { 30 | struct sdp_command read_reg_command = { 31 | .cmd = SDP_READ_REG, 32 | .addr = BE32(addr), 33 | .format = 0x20, 34 | .cnt = BE32(cnt), 35 | .data = BE32(0), 36 | .rsvd = 0x00 37 | }; 38 | int cmd_size = sizeof(struct sdp_command); 39 | 40 | memcpy(buf, &read_reg_command, cmd_size); 41 | return cmd_size; 42 | } 43 | 44 | static int sdp_fill_write_reg(unsigned char *buf, unsigned addr, unsigned val) 45 | { 46 | struct sdp_command write_reg_command = { 47 | .cmd = SDP_WRITE_REG, 48 | .addr = BE32(addr), 49 | .format = 0x20, 50 | .cnt = BE32(4), 51 | .data = BE32(val), 52 | .rsvd = 0x00 53 | }; 54 | int cmd_size = sizeof(struct sdp_command); 55 | 56 | memcpy(buf, &write_reg_command, cmd_size); 57 | return cmd_size; 58 | } 59 | 60 | static int sdp_fill_status(unsigned char *buf) 61 | { 62 | struct sdp_command status_command = { 63 | .cmd = SDP_ERROR_STATUS, 64 | .addr = 0, 65 | .format = 0, 66 | .cnt = 0, 67 | .data = 0, 68 | .rsvd = 0 69 | }; 70 | int cmd_size = sizeof(struct sdp_command); 71 | 72 | memcpy(buf, &status_command, cmd_size); 73 | return cmd_size; 74 | } 75 | 76 | static int sdp_fill_dl_dcd(unsigned char *buf, unsigned dcd_addr, int length) 77 | { 78 | struct sdp_command dl_command = { 79 | .cmd = SDP_WRITE_DCD, 80 | .addr = BE32(dcd_addr), 81 | .format = 0, 82 | .cnt = BE32(length), 83 | .data = 0, 84 | .rsvd = 0 85 | }; 86 | int cmd_size = sizeof(struct sdp_command); 87 | 88 | memcpy(buf, &dl_command, cmd_size); 89 | return cmd_size; 90 | } 91 | 92 | static int sdp_fill_write_file(unsigned char *buf, unsigned dladdr, unsigned fsize, unsigned char type) 93 | { 94 | struct sdp_command dl_command = { 95 | .cmd = SDP_WRITE_FILE, 96 | .addr = BE32(dladdr), 97 | .format = 0, 98 | .cnt = BE32(fsize), 99 | .data = 0, 100 | .rsvd = type 101 | }; 102 | int cmd_size = sizeof(struct sdp_command); 103 | 104 | memcpy(buf, &dl_command, cmd_size); 105 | return cmd_size; 106 | } 107 | 108 | static int sdp_fill_jump(unsigned char *buf, unsigned header_addr) 109 | { 110 | struct sdp_command jump_command = { 111 | .cmd = SDP_JUMP_ADDRESS, 112 | .addr = BE32(header_addr), 113 | .format = 0, 114 | .cnt = 0, 115 | .data = 0, 116 | .rsvd = 0x00 117 | }; 118 | int cmd_size = sizeof(struct sdp_command); 119 | 120 | memcpy(buf, &jump_command, cmd_size); 121 | return cmd_size; 122 | } 123 | 124 | static int sdp_get_cmd_addr_cnt(unsigned char *buf, 125 | uint16_t *cmd, uint32_t *addr, uint32_t *cnt) 126 | { 127 | struct sdp_command *p = (struct sdp_command *)buf; 128 | uint16_t c = p->cmd; 129 | uint16_t tc = CMD_INVAL; 130 | 131 | switch (c) { 132 | case SDP_READ_REG: 133 | tc = CMD_READ_REG; 134 | break; 135 | case SDP_WRITE_REG: 136 | tc = CMD_WRITE_REG; 137 | break; 138 | case SDP_WRITE_FILE: 139 | tc = CMD_WRITE_FILE; 140 | break; 141 | case SDP_ERROR_STATUS: 142 | tc = CMD_ERROR_STATUS; 143 | break; 144 | case SDP_WRITE_DCD: 145 | tc = CMD_WRITE_DCD; 146 | break; 147 | case SDP_JUMP_ADDRESS: 148 | tc = CMD_JUMP_ADDRESS; 149 | break; 150 | } 151 | *cmd = tc; 152 | *addr = BE32(p->addr); 153 | *cnt = BE32(p->cnt); 154 | return sizeof(struct sdp_command); 155 | } 156 | 157 | static struct protocol_ops sdp_protocol_ops = { 158 | .fill_read_reg = sdp_fill_read_reg, 159 | .fill_write_reg = sdp_fill_write_reg, 160 | .fill_status = sdp_fill_status, 161 | .fill_dl_dcd = sdp_fill_dl_dcd, 162 | .fill_write_file = sdp_fill_write_file, 163 | .fill_jump = sdp_fill_jump, 164 | .get_cmd_addr_cnt = sdp_get_cmd_addr_cnt, 165 | }; 166 | 167 | void sdp_init_ops(struct sdp_dev *dev) 168 | { 169 | dev->ops = &sdp_protocol_ops; 170 | } 171 | -------------------------------------------------------------------------------- /sdp.h: -------------------------------------------------------------------------------- 1 | void sdp_init_ops(struct sdp_dev *dev); 2 | -------------------------------------------------------------------------------- /sdps.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "imx_sdp.h" 10 | #include "portable.h" 11 | 12 | #pragma pack (1) 13 | 14 | struct spds 15 | { 16 | unsigned signature; // Signature: 0x43544C42:1129598018, o "BLTC" (little endian) for the BLTC CBW 17 | unsigned tag; // Tag: to be returned in the csw 18 | unsigned xfer_length; // XferLength: number of bytes to transfer 19 | unsigned char flags; // Flags: 20 | // Bit 7: direction - device shall ignore this bit if the 21 | // XferLength field is zero, otherwise: 22 | // 0 = data-out from the host to the device, 23 | // 1 = data-in from the device to the host. 24 | // Bits 6..0: reserved - shall be zero. 25 | unsigned char reserved[2]; // Reserved - shall be zero. 26 | unsigned char command; 27 | unsigned length; 28 | unsigned char reserved2[11]; 29 | }; 30 | 31 | #pragma pack () 32 | 33 | static int sdps_fill_read_reg(unsigned char *buf, unsigned addr, unsigned cnt) 34 | { 35 | return 0; 36 | } 37 | 38 | static int sdps_fill_write_reg(unsigned char *buf, unsigned addr, unsigned cnt) 39 | { 40 | return 0; 41 | } 42 | 43 | static int sdps_fill_status(unsigned char *buf) 44 | { 45 | return 0; 46 | } 47 | 48 | static int sdps_fill_dl_dcd(unsigned char *buf, unsigned dcd_addr, int length) 49 | { 50 | return 0; 51 | } 52 | 53 | static int sdps_fill_write_file(unsigned char *buf, unsigned dladdr, unsigned fsize, unsigned char type) 54 | { 55 | struct spds dl_command = { 56 | .signature = 0x43544C42, /* "BLTC" */ 57 | .tag = 1, 58 | .xfer_length = fsize, 59 | .flags = 0, /* Data In to device */ 60 | .command = 2, /* download firmware */ 61 | .length = BE32(fsize), 62 | }; 63 | int cmd_size = sizeof(struct spds); 64 | 65 | memcpy(buf, &dl_command, cmd_size); 66 | return cmd_size; 67 | } 68 | 69 | static int sdps_fill_jump(unsigned char *buf, unsigned header_addr) 70 | { 71 | return 0; 72 | } 73 | 74 | static struct protocol_ops sdps_protocol_ops = { 75 | .fill_read_reg = sdps_fill_read_reg, 76 | .fill_write_reg = sdps_fill_write_reg, 77 | .fill_status = sdps_fill_status, 78 | .fill_dl_dcd = sdps_fill_dl_dcd, 79 | .fill_write_file = sdps_fill_write_file, 80 | .fill_jump = sdps_fill_jump, 81 | }; 82 | 83 | void sdps_init_ops(struct sdp_dev *dev) 84 | { 85 | dev->ops = &sdps_protocol_ops; 86 | } 87 | -------------------------------------------------------------------------------- /sdps.h: -------------------------------------------------------------------------------- 1 | 2 | void sdps_init_ops(struct sdp_dev *dev); 3 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | IMX_USB ?= ../imx_usb 2 | 3 | %.test: % FORCE 4 | @echo Testing $* 5 | @$(IMX_USB) -v -S 0x15a2:0x0061 $* > $@ 6 | @diff -u $*.output $@ 7 | 8 | tests: test.imx.test test-dcd.imx.test test-plugin.imx.test 9 | 10 | %.output: % FORCE 11 | $(IMX_USB) -v -S 0x15a2:0x0061 $* > $@ 12 | 13 | regen: test.imx.output test-dcd.imx.output test-plugin.imx.output 14 | 15 | FORCE: ; 16 | 17 | .PHONY: tests regen 18 | -------------------------------------------------------------------------------- /tests/bare.cfg: -------------------------------------------------------------------------------- 1 | IMAGE_VERSION 2 2 | BOOT_FROM sd 3 | -------------------------------------------------------------------------------- /tests/create.txt: -------------------------------------------------------------------------------- 1 | => IMX image with plugin 2 | mkimage -n plugin.cfg -T imximage -a -e 0x87800000 -d image.bin test-plugin.imx 3 | => IMX image without plugin 4 | mkimage -n noplugin.cfg -T imximage -e 0x87800000 -d image.bin test.imx 5 | => IMX image with DCD 6 | mkimage -n dcd.cfg -T imximage -e 0x87800000 -d image.bin test-dcd.imx 7 | -------------------------------------------------------------------------------- /tests/dcd.cfg: -------------------------------------------------------------------------------- 1 | IMAGE_VERSION 2 2 | BOOT_FROM sd 3 | 4 | DATA 4 0x30000000 0x12345678 5 | -------------------------------------------------------------------------------- /tests/image.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boundarydevices/imx_usb_loader/30b43d69770cd69e84c045dc9dcabb1f3e9d975a/tests/image.bin -------------------------------------------------------------------------------- /tests/plugin.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boundarydevices/imx_usb_loader/30b43d69770cd69e84c045dc9dcabb1f3e9d975a/tests/plugin.bin -------------------------------------------------------------------------------- /tests/plugin.cfg: -------------------------------------------------------------------------------- 1 | IMAGE_VERSION 2 2 | BOOT_FROM sd 3 | PLUGIN plugin.bin 0x00907000 4 | -------------------------------------------------------------------------------- /tests/test-dcd.imx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boundarydevices/imx_usb_loader/30b43d69770cd69e84c045dc9dcabb1f3e9d975a/tests/test-dcd.imx -------------------------------------------------------------------------------- /tests/test-plugin.imx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boundarydevices/imx_usb_loader/30b43d69770cd69e84c045dc9dcabb1f3e9d975a/tests/test-plugin.imx -------------------------------------------------------------------------------- /tests/test.imx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boundarydevices/imx_usb_loader/30b43d69770cd69e84c045dc9dcabb1f3e9d975a/tests/test.imx -------------------------------------------------------------------------------- /vybrid_usb_work.conf: -------------------------------------------------------------------------------- 1 | vybrid 2 | #hid/bulk,[old_header,]max packet size,dcd_addr,{ram start, ram size}(repeat valid ram areas) 3 | #SysRAM0 4 | #hid,1024,0x3f007000,0x10000000,1G,0x3f007000,0x31000 5 | #gfxRAM 6 | hid,1024,0x3f400000,0x10000000,1G,0x3f400000,0x80000 7 | #file:dcd,plug,load nnn,jump [nnn/header/header2] 8 | #jump nnn - header is after last downloaded word 9 | # entire file is loaded before jump, needs load nnn as well 10 | # i.e. file:load nnn,jump nnn 11 | #jump header - only length parameter is downloaded 12 | #header - uses existing header(error if none), but clears plug and dcd values unless plug also specified 13 | #header2 - uses 2nd header found(error if none) 14 | #plug - without jump uses header but clears plug flag to stop after plug execution 15 | #load nnn - load entire file to address 16 | #../u-boot/u-boot.imx:jump header 17 | --------------------------------------------------------------------------------