diff options
author | nduca@google.com <nduca@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-27 02:36:02 +0000 |
---|---|---|
committer | nduca@google.com <nduca@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-27 02:36:02 +0000 |
commit | 3e601082ac52a9b4787b0be515e4f654fd40dce7 (patch) | |
tree | a250d18d509689361017e6eded3fd010a4ebaa29 /third_party/libusb | |
parent | eb85922f3999887a87d6d4f7eb6afb59cbdc3cfe (diff) | |
download | chromium_src-3e601082ac52a9b4787b0be515e4f654fd40dce7.zip chromium_src-3e601082ac52a9b4787b0be515e4f654fd40dce7.tar.gz chromium_src-3e601082ac52a9b4787b0be515e4f654fd40dce7.tar.bz2 |
Revert 129069 - Import libusb 1.0.9-rc3 into third_party.
Failing license check.
http://chromegw.corp.google.com/i/chromium/builders/Linux/builds/21702/steps/check_licenses
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/9826025
TBR=gdk@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9866021
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129101 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/libusb')
53 files changed, 0 insertions, 22047 deletions
diff --git a/third_party/libusb/AUTHORS b/third_party/libusb/AUTHORS deleted file mode 100644 index 9ced4a9..0000000 --- a/third_party/libusb/AUTHORS +++ /dev/null @@ -1,24 +0,0 @@ -Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> -Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> -Copyright (C) 2008-2010 Nathan Hjelm <hjelmn@users.sourceforge.net> -Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> -Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> - -Other contributors: -Alex Vatchenko -Artem Egorkine -Aurelien Jarno -Bastien Nocera -David Engraf -David Moore -Felipe Balbi -Hans Ulrich Niedermann -Hoi-Ho Chan -Ludovic Rousseau -Martin Koegler -Mikhail Gusarov -Peter Stuge -Rob Walker -Toby Peterson -Vasily Khoruzhick - diff --git a/third_party/libusb/COPYING b/third_party/libusb/COPYING deleted file mode 100644 index 5ab7695..0000000 --- a/third_party/libusb/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/third_party/libusb/INSTALL b/third_party/libusb/INSTALL deleted file mode 100644 index 5458714..0000000 --- a/third_party/libusb/INSTALL +++ /dev/null @@ -1,234 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006 Free Software Foundation, Inc. - -This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. - -Basic Installation -================== - -Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. - - The `configure' shell script attempts to guess correct values for -various system-dependent variables used during compilation. It uses -those values to create a `Makefile' in each directory of the package. -It may also create one or more `.h' files containing system-dependent -definitions. Finally, it creates a shell script `config.status' that -you can run in the future to recreate the current configuration, and a -file `config.log' containing compiler output (useful mainly for -debugging `configure'). - - It can also use an optional file (typically called `config.cache' -and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is -disabled by default to prevent problems with accidental use of stale -cache files. - - If you need to do unusual things to compile the package, please try -to figure out how `configure' could check whether to do them, and mail -diffs or instructions to the address given in the `README' so they can -be considered for the next release. If you are using the cache, and at -some point `config.cache' contains results you don't want to keep, you -may remove or edit it. - - The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. - -The simplest way to compile this package is: - - 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. - - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. - - 2. Type `make' to compile the package. - - 3. Optionally, type `make check' to run any self-tests that come with - the package. - - 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the - source code directory by typing `make clean'. To also remove the - files that `configure' created (so you can compile the package for - a different kind of computer), type `make distclean'. There is - also a `make maintainer-clean' target, but that is intended mainly - for the package's developers. If you use it, you may have to get - all sorts of other programs in order to regenerate files that came - with the distribution. - -Compilers and Options -===================== - -Some systems require unusual options for compilation or linking that the -`configure' script does not know about. Run `./configure --help' for -details on some of the pertinent environment variables. - - You can give `configure' initial values for configuration parameters -by setting variables in the command line or in the environment. Here -is an example: - - ./configure CC=c99 CFLAGS=-g LIBS=-lposix - - *Note Defining Variables::, for more details. - -Compiling For Multiple Architectures -==================================== - -You can compile the package for more than one kind of computer at the -same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the -directory where you want the object files and executables to go and run -the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. - - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. - -Installation Names -================== - -By default, `make install' installs the package's commands under -`/usr/local/bin', include files under `/usr/local/include', etc. You -can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX'. - - You can specify separate installation prefixes for -architecture-specific files and architecture-independent files. If you -pass the option `--exec-prefix=PREFIX' to `configure', the package uses -PREFIX as the prefix for installing programs and libraries. -Documentation and other data files still use the regular prefix. - - In addition, if you use an unusual directory layout you can give -options like `--bindir=DIR' to specify different values for particular -kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. - - If the package supports it, you can cause programs to be installed -with an extra prefix or suffix on their names by giving `configure' the -option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - -Optional Features -================= - -Some packages pay attention to `--enable-FEATURE' options to -`configure', where FEATURE indicates an optional part of the package. -They may also pay attention to `--with-PACKAGE' options, where PACKAGE -is something like `gnu-as' or `x' (for the X Window System). The -`README' should mention any `--enable-' and `--with-' options that the -package recognizes. - - For packages that use the X Window System, `configure' can usually -find the X include and library files automatically, but if it doesn't, -you can use the `configure' options `--x-includes=DIR' and -`--x-libraries=DIR' to specify their locations. - -Specifying the System Type -========================== - -There may be some features `configure' cannot figure out automatically, -but needs to determine by the type of machine the package will run on. -Usually, assuming the package is built to be run on the _same_ -architectures, `configure' can figure that out, but if it prints a -message saying it cannot guess the machine type, give it the -`--build=TYPE' option. TYPE can either be a short name for the system -type, such as `sun4', or a canonical name which has the form: - - CPU-COMPANY-SYSTEM - -where SYSTEM can have one of these forms: - - OS KERNEL-OS - - See the file `config.sub' for the possible values of each field. If -`config.sub' isn't included in this package, then this package doesn't -need to know the machine type. - - If you are _building_ compiler tools for cross-compiling, you should -use the option `--target=TYPE' to select the type of system they will -produce code for. - - If you want to _use_ a cross compiler, that generates code for a -platform different from the build platform, you should specify the -"host" platform (i.e., that on which the generated programs will -eventually be run) with `--host=TYPE'. - -Sharing Defaults -================ - -If you want to set default values for `configure' scripts to share, you -can create a site shell script called `config.site' that gives default -values for variables like `CC', `cache_file', and `prefix'. -`configure' looks for `PREFIX/share/config.site' if it exists, then -`PREFIX/etc/config.site' if it exists. Or, you can set the -`CONFIG_SITE' environment variable to the location of the site script. -A warning: not all `configure' scripts look for a site script. - -Defining Variables -================== - -Variables not defined in a site shell script can be set in the -environment passed to `configure'. However, some packages may run -configure again during the build, and the customized values of these -variables may be lost. In order to avoid this problem, you should set -them in the `configure' command line, using `VAR=value'. For example: - - ./configure CC=/usr/local2/bin/gcc - -causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). - -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: - - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash - -`configure' Invocation -====================== - -`configure' recognizes the following options to control how it operates. - -`--help' -`-h' - Print a summary of the options to `configure', and exit. - -`--version' -`-V' - Print the version of Autoconf used to generate the `configure' - script, and exit. - -`--cache-file=FILE' - Enable the cache: use and save the results of the tests in FILE, - traditionally `config.cache'. FILE defaults to `/dev/null' to - disable caching. - -`--config-cache' -`-C' - Alias for `--cache-file=config.cache'. - -`--quiet' -`--silent' -`-q' - Do not print messages saying which checks are being made. To - suppress all normal output, redirect it to `/dev/null' (any error - messages will still be shown). - -`--srcdir=DIR' - Look for the package's source code in directory DIR. Usually - `configure' can determine that directory automatically. - -`configure' also accepts some other, not widely useful, options. Run -`configure --help' for more details. - diff --git a/third_party/libusb/Makefile.am b/third_party/libusb/Makefile.am deleted file mode 100644 index f59b8c3..0000000 --- a/third_party/libusb/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip -ACLOCAL_AMFLAGS = -I m4 -DISTCLEANFILES = libusb-1.0.pc -MAINTAINERCLEANFILES = ChangeLog -EXTRA_DIST = TODO PORTING -SUBDIRS = libusb doc - -if BUILD_EXAMPLES -SUBDIRS += examples -endif - -pkgconfigdir=$(libdir)/pkgconfig -pkgconfig_DATA=libusb-1.0.pc - -.PHONY: ChangeLog dist-up -ChangeLog: - git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog - -dist-hook: ChangeLog - -reldir = .release/$(distdir) -dist-up: dist - rm -rf $(reldir) - mkdir -p $(reldir) - cp $(distdir).tar.bz2 $(reldir) - rsync -rv $(reldir) frs.sourceforge.net:/home/frs/project/l/li/libusb/libusb-1.0/ - rm -rf $(reldir) - diff --git a/third_party/libusb/NEWS b/third_party/libusb/NEWS deleted file mode 100644 index 42c232c..0000000 --- a/third_party/libusb/NEWS +++ /dev/null @@ -1,56 +0,0 @@ -This file lists notable changes in each release. For the full history of all -changes, see ChangeLog. - -2010-05-07: v1.0.8 -* Bug fixes - -2010-04-19: v1.0.7 -* Bug fixes and documentation tweaks -* Add more interface class definitions - -2009-11-22: v1.0.6 -* Bug fixes -* Increase libusb_handle_events() timeout to 60s for powersaving - -2009-11-15: v1.0.5 - * Use timerfd when available for timer management - * Small fixes/updates - -2009-11-06: v1.0.4 release - * Bug fixes including transfer locking to fix some potential threading races - * More flexibility with clock types on Linux - * Use new bulk continuation tracking in Linux 2.6.32 for improved handling - of short/failed transfers - -2009-08-27: v1.0.3 release - * Bug fixes - * Add libusb_get_max_iso_packet_size() - -2009-06-13: v1.0.2 release - * Bug fixes - -2009-05-12: v1.0.1 release - * Bug fixes - * Darwin backend - -2008-12-13: v1.0.0 release - * Bug fixes - -2008-11-21: v0.9.4 release - * Bug fixes - * Add libusb_attach_kernel_driver() - -2008-08-23: v0.9.3 release - * Bug fixes - -2008-07-19: v0.9.2 release - * Bug fixes - -2008-06-28: v0.9.1 release - * Bug fixes - * Introduce contexts to the API - * Compatibility with new Linux kernel features - -2008-05-25: v0.9.0 release - * First libusb-1.0 beta release - diff --git a/third_party/libusb/PORTING b/third_party/libusb/PORTING deleted file mode 100644 index 7070784..0000000 --- a/third_party/libusb/PORTING +++ /dev/null @@ -1,95 +0,0 @@ -PORTING LIBUSB TO OTHER PLATFORMS - -Introduction -============ - -This document is aimed at developers wishing to port libusb to unsupported -platforms. I believe the libusb API is OS-independent, so by supporting -multiple operating systems we pave the way for cross-platform USB device -drivers. - -Implementation-wise, the basic idea is that you provide an interface to -libusb's internal "backend" API, which performs the appropriate operations on -your target platform. - -In terms of USB I/O, your backend provides functionality to submit -asynchronous transfers (synchronous transfers are implemented in the higher -layers, based on the async interface). Your backend must also provide -functionality to cancel those transfers. - -Your backend must also provide an event handling function to "reap" ongoing -transfers and process their results. - -The backend must also provide standard functions for other USB operations, -e.g. setting configuration, obtaining descriptors, etc. - - -File descriptors for I/O polling -================================ - -For libusb to work, your event handling function obviously needs to be called -at various points in time. Your backend must provide a set of file descriptors -which libusb and its users can pass to poll() or select() to determine when -it is time to call the event handling function. - -On Linux, this is easy: the usbfs kernel interface exposes a file descriptor -which can be passed to poll(). If something similar is not true for your -platform, you can emulate this using an internal library thread to reap I/O as -necessary, and a pipe() with the main library to raise events. The file -descriptor of the pipe can then be provided to libusb as an event source. - - -Interface semantics and documentation -===================================== - -Documentation of the backend interface can be found in libusbi.h inside the -usbi_os_backend structure definition. - -Your implementations of these functions will need to call various internal -libusb functions, prefixed with "usbi_". Documentation for these functions -can be found in the .c files where they are implemented. - -You probably want to skim over *all* the documentation before starting your -implementation. For example, you probably need to allocate and store private -OS-specific data for device handles, but the documentation for the mechanism -for doing so is probably not the first thing you will see. - -The Linux backend acts as a good example - view it as a reference -implementation which you should try to match the behaviour of. - - -Getting started -=============== - -1. Modify configure.ac to detect your platform appropriately (see the OS_LINUX -stuff for an example). - -2. Implement your backend in the libusb/os/ directory, modifying -libusb/os/Makefile.am appropriately. - -3. Add preprocessor logic to the top of libusb/core.c to statically assign the -right usbi_backend for your platform. - -4. Produce and test your implementation. - -5. Send your implementation to libusb-devel mailing list. - - -Implementation difficulties? Questions? -======================================= - -If you encounter difficulties porting libusb to your platform, please raise -these issues on the libusb-devel mailing list. Where possible and sensible, I -am interested in solving problems preventing libusb from operating on other -platforms. - -The libusb-devel mailing list is also a good place to ask questions and -make suggestions about the internal API. Hopefully we can produce some -better documentation based on your questions and other input. - -You are encouraged to get involved in the process; if the library needs -some infrastructure additions/modifications to better support your platform, -you are encouraged to make such changes (in cleanly distinct patch -submissions). Even if you do not make such changes yourself, please do raise -the issues on the mailing list at the very minimum. - diff --git a/third_party/libusb/README b/third_party/libusb/README deleted file mode 100644 index c5dabd7..0000000 --- a/third_party/libusb/README +++ /dev/null @@ -1,23 +0,0 @@ -libusb -====== - -libusb is a library for USB device access from Linux, Mac OS X and -Windows userspace. -It is written in C and licensed under the LGPL-2.1 (see COPYING). - -libusb is abstracted internally in such a way that it can hopefully -be ported to other operating systems. See the PORTING file for some -information, if you fancy a challenge :) - -libusb homepage: -http://libusb.org/ - -Developers will wish to consult the API documentation: -http://libusb.sourceforge.net/api-1.0/ - -Use the mailing list for questions, comments, etc: -https://sourceforge.net/mailarchive/forum.php?forum_name=libusb-devel - -- Daniel Drake <dsd@gentoo.org> -- Peter Stuge <peter@stuge.se> -(use the mailing list rather than mailing developers directly) diff --git a/third_party/libusb/README.chromium b/third_party/libusb/README.chromium deleted file mode 100644 index df7680b..0000000 --- a/third_party/libusb/README.chromium +++ /dev/null @@ -1,12 +0,0 @@ -Name: libusb -URL: http://libusb.org -Version: 1.0.8 -License: LGPL 2.1 -Security Critical: yes - -Description: -libusb provides a platform-agnostic API for accessing the USB subsystem on Mac, -Windows, and Linux systems. - -Local Modifications: -- config.h has been populated with required defines. diff --git a/third_party/libusb/THANKS b/third_party/libusb/THANKS deleted file mode 100644 index d926126..0000000 --- a/third_party/libusb/THANKS +++ /dev/null @@ -1,8 +0,0 @@ -Development contributors are listed in the AUTHORS file. Other community -members who have made significant contributions in other areas are listed -in this file: - -Alan Stern -Ludovic Rousseau -Tim Roberts -Xiaofan Chen diff --git a/third_party/libusb/TODO b/third_party/libusb/TODO deleted file mode 100644 index 6c162a3..0000000 --- a/third_party/libusb/TODO +++ /dev/null @@ -1,9 +0,0 @@ -for 1.1 or future -================== -optional timerfd support (runtime detection) -notifications of hotplugged/unplugged devices -offer API to create/destroy handle_events thread -isochronous sync I/O? -exposing of parent-child device relationships -"usb primer" introduction docs -more examples diff --git a/third_party/libusb/autogen.sh b/third_party/libusb/autogen.sh deleted file mode 100755 index d5c6a19..0000000 --- a/third_party/libusb/autogen.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# use glibtoolize if it is available (darwin) -(glibtoolize --version) < /dev/null > /dev/null 2>&1 && LIBTOOLIZE=glibtoolize || LIBTOOLIZE=libtoolize - -$LIBTOOLIZE --copy --force || exit 1 -aclocal || exit 1 -autoheader || exit 1 -autoconf || exit 1 -automake -a -c || exit 1 -./configure --enable-maintainer-mode --enable-debug-log \ - --enable-examples-build $* diff --git a/third_party/libusb/config.h b/third_party/libusb/config.h deleted file mode 100644 index ac62ec9..0000000 --- a/third_party/libusb/config.h +++ /dev/null @@ -1,7 +0,0 @@ -#define DEFAULT_VISIBILITY -#define _GNU_SOURCE 1 - -// #define ENABLE_DEBUG_LOGGING 1 -// #define ENABLE_LOGGING 1 - -// #define USBI_TIMERFD_AVAILABLE 1 diff --git a/third_party/libusb/configure.ac b/third_party/libusb/configure.ac deleted file mode 100644 index 8020907..0000000 --- a/third_party/libusb/configure.ac +++ /dev/null @@ -1,198 +0,0 @@ -dnl These m4 macros are whitespace sensitive and break if moved around much. -m4_define([LU_VERSION_H], m4_include([libusb/version.h])) -m4_define([LU_DEFINE_VERSION_ATOM], - [m4_define([$1], m4_bregexp(LU_VERSION_H, - [^#define\s*$1\s*\([0-9]*\).*], [\1]))]) -m4_define([LU_DEFINE_VERSION_RC_ATOM], - [m4_define([$1], m4_bregexp(LU_VERSION_H, - [^#define\s*$1\s*"\(-rc[0-9]*\)".*], [\1]))]) -dnl The m4_bregexp() returns (only) the numbers following the #define named -dnl in the first macro parameter. m4_define() then defines the name for use -dnl in AC_INIT(). - -LU_DEFINE_VERSION_ATOM([LIBUSB_MAJOR]) -LU_DEFINE_VERSION_ATOM([LIBUSB_MINOR]) -LU_DEFINE_VERSION_ATOM([LIBUSB_MICRO]) -LU_DEFINE_VERSION_RC_ATOM([LIBUSB_RC]) - -AC_INIT([libusb], LIBUSB_MAJOR[.]LIBUSB_MINOR[.]LIBUSB_MICRO[]LIBUSB_RC, [libusb-devel@lists.sourceforge.net], [libusb], [http://www.libusb.org/]) - -# Library versioning -# These numbers should be tweaked on every release. Read carefully: -# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html -# http://sourceware.org/autobook/autobook/autobook_91.html -lt_current="1" -lt_revision="0" -lt_age="1" -LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}" - -AM_INIT_AUTOMAKE -AM_MAINTAINER_MODE - -AC_CONFIG_SRCDIR([libusb/core.c]) -AC_CONFIG_MACRO_DIR([m4]) -AM_CONFIG_HEADER([config.h]) -m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) - -AC_PREREQ([2.50]) -AC_PROG_CC -AC_PROG_LIBTOOL -AC_C_INLINE -AM_PROG_CC_C_O -AC_DEFINE([_GNU_SOURCE], 1, [Use GNU extensions]) - -LTLDFLAGS="${LTLDFLAGS} -no-undefined" - -AC_MSG_CHECKING([operating system]) -case $host in -*-linux*) - AC_DEFINE(OS_LINUX, 1, [Linux backend]) - AC_SUBST(OS_LINUX) - AC_MSG_RESULT([Linux]) - backend="linux" - AC_CHECK_LIB(rt, clock_gettime, PC_LIBS_PRIVATE="-lrt") - threads="posix" - THREAD_CFLAGS="-pthread" - PC_LIBS_PRIVATE="${PC_LIBS_PRIVATE} -pthread" - AC_CHECK_HEADERS([poll.h]) - AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument]) - ;; -*-darwin*) - AC_DEFINE(OS_DARWIN, 1, [Darwin backend]) - AC_SUBST(OS_DARWIN) - AC_MSG_RESULT([Darwin/Mac OS X]) - backend="darwin" - threads="posix" - LIBS="${LIBS} -lobjc" - PC_LIBS_PRIVATE="-Wl,-framework,IOKit -Wl,-framework,CoreFoundation" - LTLDFLAGS="${LTLDFLAGS} -Wl,-prebind" - AC_CHECK_HEADERS([poll.h]) - AC_CHECK_TYPE([nfds_t], - [AC_DEFINE([POLL_NFDS_TYPE],[nfds_t],[type of second poll() argument])], - [AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument])], - [#include <poll.h>]) - ;; -*-mingw*) - AC_MSG_RESULT([Windows]) - backend="windows" - ;; -*-cygwin*) - AC_MSG_RESULT([Cygwin (using Windows backend)]) - backend="windows" - threads="posix" - ;; -*) - AC_MSG_ERROR([unsupported operating system]) -esac -if test "$backend" = windows; then - AC_DEFINE(OS_WINDOWS, 1, [Windows backend]) - AC_SUBST(OS_WINDOWS) - PC_LIBS_PRIVATE="" - LTLDFLAGS="${LTLDFLAGS} -avoid-version -Wl,--add-stdcall-alias" - AC_CHECK_TOOL(RC, windres, no) - AC_DEFINE([POLL_NFDS_TYPE],[unsigned int],[type of second poll() argument]) -fi -AC_SUBST(THREAD_CFLAGS) -AC_SUBST(PC_LIBS_PRIVATE) -LIBS="${LIBS} ${PC_LIBS_PRIVATE}" - -AM_CONDITIONAL(OS_LINUX, test "x$backend" = xlinux) -AM_CONDITIONAL(OS_DARWIN, test "x$backend" = xdarwin) -AM_CONDITIONAL(OS_WINDOWS, test "x$backend" = xwindows) -AM_CONDITIONAL(THREADS_POSIX, test "x$threads" = xposix) -if test "$threads" = posix; then - AC_DEFINE(THREADS_POSIX, 1, [Use POSIX Threads]) -fi - -# timerfd -AC_CHECK_HEADER([sys/timerfd.h], [timerfd_h=1], [timerfd_h=0]) -AC_ARG_ENABLE([timerfd], - [AS_HELP_STRING([--enable-timerfd], - [use timerfd for timing (default auto)])], - [use_timerfd=$enableval], [use_timerfd='auto']) - -if test "x$use_timerfd" = "xyes" -a "x$timerfd_h" = "x0"; then - AC_MSG_ERROR([timerfd header not available; glibc 2.9+ required]) -fi - -AC_CHECK_DECL([TFD_NONBLOCK], [tfd_hdr_ok=yes], [tfd_hdr_ok=no], [#include <sys/timerfd.h>]) -if test "x$use_timerfd" = "xyes" -a "x$tfd_hdr_ok" = "xno"; then - AC_MSG_ERROR([timerfd header not usable; glibc 2.9+ required]) -fi - -AC_MSG_CHECKING([whether to use timerfd for timing]) -if test "x$use_timerfd" = "xno"; then - AC_MSG_RESULT([no (disabled by user)]) -else - if test "x$timerfd_h" = "x1" -a "x$tfd_hdr_ok" = "xyes"; then - AC_MSG_RESULT([yes]) - AC_DEFINE(USBI_TIMERFD_AVAILABLE, 1, [timerfd headers available]) - else - AC_MSG_RESULT([no (header not available)]) - fi -fi - -AC_CHECK_TYPES(struct timespec) - -# Message logging -AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])], - [log_enabled=$enableval], - [log_enabled='yes']) -if test "x$log_enabled" != "xno"; then - AC_DEFINE([ENABLE_LOGGING], 1, [Message logging]) -fi - -AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log], - [enable debug logging (default n)])], - [debug_log_enabled=$enableval], - [debug_log_enabled='no']) -if test "x$debug_log_enabled" != "xno"; then - AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging]) -fi - -# Examples build -AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build], - [build example applications (default n)])], - [build_examples=$enableval], - [build_examples='no']) -AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"]) - -# check for -fvisibility=hidden compiler support (GCC >= 3.4) -saved_cflags="$CFLAGS" -# -Werror required for cygwin -CFLAGS="$CFLAGS -Werror -fvisibility=hidden" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], - [VISIBILITY_CFLAGS="-fvisibility=hidden" - AC_DEFINE([DEFAULT_VISIBILITY], [__attribute__((visibility("default")))], [Default visibility]) ], - [ VISIBILITY_CFLAGS="" - AC_DEFINE([DEFAULT_VISIBILITY], [], [Default visibility]) ], - ]) -CFLAGS="$saved_cflags" - -# check for -Wno-pointer-sign compiler support (GCC >= 4) -saved_cflags="$CFLAGS" -CFLAGS="$CFLAGS -Wno-pointer-sign" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], - nopointersign_cflags="-Wno-pointer-sign", nopointersign_cflags="") -CFLAGS="$saved_cflags" - -# sigaction not available on MinGW -AC_CHECK_FUNC([sigaction], [have_sigaction=yes], [have_sigaction=no]) -AM_CONDITIONAL([HAVE_SIGACTION], [test "x$have_sigaction" = "xyes"]) - -# headers not available on all platforms but required on others -AC_CHECK_HEADERS([sys/time.h]) - -AM_CFLAGS="-std=gnu99 -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration $nopointersign_cflags -Wshadow" - -AC_SUBST(VISIBILITY_CFLAGS) -AC_SUBST(AM_CFLAGS) -AC_SUBST(LTLDFLAGS) - -AC_CONFIG_FILES([libusb-1.0.pc]) -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_FILES([libusb/Makefile]) -AC_CONFIG_FILES([examples/Makefile]) -AC_CONFIG_FILES([doc/Makefile]) -AC_CONFIG_FILES([doc/doxygen.cfg]) -AC_OUTPUT diff --git a/third_party/libusb/doc/Makefile.am b/third_party/libusb/doc/Makefile.am deleted file mode 100644 index ac5b189..0000000 --- a/third_party/libusb/doc/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -EXTRA_DIST = doxygen.cfg.in - -docs: doxygen.cfg - doxygen $^ - -docs-upload: docs - ln -s html api-1.0 - rsync -av api-1.0/ dsd_,libusb@web.sourceforge.net:htdocs/api-1.0/ - rm -f api-1.0 - diff --git a/third_party/libusb/doc/doxygen.cfg.in b/third_party/libusb/doc/doxygen.cfg.in deleted file mode 100644 index 128e1de..0000000 --- a/third_party/libusb/doc/doxygen.cfg.in +++ /dev/null @@ -1,1294 +0,0 @@ -# Doxyfile 1.5.3 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = libusb - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be extracted -# and appear in the documentation as a namespace called 'anonymous_namespace{file}', -# where file will be replaced with the base name of the file that contains the anonymous -# namespace. By default anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = NO - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command <command> <input-file>, where <command> is the value of -# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = @top_srcdir@/libusb - -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = @top_srcdir@/libusb/libusbi.h - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH -# then you must also enable this option. If you don't then doxygen will produce -# a warning and turn it on anyway - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = YES - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = YES - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = API_EXPORTED= LIBUSB_CALL= DEFAULT_VISIBILITY= - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the number -# of direct children of the root node in a graph is already larger than -# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/third_party/libusb/examples/Makefile.am b/third_party/libusb/examples/Makefile.am deleted file mode 100644 index 846af15..0000000 --- a/third_party/libusb/examples/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ -INCLUDES = -I$(top_srcdir)/libusb -noinst_PROGRAMS = lsusb - -lsusb_SOURCES = lsusb.c -lsusb_LDADD = ../libusb/libusb-1.0.la -lusb-1.0 - -if HAVE_SIGACTION -dpfp_SOURCES = dpfp.c -dpfp_LDADD = ../libusb/libusb-1.0.la -lusb-1.0 -noinst_PROGRAMS += dpfp -endif - -if THREADS_POSIX -if HAVE_SIGACTION -dpfp_threaded_SOURCES = dpfp_threaded.c -dpfp_threaded_CFLAGS = $(THREAD_CFLAGS) $(AM_CFLAGS) -dpfp_threaded_LDADD = ../libusb/libusb-1.0.la -lusb-1.0 -noinst_PROGRAMS += dpfp_threaded -endif -endif - diff --git a/third_party/libusb/examples/dpfp.c b/third_party/libusb/examples/dpfp.c deleted file mode 100644 index 1b3c3a4..0000000 --- a/third_party/libusb/examples/dpfp.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * libusb example program to manipulate U.are.U 4000B fingerprint scanner. - * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> - * - * Basic image capture program only, does not consider the powerup quirks or - * the fact that image encryption may be enabled. Not expected to work - * flawlessly all of the time. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <errno.h> -#include <signal.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> - -#include <libusb.h> - -#define EP_INTR (1 | LIBUSB_ENDPOINT_IN) -#define EP_DATA (2 | LIBUSB_ENDPOINT_IN) -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) -#define USB_RQ 0x04 -#define INTR_LENGTH 64 - -enum { - MODE_INIT = 0x00, - MODE_AWAIT_FINGER_ON = 0x10, - MODE_AWAIT_FINGER_OFF = 0x12, - MODE_CAPTURE = 0x20, - MODE_SHUT_UP = 0x30, - MODE_READY = 0x80, -}; - -static int next_state(void); - -enum { - STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1, - STATE_AWAIT_IRQ_FINGER_DETECTED, - STATE_AWAIT_MODE_CHANGE_CAPTURE, - STATE_AWAIT_IMAGE, - STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF, - STATE_AWAIT_IRQ_FINGER_REMOVED, -}; - -static int state = 0; -static struct libusb_device_handle *devh = NULL; -static unsigned char imgbuf[0x1b340]; -static unsigned char irqbuf[INTR_LENGTH]; -static struct libusb_transfer *img_transfer = NULL; -static struct libusb_transfer *irq_transfer = NULL; -static int img_idx = 0; -static int do_exit = 0; - -static int find_dpfp_device(void) -{ - devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); - return devh ? 0 : -EIO; -} - -static int print_f0_data(void) -{ - unsigned char data[0x10]; - int r; - unsigned int i; - - r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, - sizeof(data), 0); - if (r < 0) { - fprintf(stderr, "F0 error %d\n", r); - return r; - } - if ((unsigned int) r < sizeof(data)) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("F0 data:"); - for (i = 0; i < sizeof(data); i++) - printf("%02x ", data[i]); - printf("\n"); - return 0; -} - -static int get_hwstat(unsigned char *status) -{ - int r; - - r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0); - if (r < 0) { - fprintf(stderr, "read hwstat error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("hwstat reads %02x\n", *status); - return 0; -} - -static int set_hwstat(unsigned char data) -{ - int r; - - printf("set hwstat to %02x\n", data); - r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0); - if (r < 0) { - fprintf(stderr, "set hwstat error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); - return -1; - } - - return 0; -} - -static int set_mode(unsigned char data) -{ - int r; - printf("set mode %02x\n", data); - - r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0); - if (r < 0) { - fprintf(stderr, "set mode error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); - return -1; - } - - return 0; -} - -static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer) -{ - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "mode change transfer not completed!\n"); - do_exit = 2; - } - - printf("async cb_mode_changed length=%d actual_length=%d\n", - transfer->length, transfer->actual_length); - if (next_state() < 0) - do_exit = 2; -} - -static int set_mode_async(unsigned char data) -{ - unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); - struct libusb_transfer *transfer; - - if (!buf) - return -ENOMEM; - - transfer = libusb_alloc_transfer(0); - if (!transfer) { - free(buf); - return -ENOMEM; - } - - printf("async set mode %02x\n", data); - libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1); - buf[LIBUSB_CONTROL_SETUP_SIZE] = data; - libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL, - 1000); - - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK - | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; - return libusb_submit_transfer(transfer); -} - -static int do_sync_intr(unsigned char *data) -{ - int r; - int transferred; - - r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH, - &transferred, 1000); - if (r < 0) { - fprintf(stderr, "intr error %d\n", r); - return r; - } - if (transferred < INTR_LENGTH) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("recv interrupt %04x\n", *((uint16_t *) data)); - return 0; -} - -static int sync_intr(unsigned char type) -{ - int r; - unsigned char data[INTR_LENGTH]; - - while (1) { - r = do_sync_intr(data); - if (r < 0) - return r; - if (data[0] == type) - return 0; - } -} - -static int save_to_file(unsigned char *data) -{ - FILE *fd; - char filename[64]; - - sprintf(filename, "finger%d.pgm", img_idx++); - fd = fopen(filename, "w"); - if (!fd) - return -1; - - fputs("P5 384 289 255 ", fd); - (void) fwrite(data + 64, 1, 384*289, fd); - fclose(fd); - printf("saved image to %s\n", filename); - return 0; -} - -static int next_state(void) -{ - int r = 0; - printf("old state: %d\n", state); - switch (state) { - case STATE_AWAIT_IRQ_FINGER_REMOVED: - state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON; - r = set_mode_async(MODE_AWAIT_FINGER_ON); - break; - case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON: - state = STATE_AWAIT_IRQ_FINGER_DETECTED; - break; - case STATE_AWAIT_IRQ_FINGER_DETECTED: - state = STATE_AWAIT_MODE_CHANGE_CAPTURE; - r = set_mode_async(MODE_CAPTURE); - break; - case STATE_AWAIT_MODE_CHANGE_CAPTURE: - state = STATE_AWAIT_IMAGE; - break; - case STATE_AWAIT_IMAGE: - state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF; - r = set_mode_async(MODE_AWAIT_FINGER_OFF); - break; - case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF: - state = STATE_AWAIT_IRQ_FINGER_REMOVED; - break; - default: - printf("unrecognised state %d\n", state); - } - if (r < 0) { - fprintf(stderr, "error detected changing state\n"); - return r; - } - - printf("new state: %d\n", state); - return 0; -} - -static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer) -{ - unsigned char irqtype = transfer->buffer[0]; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "irq transfer status %d?\n", transfer->status); - do_exit = 2; - libusb_free_transfer(transfer); - irq_transfer = NULL; - return; - } - - printf("IRQ callback %02x\n", irqtype); - switch (state) { - case STATE_AWAIT_IRQ_FINGER_DETECTED: - if (irqtype == 0x01) { - if (next_state() < 0) { - do_exit = 2; - return; - } - } else { - printf("finger-on-sensor detected in wrong state!\n"); - } - break; - case STATE_AWAIT_IRQ_FINGER_REMOVED: - if (irqtype == 0x02) { - if (next_state() < 0) { - do_exit = 2; - return; - } - } else { - printf("finger-on-sensor detected in wrong state!\n"); - } - break; - } - if (libusb_submit_transfer(irq_transfer) < 0) - do_exit = 2; -} - -static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer) -{ - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "img transfer status %d?\n", transfer->status); - do_exit = 2; - libusb_free_transfer(transfer); - img_transfer = NULL; - return; - } - - printf("Image callback\n"); - save_to_file(imgbuf); - if (next_state() < 0) { - do_exit = 2; - return; - } - if (libusb_submit_transfer(img_transfer) < 0) - do_exit = 2; -} - -static int init_capture(void) -{ - int r; - - r = libusb_submit_transfer(irq_transfer); - if (r < 0) - return r; - - r = libusb_submit_transfer(img_transfer); - if (r < 0) { - libusb_cancel_transfer(irq_transfer); - while (irq_transfer) - if (libusb_handle_events(NULL) < 0) - break; - return r; - } - - /* start state machine */ - state = STATE_AWAIT_IRQ_FINGER_REMOVED; - return next_state(); -} - -static int do_init(void) -{ - unsigned char status; - int r; - - r = get_hwstat(&status); - if (r < 0) - return r; - - if (!(status & 0x80)) { - r = set_hwstat(status | 0x80); - if (r < 0) - return r; - r = get_hwstat(&status); - if (r < 0) - return r; - } - - status &= ~0x80; - r = set_hwstat(status); - if (r < 0) - return r; - - r = get_hwstat(&status); - if (r < 0) - return r; - - r = sync_intr(0x56); - if (r < 0) - return r; - - return 0; -} - -static int alloc_transfers(void) -{ - img_transfer = libusb_alloc_transfer(0); - if (!img_transfer) - return -ENOMEM; - - irq_transfer = libusb_alloc_transfer(0); - if (!irq_transfer) - return -ENOMEM; - - libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf, - sizeof(imgbuf), cb_img, NULL, 0); - libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf, - sizeof(irqbuf), cb_irq, NULL, 0); - - return 0; -} - -static void sighandler(int signum) -{ - do_exit = 1; -} - -int main(void) -{ - struct sigaction sigact; - int r = 1; - - r = libusb_init(NULL); - if (r < 0) { - fprintf(stderr, "failed to initialise libusb\n"); - exit(1); - } - - r = find_dpfp_device(); - if (r < 0) { - fprintf(stderr, "Could not find/open device\n"); - goto out; - } - - r = libusb_claim_interface(devh, 0); - if (r < 0) { - fprintf(stderr, "usb_claim_interface error %d\n", r); - goto out; - } - printf("claimed interface\n"); - - r = print_f0_data(); - if (r < 0) - goto out_release; - - r = do_init(); - if (r < 0) - goto out_deinit; - - /* async from here onwards */ - - r = alloc_transfers(); - if (r < 0) - goto out_deinit; - - r = init_capture(); - if (r < 0) - goto out_deinit; - - sigact.sa_handler = sighandler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGQUIT, &sigact, NULL); - - while (!do_exit) { - r = libusb_handle_events(NULL); - if (r < 0) - goto out_deinit; - } - - printf("shutting down...\n"); - - if (irq_transfer) { - r = libusb_cancel_transfer(irq_transfer); - if (r < 0) - goto out_deinit; - } - - if (img_transfer) { - r = libusb_cancel_transfer(img_transfer); - if (r < 0) - goto out_deinit; - } - - while (irq_transfer || img_transfer) - if (libusb_handle_events(NULL) < 0) - break; - - if (do_exit == 1) - r = 0; - else - r = 1; - -out_deinit: - libusb_free_transfer(img_transfer); - libusb_free_transfer(irq_transfer); - set_mode(0); - set_hwstat(0x80); -out_release: - libusb_release_interface(devh, 0); -out: - libusb_close(devh); - libusb_exit(NULL); - return r >= 0 ? r : -r; -} - diff --git a/third_party/libusb/examples/dpfp_threaded.c b/third_party/libusb/examples/dpfp_threaded.c deleted file mode 100644 index c3d314d..0000000 --- a/third_party/libusb/examples/dpfp_threaded.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * libusb example program to manipulate U.are.U 4000B fingerprint scanner. - * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> - * - * Basic image capture program only, does not consider the powerup quirks or - * the fact that image encryption may be enabled. Not expected to work - * flawlessly all of the time. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <errno.h> -#include <pthread.h> -#include <signal.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> - -#include <libusb.h> - -#define EP_INTR (1 | LIBUSB_ENDPOINT_IN) -#define EP_DATA (2 | LIBUSB_ENDPOINT_IN) -#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN) -#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT) -#define USB_RQ 0x04 -#define INTR_LENGTH 64 - -enum { - MODE_INIT = 0x00, - MODE_AWAIT_FINGER_ON = 0x10, - MODE_AWAIT_FINGER_OFF = 0x12, - MODE_CAPTURE = 0x20, - MODE_SHUT_UP = 0x30, - MODE_READY = 0x80, -}; - -static int next_state(void); - -enum { - STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1, - STATE_AWAIT_IRQ_FINGER_DETECTED, - STATE_AWAIT_MODE_CHANGE_CAPTURE, - STATE_AWAIT_IMAGE, - STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF, - STATE_AWAIT_IRQ_FINGER_REMOVED, -}; - -static int state = 0; -static struct libusb_device_handle *devh = NULL; -static unsigned char imgbuf[0x1b340]; -static unsigned char irqbuf[INTR_LENGTH]; -static struct libusb_transfer *img_transfer = NULL; -static struct libusb_transfer *irq_transfer = NULL; -static int img_idx = 0; -static int do_exit = 0; - -static pthread_t poll_thread; -static pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER; -static pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER; - -static void request_exit(int code) -{ - do_exit = code; - pthread_cond_signal(&exit_cond); -} - -static void *poll_thread_main(void *arg) -{ - int r = 0; - printf("poll thread running\n"); - - while (!do_exit) { - struct timeval tv = { 1, 0 }; - r = libusb_handle_events_timeout(NULL, &tv); - if (r < 0) { - request_exit(2); - break; - } - } - - printf("poll thread shutting down\n"); - return NULL; -} - -static int find_dpfp_device(void) -{ - devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a); - return devh ? 0 : -EIO; -} - -static int print_f0_data(void) -{ - unsigned char data[0x10]; - int r; - unsigned int i; - - r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data, - sizeof(data), 0); - if (r < 0) { - fprintf(stderr, "F0 error %d\n", r); - return r; - } - if ((unsigned int) r < sizeof(data)) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("F0 data:"); - for (i = 0; i < sizeof(data); i++) - printf("%02x ", data[i]); - printf("\n"); - return 0; -} - -static int get_hwstat(unsigned char *status) -{ - int r; - - r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0); - if (r < 0) { - fprintf(stderr, "read hwstat error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("hwstat reads %02x\n", *status); - return 0; -} - -static int set_hwstat(unsigned char data) -{ - int r; - - printf("set hwstat to %02x\n", data); - r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0); - if (r < 0) { - fprintf(stderr, "set hwstat error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); - return -1; - } - - return 0; -} - -static int set_mode(unsigned char data) -{ - int r; - printf("set mode %02x\n", data); - - r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0); - if (r < 0) { - fprintf(stderr, "set mode error %d\n", r); - return r; - } - if ((unsigned int) r < 1) { - fprintf(stderr, "short write (%d)", r); - return -1; - } - - return 0; -} - -static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer) -{ - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "mode change transfer not completed!\n"); - request_exit(2); - } - - printf("async cb_mode_changed length=%d actual_length=%d\n", - transfer->length, transfer->actual_length); - if (next_state() < 0) - request_exit(2); -} - -static int set_mode_async(unsigned char data) -{ - unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1); - struct libusb_transfer *transfer; - - if (!buf) - return -ENOMEM; - - transfer = libusb_alloc_transfer(0); - if (!transfer) { - free(buf); - return -ENOMEM; - } - - printf("async set mode %02x\n", data); - libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1); - buf[LIBUSB_CONTROL_SETUP_SIZE] = data; - libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL, - 1000); - - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK - | LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; - return libusb_submit_transfer(transfer); -} - -static int do_sync_intr(unsigned char *data) -{ - int r; - int transferred; - - r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH, - &transferred, 1000); - if (r < 0) { - fprintf(stderr, "intr error %d\n", r); - return r; - } - if (transferred < INTR_LENGTH) { - fprintf(stderr, "short read (%d)\n", r); - return -1; - } - - printf("recv interrupt %04x\n", *((uint16_t *) data)); - return 0; -} - -static int sync_intr(unsigned char type) -{ - int r; - unsigned char data[INTR_LENGTH]; - - while (1) { - r = do_sync_intr(data); - if (r < 0) - return r; - if (data[0] == type) - return 0; - } -} - -static int save_to_file(unsigned char *data) -{ - FILE *fd; - char filename[64]; - - sprintf(filename, "finger%d.pgm", img_idx++); - fd = fopen(filename, "w"); - if (!fd) - return -1; - - fputs("P5 384 289 255 ", fd); - (void) fwrite(data + 64, 1, 384*289, fd); - fclose(fd); - printf("saved image to %s\n", filename); - return 0; -} - -static int next_state(void) -{ - int r = 0; - printf("old state: %d\n", state); - switch (state) { - case STATE_AWAIT_IRQ_FINGER_REMOVED: - state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON; - r = set_mode_async(MODE_AWAIT_FINGER_ON); - break; - case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON: - state = STATE_AWAIT_IRQ_FINGER_DETECTED; - break; - case STATE_AWAIT_IRQ_FINGER_DETECTED: - state = STATE_AWAIT_MODE_CHANGE_CAPTURE; - r = set_mode_async(MODE_CAPTURE); - break; - case STATE_AWAIT_MODE_CHANGE_CAPTURE: - state = STATE_AWAIT_IMAGE; - break; - case STATE_AWAIT_IMAGE: - state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF; - r = set_mode_async(MODE_AWAIT_FINGER_OFF); - break; - case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF: - state = STATE_AWAIT_IRQ_FINGER_REMOVED; - break; - default: - printf("unrecognised state %d\n", state); - } - if (r < 0) { - fprintf(stderr, "error detected changing state\n"); - return r; - } - - printf("new state: %d\n", state); - return 0; -} - -static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer) -{ - unsigned char irqtype = transfer->buffer[0]; - - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "irq transfer status %d?\n", transfer->status); - irq_transfer = NULL; - request_exit(2); - return; - } - - printf("IRQ callback %02x\n", irqtype); - switch (state) { - case STATE_AWAIT_IRQ_FINGER_DETECTED: - if (irqtype == 0x01) { - if (next_state() < 0) { - request_exit(2); - return; - } - } else { - printf("finger-on-sensor detected in wrong state!\n"); - } - break; - case STATE_AWAIT_IRQ_FINGER_REMOVED: - if (irqtype == 0x02) { - if (next_state() < 0) { - request_exit(2); - return; - } - } else { - printf("finger-on-sensor detected in wrong state!\n"); - } - break; - } - if (libusb_submit_transfer(irq_transfer) < 0) - request_exit(2); -} - -static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer) -{ - if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { - fprintf(stderr, "img transfer status %d?\n", transfer->status); - img_transfer = NULL; - request_exit(2); - return; - } - - printf("Image callback\n"); - save_to_file(imgbuf); - if (next_state() < 0) { - request_exit(2); - return; - } - if (libusb_submit_transfer(img_transfer) < 0) - request_exit(2); -} - -static int init_capture(void) -{ - int r; - - r = libusb_submit_transfer(irq_transfer); - if (r < 0) - return r; - - r = libusb_submit_transfer(img_transfer); - if (r < 0) { - libusb_cancel_transfer(irq_transfer); - while (irq_transfer) - if (libusb_handle_events(NULL) < 0) - break; - return r; - } - - /* start state machine */ - state = STATE_AWAIT_IRQ_FINGER_REMOVED; - return next_state(); -} - -static int do_init(void) -{ - unsigned char status; - int r; - - r = get_hwstat(&status); - if (r < 0) - return r; - - if (!(status & 0x80)) { - r = set_hwstat(status | 0x80); - if (r < 0) - return r; - r = get_hwstat(&status); - if (r < 0) - return r; - } - - status &= ~0x80; - r = set_hwstat(status); - if (r < 0) - return r; - - r = get_hwstat(&status); - if (r < 0) - return r; - - r = sync_intr(0x56); - if (r < 0) - return r; - - return 0; -} - -static int alloc_transfers(void) -{ - img_transfer = libusb_alloc_transfer(0); - if (!img_transfer) - return -ENOMEM; - - irq_transfer = libusb_alloc_transfer(0); - if (!irq_transfer) - return -ENOMEM; - - libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf, - sizeof(imgbuf), cb_img, NULL, 0); - libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf, - sizeof(irqbuf), cb_irq, NULL, 0); - - return 0; -} - -static void sighandler(int signum) -{ - request_exit(1); -} - -int main(void) -{ - struct sigaction sigact; - int r = 1; - - r = libusb_init(NULL); - if (r < 0) { - fprintf(stderr, "failed to initialise libusb\n"); - exit(1); - } - - r = find_dpfp_device(); - if (r < 0) { - fprintf(stderr, "Could not find/open device\n"); - goto out; - } - - r = libusb_claim_interface(devh, 0); - if (r < 0) { - fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r)); - goto out; - } - printf("claimed interface\n"); - - r = print_f0_data(); - if (r < 0) - goto out_release; - - r = do_init(); - if (r < 0) - goto out_deinit; - - /* async from here onwards */ - - sigact.sa_handler = sighandler; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigaction(SIGINT, &sigact, NULL); - sigaction(SIGTERM, &sigact, NULL); - sigaction(SIGQUIT, &sigact, NULL); - - r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL); - if (r) - goto out_deinit; - - r = alloc_transfers(); - if (r < 0) { - request_exit(1); - pthread_join(poll_thread, NULL); - goto out_deinit; - } - - r = init_capture(); - if (r < 0) { - request_exit(1); - pthread_join(poll_thread, NULL); - goto out_deinit; - } - - while (!do_exit) { - pthread_mutex_lock(&exit_cond_lock); - pthread_cond_wait(&exit_cond, &exit_cond_lock); - pthread_mutex_unlock(&exit_cond_lock); - } - - printf("shutting down...\n"); - pthread_join(poll_thread, NULL); - - r = libusb_cancel_transfer(irq_transfer); - if (r < 0) { - request_exit(1); - goto out_deinit; - } - - r = libusb_cancel_transfer(img_transfer); - if (r < 0) { - request_exit(1); - goto out_deinit; - } - - while (img_transfer || irq_transfer) - if (libusb_handle_events(NULL) < 0) - break; - - if (do_exit == 1) - r = 0; - else - r = 1; - -out_deinit: - libusb_free_transfer(img_transfer); - libusb_free_transfer(irq_transfer); - set_mode(0); - set_hwstat(0x80); -out_release: - libusb_release_interface(devh, 0); -out: - libusb_close(devh); - libusb_exit(NULL); - return r >= 0 ? r : -r; -} - diff --git a/third_party/libusb/examples/lsusb.c b/third_party/libusb/examples/lsusb.c deleted file mode 100644 index 6ab8917..0000000 --- a/third_party/libusb/examples/lsusb.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * libusb example program to list devices on the bus - * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <stdio.h> -#include <sys/types.h> - -#include <libusb.h> - -static void print_devs(libusb_device **devs) -{ - libusb_device *dev; - int i = 0; - - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - int r = libusb_get_device_descriptor(dev, &desc); - if (r < 0) { - fprintf(stderr, "failed to get device descriptor"); - return; - } - - printf("%04x:%04x (bus %d, device %d)\n", - desc.idVendor, desc.idProduct, - libusb_get_bus_number(dev), libusb_get_device_address(dev)); - } -} - -int main(void) -{ - libusb_device **devs; - int r; - ssize_t cnt; - - r = libusb_init(NULL); - if (r < 0) - return r; - - cnt = libusb_get_device_list(NULL, &devs); - if (cnt < 0) - return (int) cnt; - - print_devs(devs); - libusb_free_device_list(devs, 1); - - libusb_exit(NULL); - return 0; -} - diff --git a/third_party/libusb/libusb-1.0.pc.in b/third_party/libusb/libusb-1.0.pc.in deleted file mode 100644 index 81b56ec..0000000 --- a/third_party/libusb/libusb-1.0.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libusb-1.0 -Description: C API for USB device access from Linux, Mac OS X and Windows userspace -Version: @VERSION@ -Libs: -L${libdir} -lusb-1.0 -Libs.private: @PC_LIBS_PRIVATE@ -Cflags: -I${includedir}/libusb-1.0 - diff --git a/third_party/libusb/libusb.gyp b/third_party/libusb/libusb.gyp deleted file mode 100644 index b57609c..0000000 --- a/third_party/libusb/libusb.gyp +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'targets': [ - { - 'target_name': 'libusb', - 'type': '<(library)', - 'sources': [ - 'libusb/core.c', - 'libusb/descriptor.c', - 'libusb/io.c', - 'libusb/sync.c', - ], - 'include_dirs': [ - '.', - 'libusb', - 'libusb/os', - ], - 'conditions': [ - [ 'OS == "linux"', { - 'sources': [ - 'libusb/os/linux_usbfs.c', - 'libusb/os/threads_posix.c', - ], - 'defines': [ - 'HAVE_POLL_H=1', - 'HAVE_SYS_TIME_H=1', - 'OS_LINUX=1', - 'POLL_NFDS_TYPE=nfds_t', - 'THREADS_POSIX=1', - ], - }], - [ 'OS == "win"', { - 'sources': [ - 'libusb/os/windows_usb.c', - 'libusb/os/threads_windows.c', - ], - 'include_dirs!': [ - '.', - ], - 'include_dirs': [ - 'msvc', - ], - }], - [ 'OS == "mac"', { - 'sources': [ - 'libusb/os/darwin_usb.c', - 'libusb/os/threads_posix.c', - ], - 'defines': [ - 'HAVE_POLL_H=1', - 'HAVE_SYS_TIME_H=1', - 'OS_DARWIN=1', - 'POLL_NFDS_TYPE=nfds_t', - 'THREADS_POSIX=1', - ], - }], - ], - }, - ], -} diff --git a/third_party/libusb/libusb/Makefile.am b/third_party/libusb/libusb/Makefile.am deleted file mode 100644 index 22661dcc..0000000 --- a/third_party/libusb/libusb/Makefile.am +++ /dev/null @@ -1,40 +0,0 @@ -lib_LTLIBRARIES = libusb-1.0.la - -LINUX_USBFS_SRC = os/linux_usbfs.c -DARWIN_USB_SRC = os/darwin_usb.c -WINDOWS_USB_SRC = os/poll_windows.c os/windows_usb.c libusb-1.0.rc - -EXTRA_DIST = $(LINUX_USBFS_SRC) $(DARWIN_USB_SRC) $(WINDOWS_USB_SRC) \ - os/threads_posix.c os/threads_windows.c - -if OS_LINUX -OS_SRC = $(LINUX_USBFS_SRC) -endif - -if OS_DARWIN -OS_SRC = $(DARWIN_USB_SRC) -AM_CFLAGS_EXT = -no-cpp-precomp -endif - -if OS_WINDOWS -OS_SRC = $(WINDOWS_USB_SRC) - -.rc.lo: - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(RC) $(RCFLAGS) -i $< -o $@ -endif - -if THREADS_POSIX -THREADS_SRC = os/threads_posix.h os/threads_posix.c -else -THREADS_SRC = os/threads_windows.h os/threads_windows.c -endif - -libusb_1_0_la_CFLAGS = $(VISIBILITY_CFLAGS) $(AM_CFLAGS) $(THREAD_CFLAGS) -libusb_1_0_la_LDFLAGS = $(LTLDFLAGS) -libusb_1_0_la_SOURCES = libusbi.h core.c descriptor.c io.c sync.c $(OS_SRC) \ - os/linux_usbfs.h os/darwin_usb.h os/windows_usb.h \ - $(THREADS_SRC) \ - os/poll_posix.h os/poll_windows.h - -hdrdir = $(includedir)/libusb-1.0 -hdr_HEADERS = libusb.h diff --git a/third_party/libusb/libusb/core.c b/third_party/libusb/libusb/core.c deleted file mode 100644 index a91c77b..0000000 --- a/third_party/libusb/libusb/core.c +++ /dev/null @@ -1,1781 +0,0 @@ -/* - * Core functions for libusb - * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> - -#include <errno.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> - -#include "libusbi.h" - -#if defined(OS_LINUX) -const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; -#elif defined(OS_DARWIN) -const struct usbi_os_backend * const usbi_backend = &darwin_backend; -#elif defined(OS_WINDOWS) -const struct usbi_os_backend * const usbi_backend = &windows_backend; -#else -#error "Unsupported OS" -#endif - -struct libusb_context *usbi_default_context = NULL; -static int default_context_refcnt = 0; -static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER; - -/** - * \mainpage libusb-1.0 API Reference - * - * \section intro Introduction - * - * libusb is an open source library that allows you to communicate with USB - * devices from userspace. For more info, see the - * <a href="http://libusb.sourceforge.net">libusb homepage</a>. - * - * This documentation is aimed at application developers wishing to - * communicate with USB peripherals from their own software. After reviewing - * this documentation, feedback and questions can be sent to the - * <a href="http://sourceforge.net/mail/?group_id=1674">libusb-devel mailing - * list</a>. - * - * This documentation assumes knowledge of how to operate USB devices from - * a software standpoint (descriptors, configurations, interfaces, endpoints, - * control/bulk/interrupt/isochronous transfers, etc). Full information - * can be found in the <a href="http://www.usb.org/developers/docs/">USB 2.0 - * Specification</a> which is available for free download. You can probably - * find less verbose introductions by searching the web. - * - * \section features Library features - * - * - All transfer types supported (control/bulk/interrupt/isochronous) - * - 2 transfer interfaces: - * -# Synchronous (simple) - * -# Asynchronous (more complicated, but more powerful) - * - Thread safe (although the asynchronous interface means that you - * usually won't need to thread) - * - Lightweight with lean API - * - Compatible with libusb-0.1 through the libusb-compat-0.1 translation layer - * - * \section gettingstarted Getting Started - * - * To begin reading the API documentation, start with the Modules page which - * links to the different categories of libusb's functionality. - * - * One decision you will have to make is whether to use the synchronous - * or the asynchronous data transfer interface. The \ref io documentation - * provides some insight into this topic. - * - * Some example programs can be found in the libusb source distribution under - * the "examples" subdirectory. The libusb homepage includes a list of - * real-life project examples which use libusb. - * - * \section errorhandling Error handling - * - * libusb functions typically return 0 on success or a negative error code - * on failure. These negative error codes relate to LIBUSB_ERROR constants - * which are listed on the \ref misc "miscellaneous" documentation page. - * - * \section msglog Debug message logging - * - * libusb does not log any messages by default. Your application is therefore - * free to close stdout/stderr and those descriptors may be reused without - * worry. - * - * The libusb_set_debug() function can be used to enable stdout/stderr logging - * of certain messages. Under standard configuration, libusb doesn't really - * log much at all, so you are advised to use this function to enable all - * error/warning/informational messages. It will help you debug problems with - * your software. - * - * The logged messages are unstructured. There is no one-to-one correspondence - * between messages being logged and success or failure return codes from - * libusb functions. There is no format to the messages, so you should not - * try to capture or parse them. They are not and will not be localized. - * These messages are not suitable for being passed to your application user; - * instead, you should interpret the error codes returned from libusb functions - * and provide appropriate notification to the user. The messages are simply - * there to aid you as a programmer, and if you're confused because you're - * getting a strange error code from a libusb function, enabling message - * logging may give you a suitable explanation. - * - * The LIBUSB_DEBUG environment variable can be used to enable message logging - * at run-time. This environment variable should be set to a number, which is - * interpreted the same as the libusb_set_debug() parameter. When this - * environment variable is set, the message logging verbosity level is fixed - * and libusb_set_debug() effectively does nothing. - * - * libusb can be compiled without any logging functions, useful for embedded - * systems. In this case, libusb_set_debug() and the LIBUSB_DEBUG environment - * variable have no effects. - * - * libusb can also be compiled with verbose debugging messages. When the - * library is compiled in this way, all messages of all verbosities are always - * logged. libusb_set_debug() and the LIBUSB_DEBUG environment variable have - * no effects. - * - * \section remarks Other remarks - * - * libusb does have imperfections. The \ref caveats "caveats" page attempts - * to document these. - */ - -/** - * \page caveats Caveats - * - * \section devresets Device resets - * - * The libusb_reset_device() function allows you to reset a device. If your - * program has to call such a function, it should obviously be aware that - * the reset will cause device state to change (e.g. register values may be - * reset). - * - * The problem is that any other program could reset the device your program - * is working with, at any time. libusb does not offer a mechanism to inform - * you when this has happened, so if someone else resets your device it will - * not be clear to your own program why the device state has changed. - * - * Ultimately, this is a limitation of writing drivers in userspace. - * Separation from the USB stack in the underlying kernel makes it difficult - * for the operating system to deliver such notifications to your program. - * The Linux kernel USB stack allows such reset notifications to be delivered - * to in-kernel USB drivers, but it is not clear how such notifications could - * be delivered to second-class drivers that live in userspace. - * - * \section blockonly Blocking-only functionality - * - * The functionality listed below is only available through synchronous, - * blocking functions. There are no asynchronous/non-blocking alternatives, - * and no clear ways of implementing these. - * - * - Configuration activation (libusb_set_configuration()) - * - Interface/alternate setting activation (libusb_set_interface_alt_setting()) - * - Releasing of interfaces (libusb_release_interface()) - * - Clearing of halt/stall condition (libusb_clear_halt()) - * - Device resets (libusb_reset_device()) - * - * \section nohotplug No hotplugging - * - * libusb-1.0 lacks functionality for providing notifications of when devices - * are added or removed. This functionality is planned to be implemented - * for libusb-1.1. - * - * That said, there is basic disconnection handling for open device handles: - * - If there are ongoing transfers, libusb's handle_events loop will detect - * disconnections and complete ongoing transfers with the - * LIBUSB_TRANSFER_NO_DEVICE status code. - * - Many functions such as libusb_set_configuration() return the special - * LIBUSB_ERROR_NO_DEVICE error code when the device has been disconnected. - * - * \section configsel Configuration selection and handling - * - * When libusb presents a device handle to an application, there is a chance - * that the corresponding device may be in unconfigured state. For devices - * with multiple configurations, there is also a chance that the configuration - * currently selected is not the one that the application wants to use. - * - * The obvious solution is to add a call to libusb_set_configuration() early - * on during your device initialization routines, but there are caveats to - * be aware of: - * -# If the device is already in the desired configuration, calling - * libusb_set_configuration() using the same configuration value will cause - * a lightweight device reset. This may not be desirable behaviour. - * -# libusb will be unable to change configuration if the device is in - * another configuration and other programs or drivers have claimed - * interfaces under that configuration. - * -# In the case where the desired configuration is already active, libusb - * may not even be able to perform a lightweight device reset. For example, - * take my USB keyboard with fingerprint reader: I'm interested in driving - * the fingerprint reader interface through libusb, but the kernel's - * USB-HID driver will almost always have claimed the keyboard interface. - * Because the kernel has claimed an interface, it is not even possible to - * perform the lightweight device reset, so libusb_set_configuration() will - * fail. (Luckily the device in question only has a single configuration.) - * - * One solution to some of the above problems is to consider the currently - * active configuration. If the configuration we want is already active, then - * we don't have to select any configuration: -\code -cfg = libusb_get_configuration(dev); -if (cfg != desired) - libusb_set_configuration(dev, desired); -\endcode - * - * This is probably suitable for most scenarios, but is inherently racy: - * another application or driver may change the selected configuration - * <em>after</em> the libusb_get_configuration() call. - * - * Even in cases where libusb_set_configuration() succeeds, consider that other - * applications or drivers may change configuration after your application - * calls libusb_set_configuration(). - * - * One possible way to lock your device into a specific configuration is as - * follows: - * -# Set the desired configuration (or use the logic above to realise that - * it is already in the desired configuration) - * -# Claim the interface that you wish to use - * -# Check that the currently active configuration is the one that you want - * to use. - * - * The above method works because once an interface is claimed, no application - * or driver is able to select another configuration. - * - * \section earlycomp Early transfer completion - * - * NOTE: This section is currently Linux-centric. I am not sure if any of these - * considerations apply to Darwin or other platforms. - * - * When a transfer completes early (i.e. when less data is received/sent in - * any one packet than the transfer buffer allows for) then libusb is designed - * to terminate the transfer immediately, not transferring or receiving any - * more data unless other transfers have been queued by the user. - * - * On legacy platforms, libusb is unable to do this in all situations. After - * the incomplete packet occurs, "surplus" data may be transferred. Prior to - * libusb v1.0.2, this information was lost (and for device-to-host transfers, - * the corresponding data was discarded). As of libusb v1.0.3, this information - * is kept (the data length of the transfer is updated) and, for device-to-host - * transfers, any surplus data was added to the buffer. Still, this is not - * a nice solution because it loses the information about the end of the short - * packet, and the user probably wanted that surplus data to arrive in the next - * logical transfer. - * - * A previous workaround was to only ever submit transfers of size 16kb or - * less. - * - * As of libusb v1.0.4 and Linux v2.6.32, this is fixed. A technical - * explanation of this issue follows. - * - * When you ask libusb to submit a bulk transfer larger than 16kb in size, - * libusb breaks it up into a number of smaller subtransfers. This is because - * the usbfs kernel interface only accepts transfers of up to 16kb in size. - * The subtransfers are submitted all at once so that the kernel can queue - * them at the hardware level, therefore maximizing bus throughput. - * - * On legacy platforms, this caused problems when transfers completed early. - * Upon this event, the kernel would terminate all further packets in that - * subtransfer (but not any following ones). libusb would note this event and - * immediately cancel any following subtransfers that had been queued, - * but often libusb was not fast enough, and the following subtransfers had - * started before libusb got around to cancelling them. - * - * Thanks to an API extension to usbfs, this is fixed with recent kernel and - * libusb releases. The solution was to allow libusb to communicate to the - * kernel where boundaries occur between logical libusb-level transfers. When - * a short transfer (or other error) occurs, the kernel will cancel all the - * subtransfers until the boundary without allowing those transfers to start. - */ - -/** - * \page contexts Contexts - * - * It is possible that libusb may be used simultaneously from two independent - * libraries linked into the same executable. For example, if your application - * has a plugin-like system which allows the user to dynamically load a range - * of modules into your program, it is feasible that two independently - * developed modules may both use libusb. - * - * libusb is written to allow for these multiple user scenarios. The two - * "instances" of libusb will not interfere: libusb_set_debug() calls - * from one user will not affect the same settings for other users, other - * users can continue using libusb after one of them calls libusb_exit(), etc. - * - * This is made possible through libusb's <em>context</em> concept. When you - * call libusb_init(), you are (optionally) given a context. You can then pass - * this context pointer back into future libusb functions. - * - * In order to keep things simple for more simplistic applications, it is - * legal to pass NULL to all functions requiring a context pointer (as long as - * you're sure no other code will attempt to use libusb from the same process). - * When you pass NULL, the default context will be used. The default context - * is created the first time a process calls libusb_init() when no other - * context is alive. Contexts are destroyed during libusb_exit(). - * - * The default context is reference-counted and can be shared. That means that - * if libusb_init(NULL) is called twice within the same process, the two - * users end up sharing the same context. The deinitialization and freeing of - * the default context will only happen when the last user calls libusb_exit(). - * In other words, the default context is created and initialized when its - * reference count goes from 0 to 1, and is deinitialized and destroyed when - * its reference count goes from 1 to 0. - * - * You may be wondering why only a subset of libusb functions require a - * context pointer in their function definition. Internally, libusb stores - * context pointers in other objects (e.g. libusb_device instances) and hence - * can infer the context from those objects. - */ - -/** - * @defgroup lib Library initialization/deinitialization - * This page details how to initialize and deinitialize libusb. Initialization - * must be performed before using any libusb functionality, and similarly you - * must not call any libusb functions after deinitialization. - */ - -/** - * @defgroup dev Device handling and enumeration - * The functionality documented below is designed to help with the following - * operations: - * - Enumerating the USB devices currently attached to the system - * - Choosing a device to operate from your software - * - Opening and closing the chosen device - * - * \section nutshell In a nutshell... - * - * The description below really makes things sound more complicated than they - * actually are. The following sequence of function calls will be suitable - * for almost all scenarios and does not require you to have such a deep - * understanding of the resource management issues: - * \code -// discover devices -libusb_device **list; -libusb_device *found = NULL; -ssize_t cnt = libusb_get_device_list(NULL, &list); -ssize_t i = 0; -int err = 0; -if (cnt < 0) - error(); - -for (i = 0; i < cnt; i++) { - libusb_device *device = list[i]; - if (is_interesting(device)) { - found = device; - break; - } -} - -if (found) { - libusb_device_handle *handle; - - err = libusb_open(found, &handle); - if (err) - error(); - // etc -} - -libusb_free_device_list(list, 1); -\endcode - * - * The two important points: - * - You asked libusb_free_device_list() to unreference the devices (2nd - * parameter) - * - You opened the device before freeing the list and unreferencing the - * devices - * - * If you ended up with a handle, you can now proceed to perform I/O on the - * device. - * - * \section devshandles Devices and device handles - * libusb has a concept of a USB device, represented by the - * \ref libusb_device opaque type. A device represents a USB device that - * is currently or was previously connected to the system. Using a reference - * to a device, you can determine certain information about the device (e.g. - * you can read the descriptor data). - * - * The libusb_get_device_list() function can be used to obtain a list of - * devices currently connected to the system. This is known as device - * discovery. - * - * Just because you have a reference to a device does not mean it is - * necessarily usable. The device may have been unplugged, you may not have - * permission to operate such device, or another program or driver may be - * using the device. - * - * When you've found a device that you'd like to operate, you must ask - * libusb to open the device using the libusb_open() function. Assuming - * success, libusb then returns you a <em>device handle</em> - * (a \ref libusb_device_handle pointer). All "real" I/O operations then - * operate on the handle rather than the original device pointer. - * - * \section devref Device discovery and reference counting - * - * Device discovery (i.e. calling libusb_get_device_list()) returns a - * freshly-allocated list of devices. The list itself must be freed when - * you are done with it. libusb also needs to know when it is OK to free - * the contents of the list - the devices themselves. - * - * To handle these issues, libusb provides you with two separate items: - * - A function to free the list itself - * - A reference counting system for the devices inside - * - * New devices presented by the libusb_get_device_list() function all have a - * reference count of 1. You can increase and decrease reference count using - * libusb_ref_device() and libusb_unref_device(). A device is destroyed when - * its reference count reaches 0. - * - * With the above information in mind, the process of opening a device can - * be viewed as follows: - * -# Discover devices using libusb_get_device_list(). - * -# Choose the device that you want to operate, and call libusb_open(). - * -# Unref all devices in the discovered device list. - * -# Free the discovered device list. - * - * The order is important - you must not unreference the device before - * attempting to open it, because unreferencing it may destroy the device. - * - * For convenience, the libusb_free_device_list() function includes a - * parameter to optionally unreference all the devices in the list before - * freeing the list itself. This combines steps 3 and 4 above. - * - * As an implementation detail, libusb_open() actually adds a reference to - * the device in question. This is because the device remains available - * through the handle via libusb_get_device(). The reference is deleted during - * libusb_close(). - */ - -/** @defgroup misc Miscellaneous */ - -/* we traverse usbfs without knowing how many devices we are going to find. - * so we create this discovered_devs model which is similar to a linked-list - * which grows when required. it can be freed once discovery has completed, - * eliminating the need for a list node in the libusb_device structure - * itself. */ -#define DISCOVERED_DEVICES_SIZE_STEP 8 - -static struct discovered_devs *discovered_devs_alloc(void) -{ - struct discovered_devs *ret = - malloc(sizeof(*ret) + (sizeof(void *) * DISCOVERED_DEVICES_SIZE_STEP)); - - if (ret) { - ret->len = 0; - ret->capacity = DISCOVERED_DEVICES_SIZE_STEP; - } - return ret; -} - -/* append a device to the discovered devices collection. may realloc itself, - * returning new discdevs. returns NULL on realloc failure. */ -struct discovered_devs *discovered_devs_append( - struct discovered_devs *discdevs, struct libusb_device *dev) -{ - size_t len = discdevs->len; - size_t capacity; - - /* if there is space, just append the device */ - if (len < discdevs->capacity) { - discdevs->devices[len] = libusb_ref_device(dev); - discdevs->len++; - return discdevs; - } - - /* exceeded capacity, need to grow */ - usbi_dbg("need to increase capacity"); - capacity = discdevs->capacity + DISCOVERED_DEVICES_SIZE_STEP; - discdevs = realloc(discdevs, - sizeof(*discdevs) + (sizeof(void *) * capacity)); - if (discdevs) { - discdevs->capacity = capacity; - discdevs->devices[len] = libusb_ref_device(dev); - discdevs->len++; - } - - return discdevs; -} - -static void discovered_devs_free(struct discovered_devs *discdevs) -{ - size_t i; - - for (i = 0; i < discdevs->len; i++) - libusb_unref_device(discdevs->devices[i]); - - free(discdevs); -} - -/* Allocate a new device with a specific session ID. The returned device has - * a reference count of 1. */ -struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, - unsigned long session_id) -{ - size_t priv_size = usbi_backend->device_priv_size; - struct libusb_device *dev = calloc(1, sizeof(*dev) + priv_size); - int r; - - if (!dev) - return NULL; - - r = usbi_mutex_init(&dev->lock, NULL); - if (r) { - free(dev); - return NULL; - } - - dev->ctx = ctx; - dev->refcnt = 1; - dev->session_data = session_id; - dev->speed = LIBUSB_SPEED_UNKNOWN; - memset(&dev->os_priv, 0, priv_size); - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_add(&dev->list, &ctx->usb_devs); - usbi_mutex_unlock(&ctx->usb_devs_lock); - return dev; -} - -/* Perform some final sanity checks on a newly discovered device. If this - * function fails (negative return code), the device should not be added - * to the discovered device list. */ -int usbi_sanitize_device(struct libusb_device *dev) -{ - int r; - unsigned char raw_desc[DEVICE_DESC_LENGTH]; - uint8_t num_configurations; - int host_endian; - - r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian); - if (r < 0) - return r; - - num_configurations = raw_desc[DEVICE_DESC_LENGTH - 1]; - if (num_configurations > USB_MAXCONFIG) { - usbi_err(DEVICE_CTX(dev), "too many configurations"); - return LIBUSB_ERROR_IO; - } else if (0 == num_configurations) - usbi_dbg("zero configurations, maybe an unauthorized device"); - - dev->num_configurations = num_configurations; - return 0; -} - -/* Examine libusb's internal list of known devices, looking for one with - * a specific session ID. Returns the matching device if it was found, and - * NULL otherwise. */ -struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, - unsigned long session_id) -{ - struct libusb_device *dev; - struct libusb_device *ret = NULL; - - usbi_mutex_lock(&ctx->usb_devs_lock); - list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) - if (dev->session_data == session_id) { - ret = dev; - break; - } - usbi_mutex_unlock(&ctx->usb_devs_lock); - - return ret; -} - -/** @ingroup dev - * Returns a list of USB devices currently attached to the system. This is - * your entry point into finding a USB device to operate. - * - * You are expected to unreference all the devices when you are done with - * them, and then free the list with libusb_free_device_list(). Note that - * libusb_free_device_list() can unref all the devices for you. Be careful - * not to unreference a device you are about to open until after you have - * opened it. - * - * This return value of this function indicates the number of devices in - * the resultant list. The list is actually one element larger, as it is - * NULL-terminated. - * - * \param ctx the context to operate on, or NULL for the default context - * \param list output location for a list of devices. Must be later freed with - * libusb_free_device_list(). - * \returns The number of devices in the outputted list, or any - * \ref libusb_error according to errors encountered by the backend. - */ -ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, - libusb_device ***list) -{ - struct discovered_devs *discdevs = discovered_devs_alloc(); - struct libusb_device **ret; - int r = 0; - ssize_t i, len; - USBI_GET_CONTEXT(ctx); - usbi_dbg(""); - - if (!discdevs) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_backend->get_device_list(ctx, &discdevs); - if (r < 0) { - len = r; - goto out; - } - - /* convert discovered_devs into a list */ - len = discdevs->len; - ret = malloc(sizeof(void *) * (len + 1)); - if (!ret) { - len = LIBUSB_ERROR_NO_MEM; - goto out; - } - - ret[len] = NULL; - for (i = 0; i < len; i++) { - struct libusb_device *dev = discdevs->devices[i]; - ret[i] = libusb_ref_device(dev); - } - *list = ret; - -out: - discovered_devs_free(discdevs); - return len; -} - -/** \ingroup dev - * Frees a list of devices previously discovered using - * libusb_get_device_list(). If the unref_devices parameter is set, the - * reference count of each device in the list is decremented by 1. - * \param list the list to free - * \param unref_devices whether to unref the devices in the list - */ -void API_EXPORTED libusb_free_device_list(libusb_device **list, - int unref_devices) -{ - if (!list) - return; - - if (unref_devices) { - int i = 0; - struct libusb_device *dev; - - while ((dev = list[i++]) != NULL) - libusb_unref_device(dev); - } - free(list); -} - -/** \ingroup dev - * Get the number of the bus that a device is connected to. - * \param dev a device - * \returns the bus number - */ -uint8_t API_EXPORTED libusb_get_bus_number(libusb_device *dev) -{ - return dev->bus_number; -} - -/** \ingroup dev - * Get the address of the device on the bus it is connected to. - * \param dev a device - * \returns the device address - */ -uint8_t API_EXPORTED libusb_get_device_address(libusb_device *dev) -{ - return dev->device_address; -} - -/** \ingroup dev - * Get the negotiated connection speed for a device. - * \param dev a device - * \returns a \ref libusb_speed code, where LIBUSB_SPEED_UNKNOWN means that - * the OS doesn't know or doesn't support returning the negotiated speed. - */ -int API_EXPORTED libusb_get_device_speed(libusb_device *dev) -{ - return dev->speed; -} - -static const struct libusb_endpoint_descriptor *find_endpoint( - struct libusb_config_descriptor *config, unsigned char endpoint) -{ - int iface_idx; - for (iface_idx = 0; iface_idx < config->bNumInterfaces; iface_idx++) { - const struct libusb_interface *iface = &config->interface[iface_idx]; - int altsetting_idx; - - for (altsetting_idx = 0; altsetting_idx < iface->num_altsetting; - altsetting_idx++) { - const struct libusb_interface_descriptor *altsetting - = &iface->altsetting[altsetting_idx]; - int ep_idx; - - for (ep_idx = 0; ep_idx < altsetting->bNumEndpoints; ep_idx++) { - const struct libusb_endpoint_descriptor *ep = - &altsetting->endpoint[ep_idx]; - if (ep->bEndpointAddress == endpoint) - return ep; - } - } - } - return NULL; -} - -/** \ingroup dev - * Convenience function to retrieve the wMaxPacketSize value for a particular - * endpoint in the active device configuration. - * - * This function was originally intended to be of assistance when setting up - * isochronous transfers, but a design mistake resulted in this function - * instead. It simply returns the wMaxPacketSize value without considering - * its contents. If you're dealing with isochronous transfers, you probably - * want libusb_get_max_iso_packet_size() instead. - * - * \param dev a device - * \param endpoint address of the endpoint in question - * \returns the wMaxPacketSize value - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_OTHER on other failure - */ -int API_EXPORTED libusb_get_max_packet_size(libusb_device *dev, - unsigned char endpoint) -{ - struct libusb_config_descriptor *config; - const struct libusb_endpoint_descriptor *ep; - int r; - - r = libusb_get_active_config_descriptor(dev, &config); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "could not retrieve active config descriptor"); - return LIBUSB_ERROR_OTHER; - } - - ep = find_endpoint(config, endpoint); - if (!ep) - return LIBUSB_ERROR_NOT_FOUND; - - r = ep->wMaxPacketSize; - libusb_free_config_descriptor(config); - return r; -} - -/** \ingroup dev - * Calculate the maximum packet size which a specific endpoint is capable is - * sending or receiving in the duration of 1 microframe - * - * Only the active configution is examined. The calculation is based on the - * wMaxPacketSize field in the endpoint descriptor as described in section - * 9.6.6 in the USB 2.0 specifications. - * - * If acting on an isochronous or interrupt endpoint, this function will - * multiply the value found in bits 0:10 by the number of transactions per - * microframe (determined by bits 11:12). Otherwise, this function just - * returns the numeric value found in bits 0:10. - * - * This function is useful for setting up isochronous transfers, for example - * you might pass the return value from this function to - * libusb_set_iso_packet_lengths() in order to set the length field of every - * isochronous packet in a transfer. - * - * Since v1.0.3. - * - * \param dev a device - * \param endpoint address of the endpoint in question - * \returns the maximum packet size which can be sent/received on this endpoint - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_OTHER on other failure - */ -int API_EXPORTED libusb_get_max_iso_packet_size(libusb_device *dev, - unsigned char endpoint) -{ - struct libusb_config_descriptor *config; - const struct libusb_endpoint_descriptor *ep; - enum libusb_transfer_type ep_type; - uint16_t val; - int r; - - r = libusb_get_active_config_descriptor(dev, &config); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "could not retrieve active config descriptor"); - return LIBUSB_ERROR_OTHER; - } - - ep = find_endpoint(config, endpoint); - if (!ep) - return LIBUSB_ERROR_NOT_FOUND; - - val = ep->wMaxPacketSize; - ep_type = ep->bmAttributes & 0x3; - libusb_free_config_descriptor(config); - - r = val & 0x07ff; - if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS - || ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) - r *= (1 + ((val >> 11) & 3)); - return r; -} - -/** \ingroup dev - * Increment the reference count of a device. - * \param dev the device to reference - * \returns the same device - */ -DEFAULT_VISIBILITY -libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev) -{ - usbi_mutex_lock(&dev->lock); - dev->refcnt++; - usbi_mutex_unlock(&dev->lock); - return dev; -} - -/** \ingroup dev - * Decrement the reference count of a device. If the decrement operation - * causes the reference count to reach zero, the device shall be destroyed. - * \param dev the device to unreference - */ -void API_EXPORTED libusb_unref_device(libusb_device *dev) -{ - int refcnt; - - if (!dev) - return; - - usbi_mutex_lock(&dev->lock); - refcnt = --dev->refcnt; - usbi_mutex_unlock(&dev->lock); - - if (refcnt == 0) { - usbi_dbg("destroy device %d.%d", dev->bus_number, dev->device_address); - - if (usbi_backend->destroy_device) - usbi_backend->destroy_device(dev); - - usbi_mutex_lock(&dev->ctx->usb_devs_lock); - list_del(&dev->list); - usbi_mutex_unlock(&dev->ctx->usb_devs_lock); - - usbi_mutex_destroy(&dev->lock); - free(dev); - } -} - -/* - * Interrupt the iteration of the event handling thread, so that it picks - * up the new fd. - */ -void usbi_fd_notification(struct libusb_context *ctx) -{ - unsigned char dummy = 1; - ssize_t r; - - if (ctx == NULL) - return; - - /* record that we are messing with poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify++; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* write some data on control pipe to interrupt event handlers */ - r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { - usbi_warn(ctx, "internal signalling write failed"); - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - return; - } - - /* take event handling lock */ - libusb_lock_events(ctx); - - /* read the dummy data */ - r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) - usbi_warn(ctx, "internal signalling read failed"); - - /* we're done with modifying poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* Release event handling lock and wake up event waiters */ - libusb_unlock_events(ctx); -} - -/** \ingroup dev - * Open a device and obtain a device handle. A handle allows you to perform - * I/O on the device in question. - * - * Internally, this function adds a reference to the device and makes it - * available to you through libusb_get_device(). This reference is removed - * during libusb_close(). - * - * This is a non-blocking function; no requests are sent over the bus. - * - * \param dev the device to open - * \param handle output location for the returned device handle pointer. Only - * populated when the return code is 0. - * \returns 0 on success - * \returns LIBUSB_ERROR_NO_MEM on memory allocation failure - * \returns LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_open(libusb_device *dev, - libusb_device_handle **handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev); - struct libusb_device_handle *_handle; - size_t priv_size = usbi_backend->device_handle_priv_size; - int r; - usbi_dbg("open %d.%d", dev->bus_number, dev->device_address); - - _handle = malloc(sizeof(*_handle) + priv_size); - if (!_handle) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_mutex_init(&_handle->lock, NULL); - if (r) { - free(_handle); - return LIBUSB_ERROR_OTHER; - } - - _handle->dev = libusb_ref_device(dev); - _handle->claimed_interfaces = 0; - memset(&_handle->os_priv, 0, priv_size); - - r = usbi_backend->open(_handle); - if (r < 0) { - usbi_dbg("open %d.%d returns %d", dev->bus_number, dev->device_address, r); - libusb_unref_device(dev); - usbi_mutex_destroy(&_handle->lock); - free(_handle); - return r; - } - - usbi_mutex_lock(&ctx->open_devs_lock); - list_add(&_handle->list, &ctx->open_devs); - usbi_mutex_unlock(&ctx->open_devs_lock); - *handle = _handle; - - /* At this point, we want to interrupt any existing event handlers so - * that they realise the addition of the new device's poll fd. One - * example when this is desirable is if the user is running a separate - * dedicated libusb events handling thread, which is running with a long - * or infinite timeout. We want to interrupt that iteration of the loop, - * so that it picks up the new fd, and then continues. */ - usbi_fd_notification(ctx); - - return 0; -} - -/** \ingroup dev - * Convenience function for finding a device with a particular - * <tt>idVendor</tt>/<tt>idProduct</tt> combination. This function is intended - * for those scenarios where you are using libusb to knock up a quick test - * application - it allows you to avoid calling libusb_get_device_list() and - * worrying about traversing/freeing the list. - * - * This function has limitations and is hence not intended for use in real - * applications: if multiple devices have the same IDs it will only - * give you the first one, etc. - * - * \param ctx the context to operate on, or NULL for the default context - * \param vendor_id the idVendor value to search for - * \param product_id the idProduct value to search for - * \returns a handle for the first found device, or NULL on error or if the - * device could not be found. */ -DEFAULT_VISIBILITY -libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( - libusb_context *ctx, uint16_t vendor_id, uint16_t product_id) -{ - struct libusb_device **devs; - struct libusb_device *found = NULL; - struct libusb_device *dev; - struct libusb_device_handle *handle = NULL; - size_t i = 0; - int r; - - if (libusb_get_device_list(ctx, &devs) < 0) - return NULL; - - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - r = libusb_get_device_descriptor(dev, &desc); - if (r < 0) - goto out; - if (desc.idVendor == vendor_id && desc.idProduct == product_id) { - found = dev; - break; - } - } - - if (found) { - r = libusb_open(found, &handle); - if (r < 0) - handle = NULL; - } - -out: - libusb_free_device_list(devs, 1); - return handle; -} - -static void do_close(struct libusb_context *ctx, - struct libusb_device_handle *dev_handle) -{ - struct usbi_transfer *itransfer; - struct usbi_transfer *tmp; - - libusb_lock_events(ctx); - - /* remove any transfers in flight that are for this device */ - usbi_mutex_lock(&ctx->flying_transfers_lock); - - /* safe iteration because transfers may be being deleted */ - list_for_each_entry_safe(itransfer, tmp, &ctx->flying_transfers, list, struct usbi_transfer) { - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - if (transfer->dev_handle != dev_handle) - continue; - - if (!(itransfer->flags & USBI_TRANSFER_DEVICE_DISAPPEARED)) { - usbi_err(ctx, "Device handle closed while transfer was still being processed, but the device is still connected as far as we know"); - - if (itransfer->flags & USBI_TRANSFER_CANCELLING) - usbi_warn(ctx, "A cancellation for an in-flight transfer hasn't completed but closing the device handle"); - else - usbi_err(ctx, "A cancellation hasn't even been scheduled on the transfer for which the device is closing"); - } - - /* remove from the list of in-flight transfers and make sure - * we don't accidentally use the device handle in the future - * (or that such accesses will be easily caught and identified as a crash) - */ - usbi_mutex_lock(&itransfer->lock); - list_del(&itransfer->list); - transfer->dev_handle = NULL; - usbi_mutex_unlock(&itransfer->lock); - - /* it is up to the user to free up the actual transfer struct. this is - * just making sure that we don't attempt to process the transfer after - * the device handle is invalid - */ - usbi_dbg("Removed transfer %p from the in-flight list because device handle %p closed", - transfer, dev_handle); - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - libusb_unlock_events(ctx); - - usbi_mutex_lock(&ctx->open_devs_lock); - list_del(&dev_handle->list); - usbi_mutex_unlock(&ctx->open_devs_lock); - - usbi_backend->close(dev_handle); - libusb_unref_device(dev_handle->dev); - usbi_mutex_destroy(&dev_handle->lock); - free(dev_handle); -} - -/** \ingroup dev - * Close a device handle. Should be called on all open handles before your - * application exits. - * - * Internally, this function destroys the reference that was added by - * libusb_open() on the given device. - * - * This is a non-blocking function; no requests are sent over the bus. - * - * \param dev_handle the handle to close - */ -void API_EXPORTED libusb_close(libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx; - unsigned char dummy = 1; - ssize_t r; - - if (!dev_handle) - return; - usbi_dbg(""); - - ctx = HANDLE_CTX(dev_handle); - - /* Similarly to libusb_open(), we want to interrupt all event handlers - * at this point. More importantly, we want to perform the actual close of - * the device while holding the event handling lock (preventing any other - * thread from doing event handling) because we will be removing a file - * descriptor from the polling loop. */ - - /* record that we are messing with poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify++; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* write some data on control pipe to interrupt event handlers */ - r = usbi_write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy)); - if (r <= 0) { - usbi_warn(ctx, "internal signalling write failed, closing anyway"); - do_close(ctx, dev_handle); - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - return; - } - - /* take event handling lock */ - libusb_lock_events(ctx); - - /* read the dummy data */ - r = usbi_read(ctx->ctrl_pipe[0], &dummy, sizeof(dummy)); - if (r <= 0) - usbi_warn(ctx, "internal signalling read failed, closing anyway"); - - /* Close the device */ - do_close(ctx, dev_handle); - - /* we're done with modifying poll fds */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - ctx->pollfd_modify--; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - - /* Release event handling lock and wake up event waiters */ - libusb_unlock_events(ctx); -} - -/** \ingroup dev - * Get the underlying device for a handle. This function does not modify - * the reference count of the returned device, so do not feel compelled to - * unreference it when you are done. - * \param dev_handle a device handle - * \returns the underlying device - */ -DEFAULT_VISIBILITY -libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle) -{ - return dev_handle->dev; -} - -/** \ingroup dev - * Determine the bConfigurationValue of the currently active configuration. - * - * You could formulate your own control request to obtain this information, - * but this function has the advantage that it may be able to retrieve the - * information from operating system caches (no I/O involved). - * - * If the OS does not cache this information, then this function will block - * while a control transfer is submitted to retrieve the information. - * - * This function will return a value of 0 in the <tt>config</tt> output - * parameter if the device is in unconfigured state. - * - * \param dev a device handle - * \param config output location for the bConfigurationValue of the active - * configuration (only valid for return code 0) - * \returns 0 on success - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_get_configuration(libusb_device_handle *dev, - int *config) -{ - int r = LIBUSB_ERROR_NOT_SUPPORTED; - - usbi_dbg(""); - if (usbi_backend->get_configuration) - r = usbi_backend->get_configuration(dev, config); - - if (r == LIBUSB_ERROR_NOT_SUPPORTED) { - uint8_t tmp = 0; - usbi_dbg("falling back to control message"); - r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000); - if (r == 0) { - usbi_err(HANDLE_CTX(dev), "zero bytes returned in ctrl transfer?"); - r = LIBUSB_ERROR_IO; - } else if (r == 1) { - r = 0; - *config = tmp; - } else { - usbi_dbg("control failed, error %d", r); - } - } - - if (r == 0) - usbi_dbg("active config %d", *config); - - return r; -} - -/** \ingroup dev - * Set the active configuration for a device. - * - * The operating system may or may not have already set an active - * configuration on the device. It is up to your application to ensure the - * correct configuration is selected before you attempt to claim interfaces - * and perform other operations. - * - * If you call this function on a device already configured with the selected - * configuration, then this function will act as a lightweight device reset: - * it will issue a SET_CONFIGURATION request using the current configuration, - * causing most USB-related device state to be reset (altsetting reset to zero, - * endpoint halts cleared, toggles reset). - * - * You cannot change/reset configuration if your application has claimed - * interfaces - you should free them with libusb_release_interface() first. - * You cannot change/reset configuration if other applications or drivers have - * claimed interfaces. - * - * A configuration value of -1 will put the device in unconfigured state. - * The USB specifications state that a configuration value of 0 does this, - * however buggy devices exist which actually have a configuration 0. - * - * You should always use this function rather than formulating your own - * SET_CONFIGURATION control request. This is because the underlying operating - * system needs to know when such changes happen. - * - * This is a blocking function. - * - * \param dev a device handle - * \param configuration the bConfigurationValue of the configuration you - * wish to activate, or -1 if you wish to put the device in unconfigured state - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the requested configuration does not exist - * \returns LIBUSB_ERROR_BUSY if interfaces are currently claimed - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev, - int configuration) -{ - usbi_dbg("configuration %d", configuration); - return usbi_backend->set_configuration(dev, configuration); -} - -/** \ingroup dev - * Claim an interface on a given device handle. You must claim the interface - * you wish to use before you can perform I/O on any of its endpoints. - * - * It is legal to attempt to claim an already-claimed interface, in which - * case libusb just returns 0 without doing anything. - * - * Claiming of interfaces is a purely logical operation; it does not cause - * any requests to be sent over the bus. Interface claiming is used to - * instruct the underlying operating system that your application wishes - * to take ownership of the interface. - * - * This is a non-blocking function. - * - * \param dev a device handle - * \param interface_number the <tt>bInterfaceNumber</tt> of the interface you - * wish to claim - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the requested interface does not exist - * \returns LIBUSB_ERROR_BUSY if another program or driver has claimed the - * interface - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns a LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev, - int interface_number) -{ - int r = 0; - - usbi_dbg("interface %d", interface_number); - if (interface_number >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - usbi_mutex_lock(&dev->lock); - if (dev->claimed_interfaces & (1 << interface_number)) - goto out; - - r = usbi_backend->claim_interface(dev, interface_number); - if (r == 0) - dev->claimed_interfaces |= 1 << interface_number; - -out: - usbi_mutex_unlock(&dev->lock); - return r; -} - -/** \ingroup dev - * Release an interface previously claimed with libusb_claim_interface(). You - * should release all claimed interfaces before closing a device handle. - * - * This is a blocking function. A SET_INTERFACE control request will be sent - * to the device, resetting interface state to the first alternate setting. - * - * \param dev a device handle - * \param interface_number the <tt>bInterfaceNumber</tt> of the - * previously-claimed interface - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_release_interface(libusb_device_handle *dev, - int interface_number) -{ - int r; - - usbi_dbg("interface %d", interface_number); - if (interface_number >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - usbi_mutex_lock(&dev->lock); - if (!(dev->claimed_interfaces & (1 << interface_number))) { - r = LIBUSB_ERROR_NOT_FOUND; - goto out; - } - - r = usbi_backend->release_interface(dev, interface_number); - if (r == 0) - dev->claimed_interfaces &= ~(1 << interface_number); - -out: - usbi_mutex_unlock(&dev->lock); - return r; -} - -/** \ingroup dev - * Activate an alternate setting for an interface. The interface must have - * been previously claimed with libusb_claim_interface(). - * - * You should always use this function rather than formulating your own - * SET_INTERFACE control request. This is because the underlying operating - * system needs to know when such changes happen. - * - * This is a blocking function. - * - * \param dev a device handle - * \param interface_number the <tt>bInterfaceNumber</tt> of the - * previously-claimed interface - * \param alternate_setting the <tt>bAlternateSetting</tt> of the alternate - * setting to activate - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the interface was not claimed, or the - * requested alternate setting does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_set_interface_alt_setting(libusb_device_handle *dev, - int interface_number, int alternate_setting) -{ - usbi_dbg("interface %d altsetting %d", - interface_number, alternate_setting); - if (interface_number >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - usbi_mutex_lock(&dev->lock); - if (!(dev->claimed_interfaces & (1 << interface_number))) { - usbi_mutex_unlock(&dev->lock); - return LIBUSB_ERROR_NOT_FOUND; - } - usbi_mutex_unlock(&dev->lock); - - return usbi_backend->set_interface_altsetting(dev, interface_number, - alternate_setting); -} - -/** \ingroup dev - * Clear the halt/stall condition for an endpoint. Endpoints with halt status - * are unable to receive or transmit data until the halt condition is stalled. - * - * You should cancel all pending transfers before attempting to clear the halt - * condition. - * - * This is a blocking function. - * - * \param dev a device handle - * \param endpoint the endpoint to clear halt status - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_clear_halt(libusb_device_handle *dev, - unsigned char endpoint) -{ - usbi_dbg("endpoint %x", endpoint); - return usbi_backend->clear_halt(dev, endpoint); -} - -/** \ingroup dev - * Perform a USB port reset to reinitialize a device. The system will attempt - * to restore the previous configuration and alternate settings after the - * reset has completed. - * - * If the reset fails, the descriptors change, or the previous state cannot be - * restored, the device will appear to be disconnected and reconnected. This - * means that the device handle is no longer valid (you should close it) and - * rediscover the device. A return code of LIBUSB_ERROR_NOT_FOUND indicates - * when this is the case. - * - * This is a blocking function which usually incurs a noticeable delay. - * - * \param dev a handle of the device to reset - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the - * device has been disconnected - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_reset_device(libusb_device_handle *dev) -{ - usbi_dbg(""); - return usbi_backend->reset_device(dev); -} - -/** \ingroup dev - * Determine if a kernel driver is active on an interface. If a kernel driver - * is active, you cannot claim the interface, and libusb will be unable to - * perform I/O. - * - * This functionality is not available on Windows. - * - * \param dev a device handle - * \param interface_number the interface to check - * \returns 0 if no kernel driver is active - * \returns 1 if a kernel driver is active - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_detach_kernel_driver() - */ -int API_EXPORTED libusb_kernel_driver_active(libusb_device_handle *dev, - int interface_number) -{ - usbi_dbg("interface %d", interface_number); - if (usbi_backend->kernel_driver_active) - return usbi_backend->kernel_driver_active(dev, interface_number); - else - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -/** \ingroup dev - * Detach a kernel driver from an interface. If successful, you will then be - * able to claim the interface and perform I/O. - * - * This functionality is not available on Darwin or Windows. - * - * \param dev a device handle - * \param interface_number the interface to detach the driver from - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_kernel_driver_active() - */ -int API_EXPORTED libusb_detach_kernel_driver(libusb_device_handle *dev, - int interface_number) -{ - usbi_dbg("interface %d", interface_number); - if (usbi_backend->detach_kernel_driver) - return usbi_backend->detach_kernel_driver(dev, interface_number); - else - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -/** \ingroup dev - * Re-attach an interface's kernel driver, which was previously detached - * using libusb_detach_kernel_driver(). This call is only effective on - * Linux and returns LIBUSB_ERROR_NOT_SUPPORTED on all other platforms. - * - * This functionality is not available on Darwin or Windows. - * - * \param dev a device handle - * \param interface_number the interface to attach the driver from - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * \returns LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality - * is not available - * \returns LIBUSB_ERROR_BUSY if the driver cannot be attached because the - * interface is claimed by a program or driver - * \returns another LIBUSB_ERROR code on other failure - * \see libusb_kernel_driver_active() - */ -int API_EXPORTED libusb_attach_kernel_driver(libusb_device_handle *dev, - int interface_number) -{ - usbi_dbg("interface %d", interface_number); - if (usbi_backend->attach_kernel_driver) - return usbi_backend->attach_kernel_driver(dev, interface_number); - else - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -/** \ingroup lib - * Set message verbosity. - * - Level 0: no messages ever printed by the library (default) - * - Level 1: error messages are printed to stderr - * - Level 2: warning and error messages are printed to stderr - * - Level 3: informational messages are printed to stdout, warning and error - * messages are printed to stderr - * - * The default level is 0, which means no messages are ever printed. If you - * choose to increase the message verbosity level, ensure that your - * application does not close the stdout/stderr file descriptors. - * - * You are advised to set level 3. libusb is conservative with its message - * logging and most of the time, will only log messages that explain error - * conditions and other oddities. This will help you debug your software. - * - * If the LIBUSB_DEBUG environment variable was set when libusb was - * initialized, this function does nothing: the message verbosity is fixed - * to the value in the environment variable. - * - * If libusb was compiled without any message logging, this function does - * nothing: you'll never get any messages. - * - * If libusb was compiled with verbose debug message logging, this function - * does nothing: you'll always get messages from all levels. - * - * \param ctx the context to operate on, or NULL for the default context - * \param level debug level to set - */ -void API_EXPORTED libusb_set_debug(libusb_context *ctx, int level) -{ - USBI_GET_CONTEXT(ctx); - if (!ctx->debug_fixed) - ctx->debug = level; -} - -/** \ingroup lib - * Initialize libusb. This function must be called before calling any other - * libusb function. - * - * If you do not provide an output location for a context pointer, a default - * context will be created. If there was already a default context, it will - * be reused (and nothing will be initialized/reinitialized). - * - * \param context Optional output location for context pointer. - * Only valid on return code 0. - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see contexts - */ -int API_EXPORTED libusb_init(libusb_context **context) -{ - char *dbg = getenv("LIBUSB_DEBUG"); - struct libusb_context *ctx; - int r; - - usbi_mutex_static_lock(&default_context_lock); - if (!context && usbi_default_context) { - r = 0; - usbi_dbg("reusing default context"); - default_context_refcnt++; - usbi_mutex_static_unlock(&default_context_lock); - return 0; - } - - ctx = malloc(sizeof(*ctx)); - if (!ctx) { - r = LIBUSB_ERROR_NO_MEM; - goto err_unlock; - } - memset(ctx, 0, sizeof(*ctx)); - - if (dbg) { - ctx->debug = atoi(dbg); - if (ctx->debug) - ctx->debug_fixed = 1; - } - - usbi_dbg(""); - - if (usbi_backend->init) { - r = usbi_backend->init(ctx); - if (r) - goto err_free_ctx; - } - - usbi_mutex_init(&ctx->usb_devs_lock, NULL); - usbi_mutex_init(&ctx->open_devs_lock, NULL); - list_init(&ctx->usb_devs); - list_init(&ctx->open_devs); - - r = usbi_io_init(ctx); - if (r < 0) { - if (usbi_backend->exit) - usbi_backend->exit(); - goto err_destroy_mutex; - } - - if (context) { - *context = ctx; - } else if (!usbi_default_context) { - usbi_dbg("created default context"); - usbi_default_context = ctx; - default_context_refcnt++; - } - usbi_mutex_static_unlock(&default_context_lock); - - return 0; - -err_destroy_mutex: - usbi_mutex_destroy(&ctx->open_devs_lock); - usbi_mutex_destroy(&ctx->usb_devs_lock); -err_free_ctx: - free(ctx); -err_unlock: - usbi_mutex_static_unlock(&default_context_lock); - return r; -} - -/** \ingroup lib - * Deinitialize libusb. Should be called after closing all open devices and - * before your application terminates. - * \param ctx the context to deinitialize, or NULL for the default context - */ -void API_EXPORTED libusb_exit(struct libusb_context *ctx) -{ - usbi_dbg(""); - USBI_GET_CONTEXT(ctx); - - /* if working with default context, only actually do the deinitialization - * if we're the last user */ - if (ctx == usbi_default_context) { - usbi_mutex_static_lock(&default_context_lock); - if (--default_context_refcnt > 0) { - usbi_dbg("not destroying default context"); - usbi_mutex_static_unlock(&default_context_lock); - return; - } - usbi_dbg("destroying default context"); - usbi_default_context = NULL; - usbi_mutex_static_unlock(&default_context_lock); - } - - /* a little sanity check. doesn't bother with open_devs locking because - * unless there is an application bug, nobody will be accessing this. */ - if (!list_empty(&ctx->open_devs)) - usbi_warn(ctx, "application left some devices open"); - - usbi_io_exit(ctx); - if (usbi_backend->exit) - usbi_backend->exit(); - - usbi_mutex_destroy(&ctx->open_devs_lock); - usbi_mutex_destroy(&ctx->usb_devs_lock); - free(ctx); -} - -/** \ingroup misc - * Check if the running library has a given capability. - * - * \param capability the \ref libusb_capability to check for - * \returns 1 if the running library has the capability, 0 otherwise - */ -int API_EXPORTED libusb_has_capability(uint32_t capability) -{ - switch (capability) { - case LIBUSB_CAN_GET_DEVICE_SPEED: - return 1; - default: - break; - } - return 0; -} - -void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level, - const char *function, const char *format, va_list args) -{ - FILE *stream = stdout; - const char *prefix; - -#ifndef ENABLE_DEBUG_LOGGING - USBI_GET_CONTEXT(ctx); - if (!ctx->debug) - return; - if (level == LOG_LEVEL_WARNING && ctx->debug < 2) - return; - if (level == LOG_LEVEL_INFO && ctx->debug < 3) - return; -#endif - - switch (level) { - case LOG_LEVEL_INFO: - prefix = "info"; - break; - case LOG_LEVEL_WARNING: - stream = stderr; - prefix = "warning"; - break; - case LOG_LEVEL_ERROR: - stream = stderr; - prefix = "error"; - break; - case LOG_LEVEL_DEBUG: - stream = stderr; - prefix = "debug"; - break; - default: - stream = stderr; - prefix = "unknown"; - break; - } - - fprintf(stream, "libusb:%s [%s] ", prefix, function); - - vfprintf(stream, format, args); - - fprintf(stream, "\n"); -} - -void usbi_log(struct libusb_context *ctx, enum usbi_log_level level, - const char *function, const char *format, ...) -{ - va_list args; - - va_start (args, format); - usbi_log_v(ctx, level, function, format, args); - va_end (args); -} - -/** \ingroup misc - * Returns a constant NULL-terminated string with the ASCII name of a libusb - * error code. The caller must not free() the returned string. - * - * \param error_code The \ref libusb_error code to return the name of. - * \returns The error name, or the string **UNKNOWN** if the value of - * error_code is not a known error code. - */ -DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_error_name(int error_code) -{ - enum libusb_error error = error_code; - switch (error) { - case LIBUSB_SUCCESS: - return "LIBUSB_SUCCESS"; - case LIBUSB_ERROR_IO: - return "LIBUSB_ERROR_IO"; - case LIBUSB_ERROR_INVALID_PARAM: - return "LIBUSB_ERROR_INVALID_PARAM"; - case LIBUSB_ERROR_ACCESS: - return "LIBUSB_ERROR_ACCESS"; - case LIBUSB_ERROR_NO_DEVICE: - return "LIBUSB_ERROR_NO_DEVICE"; - case LIBUSB_ERROR_NOT_FOUND: - return "LIBUSB_ERROR_NOT_FOUND"; - case LIBUSB_ERROR_BUSY: - return "LIBUSB_ERROR_BUSY"; - case LIBUSB_ERROR_TIMEOUT: - return "LIBUSB_ERROR_TIMEOUT"; - case LIBUSB_ERROR_OVERFLOW: - return "LIBUSB_ERROR_OVERFLOW"; - case LIBUSB_ERROR_PIPE: - return "LIBUSB_ERROR_PIPE"; - case LIBUSB_ERROR_INTERRUPTED: - return "LIBUSB_ERROR_INTERRUPTED"; - case LIBUSB_ERROR_NO_MEM: - return "LIBUSB_ERROR_NO_MEM"; - case LIBUSB_ERROR_NOT_SUPPORTED: - return "LIBUSB_ERROR_NOT_SUPPORTED"; - case LIBUSB_ERROR_OTHER: - return "LIBUSB_ERROR_OTHER"; - } - return "**UNKNOWN**"; -} diff --git a/third_party/libusb/libusb/descriptor.c b/third_party/libusb/libusb/descriptor.c deleted file mode 100644 index e358e9e..0000000 --- a/third_party/libusb/libusb/descriptor.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * USB descriptor handling functions for libusb - * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "libusbi.h" - -#define DESC_HEADER_LENGTH 2 -#define DEVICE_DESC_LENGTH 18 -#define CONFIG_DESC_LENGTH 9 -#define INTERFACE_DESC_LENGTH 9 -#define ENDPOINT_DESC_LENGTH 7 -#define ENDPOINT_AUDIO_DESC_LENGTH 9 - -/** @defgroup desc USB descriptors - * This page details how to examine the various standard USB descriptors - * for detected devices - */ - -/* set host_endian if the w values are already in host endian format, - * as opposed to bus endian. */ -int usbi_parse_descriptor(unsigned char *source, const char *descriptor, - void *dest, int host_endian) -{ - unsigned char *sp = source, *dp = dest; - uint16_t w; - const char *cp; - - for (cp = descriptor; *cp; cp++) { - switch (*cp) { - case 'b': /* 8-bit byte */ - *dp++ = *sp++; - break; - case 'w': /* 16-bit word, convert from little endian to CPU */ - dp += ((uintptr_t)dp & 1); /* Align to word boundary */ - - if (host_endian) { - memcpy(dp, sp, 2); - } else { - w = (sp[1] << 8) | sp[0]; - *((uint16_t *)dp) = w; - } - sp += 2; - dp += 2; - break; - } - } - - return (int) (sp - source); -} - -static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) -{ - if (endpoint->extra) - free((unsigned char *) endpoint->extra); -} - -static int parse_endpoint(struct libusb_context *ctx, - struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, - int size, int host_endian) -{ - struct usb_descriptor_header header; - unsigned char *extra; - unsigned char *begin; - int parsed = 0; - int len; - - usbi_parse_descriptor(buffer, "bb", &header, 0); - - /* Everything should be fine being passed into here, but we sanity */ - /* check JIC */ - if (header.bLength > size) { - usbi_err(ctx, "ran out of descriptors parsing"); - return -1; - } - - if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { - usbi_err(ctx, "unexpected descriptor %x (expected %x)", - header.bDescriptorType, LIBUSB_DT_ENDPOINT); - return parsed; - } - - if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) - usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian); - else if (header.bLength >= ENDPOINT_DESC_LENGTH) - usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian); - - buffer += header.bLength; - size -= header.bLength; - parsed += header.bLength; - - /* Skip over the rest of the Class Specific or Vendor Specific */ - /* descriptors */ - begin = buffer; - while (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - - if (header.bLength < 2) { - usbi_err(ctx, "invalid descriptor length %d", header.bLength); - return -1; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header.bDescriptorType == LIBUSB_DT_INTERFACE) || - (header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) - break; - - usbi_dbg("skipping descriptor %x", header.bDescriptorType); - buffer += header.bLength; - size -= header.bLength; - parsed += header.bLength; - } - - /* Copy any unknown descriptors into a storage area for drivers */ - /* to later parse */ - len = (int)(buffer - begin); - if (!len) { - endpoint->extra = NULL; - endpoint->extra_length = 0; - return parsed; - } - - extra = malloc(len); - endpoint->extra = extra; - if (!extra) { - endpoint->extra_length = 0; - return LIBUSB_ERROR_NO_MEM; - } - - memcpy(extra, begin, len); - endpoint->extra_length = len; - - return parsed; -} - -static void clear_interface(struct libusb_interface *usb_interface) -{ - int i; - int j; - - if (usb_interface->altsetting) { - for (i = 0; i < usb_interface->num_altsetting; i++) { - struct libusb_interface_descriptor *ifp = - (struct libusb_interface_descriptor *) - usb_interface->altsetting + i; - if (ifp->extra) - free((void *) ifp->extra); - if (ifp->endpoint) { - for (j = 0; j < ifp->bNumEndpoints; j++) - clear_endpoint((struct libusb_endpoint_descriptor *) - ifp->endpoint + j); - free((void *) ifp->endpoint); - } - } - free((void *) usb_interface->altsetting); - usb_interface->altsetting = NULL; - } - -} - -static int parse_interface(libusb_context *ctx, - struct libusb_interface *usb_interface, unsigned char *buffer, int size, - int host_endian) -{ - int i; - int len; - int r; - int parsed = 0; - size_t tmp; - struct usb_descriptor_header header; - struct libusb_interface_descriptor *ifp; - unsigned char *begin; - - usb_interface->num_altsetting = 0; - - while (size >= INTERFACE_DESC_LENGTH) { - struct libusb_interface_descriptor *altsetting = - (struct libusb_interface_descriptor *) usb_interface->altsetting; - altsetting = realloc(altsetting, - sizeof(struct libusb_interface_descriptor) * - (usb_interface->num_altsetting + 1)); - if (!altsetting) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - usb_interface->altsetting = altsetting; - - ifp = altsetting + usb_interface->num_altsetting; - usb_interface->num_altsetting++; - usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); - ifp->extra = NULL; - ifp->extra_length = 0; - ifp->endpoint = NULL; - - /* Skip over the interface */ - buffer += ifp->bLength; - parsed += ifp->bLength; - size -= ifp->bLength; - - begin = buffer; - - /* Skip over any interface, class or vendor descriptors */ - while (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - if (header.bLength < 2) { - usbi_err(ctx, "invalid descriptor of length %d", - header.bLength); - r = LIBUSB_ERROR_IO; - goto err; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || - (header.bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) - break; - - buffer += header.bLength; - parsed += header.bLength; - size -= header.bLength; - } - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - ifp->extra = malloc(len); - if (!ifp->extra) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - memcpy((unsigned char *) ifp->extra, begin, len); - ifp->extra_length = len; - } - - /* Did we hit an unexpected descriptor? */ - if (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - if ((header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) { - return parsed; - } - } - - if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { - usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); - r = LIBUSB_ERROR_IO; - goto err; - } - - if (ifp->bNumEndpoints > 0) { - struct libusb_endpoint_descriptor *endpoint; - tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint_descriptor); - endpoint = malloc(tmp); - ifp->endpoint = endpoint; - if (!endpoint) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - - memset(endpoint, 0, tmp); - for (i = 0; i < ifp->bNumEndpoints; i++) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - - if (header.bLength > size) { - usbi_err(ctx, "ran out of descriptors parsing"); - r = LIBUSB_ERROR_IO; - goto err; - } - - r = parse_endpoint(ctx, endpoint + i, buffer, size, - host_endian); - if (r < 0) - goto err; - - buffer += r; - parsed += r; - size -= r; - } - } - - /* We check to see if it's an alternate to this one */ - ifp = (struct libusb_interface_descriptor *) buffer; - if (size < LIBUSB_DT_INTERFACE_SIZE || - ifp->bDescriptorType != LIBUSB_DT_INTERFACE || - !ifp->bAlternateSetting) - return parsed; - } - - return parsed; -err: - clear_interface(usb_interface); - return r; -} - -static void clear_configuration(struct libusb_config_descriptor *config) -{ - if (config->interface) { - int i; - for (i = 0; i < config->bNumInterfaces; i++) - clear_interface((struct libusb_interface *) - config->interface + i); - free((void *) config->interface); - } - if (config->extra) - free((void *) config->extra); -} - -static int parse_configuration(struct libusb_context *ctx, - struct libusb_config_descriptor *config, unsigned char *buffer, - int host_endian) -{ - int i; - int r; - int size; - size_t tmp; - struct usb_descriptor_header header; - struct libusb_interface *usb_interface; - - usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian); - size = config->wTotalLength; - - if (config->bNumInterfaces > USB_MAXINTERFACES) { - usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); - return LIBUSB_ERROR_IO; - } - - tmp = config->bNumInterfaces * sizeof(struct libusb_interface); - usb_interface = malloc(tmp); - config->interface = usb_interface; - if (!config->interface) - return LIBUSB_ERROR_NO_MEM; - - memset(usb_interface, 0, tmp); - buffer += config->bLength; - size -= config->bLength; - - config->extra = NULL; - config->extra_length = 0; - - for (i = 0; i < config->bNumInterfaces; i++) { - int len; - unsigned char *begin; - - /* Skip over the rest of the Class Specific or Vendor */ - /* Specific descriptors */ - begin = buffer; - while (size >= DESC_HEADER_LENGTH) { - usbi_parse_descriptor(buffer, "bb", &header, 0); - - if ((header.bLength > size) || - (header.bLength < DESC_HEADER_LENGTH)) { - usbi_err(ctx, "invalid descriptor length of %d", - header.bLength); - r = LIBUSB_ERROR_IO; - goto err; - } - - /* If we find another "proper" descriptor then we're done */ - if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || - (header.bDescriptorType == LIBUSB_DT_INTERFACE) || - (header.bDescriptorType == LIBUSB_DT_CONFIG) || - (header.bDescriptorType == LIBUSB_DT_DEVICE)) - break; - - usbi_dbg("skipping descriptor 0x%x\n", header.bDescriptorType); - buffer += header.bLength; - size -= header.bLength; - } - - /* Copy any unknown descriptors into a storage area for */ - /* drivers to later parse */ - len = (int)(buffer - begin); - if (len) { - /* FIXME: We should realloc and append here */ - if (!config->extra_length) { - config->extra = malloc(len); - if (!config->extra) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - - memcpy((unsigned char *) config->extra, begin, len); - config->extra_length = len; - } - } - - r = parse_interface(ctx, usb_interface + i, buffer, size, host_endian); - if (r < 0) - goto err; - - buffer += r; - size -= r; - } - - return size; - -err: - clear_configuration(config); - return r; -} - -/** \ingroup desc - * Get the USB device descriptor for a given device. - * - * This is a non-blocking function; the device descriptor is cached in memory. - * - * \param dev the device - * \param desc output location for the descriptor data - * \returns 0 on success or a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, - struct libusb_device_descriptor *desc) -{ - unsigned char raw_desc[DEVICE_DESC_LENGTH]; - int host_endian = 0; - int r; - - usbi_dbg(""); - r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian); - if (r < 0) - return r; - - memcpy((unsigned char *) desc, raw_desc, sizeof(raw_desc)); - if (!host_endian) { - desc->bcdUSB = libusb_le16_to_cpu(desc->bcdUSB); - desc->idVendor = libusb_le16_to_cpu(desc->idVendor); - desc->idProduct = libusb_le16_to_cpu(desc->idProduct); - desc->bcdDevice = libusb_le16_to_cpu(desc->bcdDevice); - } - return 0; -} - -/** \ingroup desc - * Get the USB configuration descriptor for the currently active configuration. - * This is a non-blocking function which does not involve any requests being - * sent to the device. - * - * \param dev a device - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_config_descriptor - */ -int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, - struct libusb_config_descriptor **config) -{ - struct libusb_config_descriptor *_config = malloc(sizeof(*_config)); - unsigned char tmp[8]; - unsigned char *buf = NULL; - int host_endian = 0; - int r; - - usbi_dbg(""); - if (!_config) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp), - &host_endian); - if (r < 0) - goto err; - - usbi_parse_descriptor(tmp, "bbw", _config, host_endian); - buf = malloc(_config->wTotalLength); - if (!buf) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - - r = usbi_backend->get_active_config_descriptor(dev, buf, - _config->wTotalLength, &host_endian); - if (r < 0) - goto err; - - r = parse_configuration(dev->ctx, _config, buf, host_endian); - if (r < 0) { - usbi_err(dev->ctx, "parse_configuration failed with error %d", r); - goto err; - } else if (r > 0) { - usbi_warn(dev->ctx, "descriptor data still left"); - } - - free(buf); - *config = _config; - return 0; - -err: - free(_config); - if (buf) - free(buf); - return r; -} - -/** \ingroup desc - * Get a USB configuration descriptor based on its index. - * This is a non-blocking function which does not involve any requests being - * sent to the device. - * - * \param dev a device - * \param config_index the index of the configuration you wish to retrieve - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_active_config_descriptor() - * \see libusb_get_config_descriptor_by_value() - */ -int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, - uint8_t config_index, struct libusb_config_descriptor **config) -{ - struct libusb_config_descriptor *_config; - unsigned char tmp[8]; - unsigned char *buf = NULL; - int host_endian = 0; - int r; - - usbi_dbg("index %d", config_index); - if (config_index >= dev->num_configurations) - return LIBUSB_ERROR_NOT_FOUND; - - _config = malloc(sizeof(*_config)); - if (!_config) - return LIBUSB_ERROR_NO_MEM; - - r = usbi_backend->get_config_descriptor(dev, config_index, tmp, - sizeof(tmp), &host_endian); - if (r < 0) - goto err; - - usbi_parse_descriptor(tmp, "bbw", _config, host_endian); - buf = malloc(_config->wTotalLength); - if (!buf) { - r = LIBUSB_ERROR_NO_MEM; - goto err; - } - - host_endian = 0; - r = usbi_backend->get_config_descriptor(dev, config_index, buf, - _config->wTotalLength, &host_endian); - if (r < 0) - goto err; - - r = parse_configuration(dev->ctx, _config, buf, host_endian); - if (r < 0) { - usbi_err(dev->ctx, "parse_configuration failed with error %d", r); - goto err; - } else if (r > 0) { - usbi_warn(dev->ctx, "descriptor data still left"); - } - - free(buf); - *config = _config; - return 0; - -err: - free(_config); - if (buf) - free(buf); - return r; -} - -/* iterate through all configurations, returning the index of the configuration - * matching a specific bConfigurationValue in the idx output parameter, or -1 - * if the config was not found. - * returns 0 or a LIBUSB_ERROR code - */ -int usbi_get_config_index_by_value(struct libusb_device *dev, - uint8_t bConfigurationValue, int *idx) -{ - uint8_t i; - - usbi_dbg("value %d", bConfigurationValue); - for (i = 0; i < dev->num_configurations; i++) { - unsigned char tmp[6]; - int host_endian; - int r = usbi_backend->get_config_descriptor(dev, i, tmp, sizeof(tmp), - &host_endian); - if (r < 0) - return r; - if (tmp[5] == bConfigurationValue) { - *idx = i; - return 0; - } - } - - *idx = -1; - return 0; -} - -/** \ingroup desc - * Get a USB configuration descriptor with a specific bConfigurationValue. - * This is a non-blocking function which does not involve any requests being - * sent to the device. - * - * \param dev a device - * \param bConfigurationValue the bConfigurationValue of the configuration you - * wish to retrieve - * \param config output location for the USB configuration descriptor. Only - * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() - * after use. - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * \returns another LIBUSB_ERROR code on error - * \see libusb_get_active_config_descriptor() - * \see libusb_get_config_descriptor() - */ -int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, - uint8_t bConfigurationValue, struct libusb_config_descriptor **config) -{ - int idx; - int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx); - if (r < 0) - return r; - else if (idx == -1) - return LIBUSB_ERROR_NOT_FOUND; - else - return libusb_get_config_descriptor(dev, (uint8_t) idx, config); -} - -/** \ingroup desc - * Free a configuration descriptor obtained from - * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). - * It is safe to call this function with a NULL config parameter, in which - * case the function simply returns. - * - * \param config the configuration descriptor to free - */ -void API_EXPORTED libusb_free_config_descriptor( - struct libusb_config_descriptor *config) -{ - if (!config) - return; - - clear_configuration(config); - free(config); -} - -/** \ingroup desc - * Retrieve a string descriptor in C style ASCII. - * - * Wrapper around libusb_get_string_descriptor(). Uses the first language - * supported by the device. - * - * \param dev a device handle - * \param desc_index the index of the descriptor to retrieve - * \param data output buffer for ASCII string descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev, - uint8_t desc_index, unsigned char *data, int length) -{ - unsigned char tbuf[255]; /* Some devices choke on size > 255 */ - int r, si, di; - uint16_t langid; - - /* Asking for the zero'th index is special - it returns a string - * descriptor that contains all the language IDs supported by the - * device. Typically there aren't many - often only one. Language - * IDs are 16 bit numbers, and they start at the third byte in the - * descriptor. There's also no point in trying to read descriptor 0 - * with this function. See USB 2.0 specification section 9.6.7 for - * more information. - */ - - if (desc_index == 0) - return LIBUSB_ERROR_INVALID_PARAM; - - r = libusb_get_string_descriptor(dev, 0, 0, tbuf, sizeof(tbuf)); - if (r < 0) - return r; - - if (r < 4) - return LIBUSB_ERROR_IO; - - langid = tbuf[2] | (tbuf[3] << 8); - - r = libusb_get_string_descriptor(dev, desc_index, langid, tbuf, - sizeof(tbuf)); - if (r < 0) - return r; - - if (tbuf[1] != LIBUSB_DT_STRING) - return LIBUSB_ERROR_IO; - - if (tbuf[0] > r) - return LIBUSB_ERROR_IO; - - for (di = 0, si = 2; si < tbuf[0]; si += 2) { - if (di >= (length - 1)) - break; - - if (tbuf[si + 1]) /* high byte */ - data[di++] = '?'; - else - data[di++] = tbuf[si]; - } - - data[di] = 0; - return di; -} - diff --git a/third_party/libusb/libusb/io.c b/third_party/libusb/libusb/io.c deleted file mode 100644 index 51b641d..0000000 --- a/third_party/libusb/libusb/io.c +++ /dev/null @@ -1,2445 +0,0 @@ -/* - * I/O functions for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <errno.h> -#include <signal.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#ifdef USBI_TIMERFD_AVAILABLE -#include <sys/timerfd.h> -#endif - -#include "libusbi.h" - -/** - * \page io Synchronous and asynchronous device I/O - * - * \section intro Introduction - * - * If you're using libusb in your application, you're probably wanting to - * perform I/O with devices - you want to perform USB data transfers. - * - * libusb offers two separate interfaces for device I/O. This page aims to - * introduce the two in order to help you decide which one is more suitable - * for your application. You can also choose to use both interfaces in your - * application by considering each transfer on a case-by-case basis. - * - * Once you have read through the following discussion, you should consult the - * detailed API documentation pages for the details: - * - \ref syncio - * - \ref asyncio - * - * \section theory Transfers at a logical level - * - * At a logical level, USB transfers typically happen in two parts. For - * example, when reading data from a endpoint: - * -# A request for data is sent to the device - * -# Some time later, the incoming data is received by the host - * - * or when writing data to an endpoint: - * - * -# The data is sent to the device - * -# Some time later, the host receives acknowledgement from the device that - * the data has been transferred. - * - * There may be an indefinite delay between the two steps. Consider a - * fictional USB input device with a button that the user can press. In order - * to determine when the button is pressed, you would likely submit a request - * to read data on a bulk or interrupt endpoint and wait for data to arrive. - * Data will arrive when the button is pressed by the user, which is - * potentially hours later. - * - * libusb offers both a synchronous and an asynchronous interface to performing - * USB transfers. The main difference is that the synchronous interface - * combines both steps indicated above into a single function call, whereas - * the asynchronous interface separates them. - * - * \section sync The synchronous interface - * - * The synchronous I/O interface allows you to perform a USB transfer with - * a single function call. When the function call returns, the transfer has - * completed and you can parse the results. - * - * If you have used the libusb-0.1 before, this I/O style will seem familar to - * you. libusb-0.1 only offered a synchronous interface. - * - * In our input device example, to read button presses you might write code - * in the following style: -\code -unsigned char data[4]; -int actual_length; -int r = libusb_bulk_transfer(handle, LIBUSB_ENDPOINT_IN, data, sizeof(data), &actual_length, 0); -if (r == 0 && actual_length == sizeof(data)) { - // results of the transaction can now be found in the data buffer - // parse them here and report button press -} else { - error(); -} -\endcode - * - * The main advantage of this model is simplicity: you did everything with - * a single simple function call. - * - * However, this interface has its limitations. Your application will sleep - * inside libusb_bulk_transfer() until the transaction has completed. If it - * takes the user 3 hours to press the button, your application will be - * sleeping for that long. Execution will be tied up inside the library - - * the entire thread will be useless for that duration. - * - * Another issue is that by tieing up the thread with that single transaction - * there is no possibility of performing I/O with multiple endpoints and/or - * multiple devices simultaneously, unless you resort to creating one thread - * per transaction. - * - * Additionally, there is no opportunity to cancel the transfer after the - * request has been submitted. - * - * For details on how to use the synchronous API, see the - * \ref syncio "synchronous I/O API documentation" pages. - * - * \section async The asynchronous interface - * - * Asynchronous I/O is the most significant new feature in libusb-1.0. - * Although it is a more complex interface, it solves all the issues detailed - * above. - * - * Instead of providing which functions that block until the I/O has complete, - * libusb's asynchronous interface presents non-blocking functions which - * begin a transfer and then return immediately. Your application passes a - * callback function pointer to this non-blocking function, which libusb will - * call with the results of the transaction when it has completed. - * - * Transfers which have been submitted through the non-blocking functions - * can be cancelled with a separate function call. - * - * The non-blocking nature of this interface allows you to be simultaneously - * performing I/O to multiple endpoints on multiple devices, without having - * to use threads. - * - * This added flexibility does come with some complications though: - * - In the interest of being a lightweight library, libusb does not create - * threads and can only operate when your application is calling into it. Your - * application must call into libusb from it's main loop when events are ready - * to be handled, or you must use some other scheme to allow libusb to - * undertake whatever work needs to be done. - * - libusb also needs to be called into at certain fixed points in time in - * order to accurately handle transfer timeouts. - * - Memory handling becomes more complex. You cannot use stack memory unless - * the function with that stack is guaranteed not to return until the transfer - * callback has finished executing. - * - You generally lose some linearity from your code flow because submitting - * the transfer request is done in a separate function from where the transfer - * results are handled. This becomes particularly obvious when you want to - * submit a second transfer based on the results of an earlier transfer. - * - * Internally, libusb's synchronous interface is expressed in terms of function - * calls to the asynchronous interface. - * - * For details on how to use the asynchronous API, see the - * \ref asyncio "asynchronous I/O API" documentation pages. - */ - - -/** - * \page packetoverflow Packets and overflows - * - * \section packets Packet abstraction - * - * The USB specifications describe how data is transmitted in packets, with - * constraints on packet size defined by endpoint descriptors. The host must - * not send data payloads larger than the endpoint's maximum packet size. - * - * libusb and the underlying OS abstract out the packet concept, allowing you - * to request transfers of any size. Internally, the request will be divided - * up into correctly-sized packets. You do not have to be concerned with - * packet sizes, but there is one exception when considering overflows. - * - * \section overflow Bulk/interrupt transfer overflows - * - * When requesting data on a bulk endpoint, libusb requires you to supply a - * buffer and the maximum number of bytes of data that libusb can put in that - * buffer. However, the size of the buffer is not communicated to the device - - * the device is just asked to send any amount of data. - * - * There is no problem if the device sends an amount of data that is less than - * or equal to the buffer size. libusb reports this condition to you through - * the \ref libusb_transfer::actual_length "libusb_transfer.actual_length" - * field. - * - * Problems may occur if the device attempts to send more data than can fit in - * the buffer. libusb reports LIBUSB_TRANSFER_OVERFLOW for this condition but - * other behaviour is largely undefined: actual_length may or may not be - * accurate, the chunk of data that can fit in the buffer (before overflow) - * may or may not have been transferred. - * - * Overflows are nasty, but can be avoided. Even though you were told to - * ignore packets above, think about the lower level details: each transfer is - * split into packets (typically small, with a maximum size of 512 bytes). - * Overflows can only happen if the final packet in an incoming data transfer - * is smaller than the actual packet that the device wants to transfer. - * Therefore, you will never see an overflow if your transfer buffer size is a - * multiple of the endpoint's packet size: the final packet will either - * fill up completely or will be only partially filled. - */ - -/** - * @defgroup asyncio Asynchronous device I/O - * - * This page details libusb's asynchronous (non-blocking) API for USB device - * I/O. This interface is very powerful but is also quite complex - you will - * need to read this page carefully to understand the necessary considerations - * and issues surrounding use of this interface. Simplistic applications - * may wish to consider the \ref syncio "synchronous I/O API" instead. - * - * The asynchronous interface is built around the idea of separating transfer - * submission and handling of transfer completion (the synchronous model - * combines both of these into one). There may be a long delay between - * submission and completion, however the asynchronous submission function - * is non-blocking so will return control to your application during that - * potentially long delay. - * - * \section asyncabstraction Transfer abstraction - * - * For the asynchronous I/O, libusb implements the concept of a generic - * transfer entity for all types of I/O (control, bulk, interrupt, - * isochronous). The generic transfer object must be treated slightly - * differently depending on which type of I/O you are performing with it. - * - * This is represented by the public libusb_transfer structure type. - * - * \section asynctrf Asynchronous transfers - * - * We can view asynchronous I/O as a 5 step process: - * -# <b>Allocation</b>: allocate a libusb_transfer - * -# <b>Filling</b>: populate the libusb_transfer instance with information - * about the transfer you wish to perform - * -# <b>Submission</b>: ask libusb to submit the transfer - * -# <b>Completion handling</b>: examine transfer results in the - * libusb_transfer structure - * -# <b>Deallocation</b>: clean up resources - * - * - * \subsection asyncalloc Allocation - * - * This step involves allocating memory for a USB transfer. This is the - * generic transfer object mentioned above. At this stage, the transfer - * is "blank" with no details about what type of I/O it will be used for. - * - * Allocation is done with the libusb_alloc_transfer() function. You must use - * this function rather than allocating your own transfers. - * - * \subsection asyncfill Filling - * - * This step is where you take a previously allocated transfer and fill it - * with information to determine the message type and direction, data buffer, - * callback function, etc. - * - * You can either fill the required fields yourself or you can use the - * helper functions: libusb_fill_control_transfer(), libusb_fill_bulk_transfer() - * and libusb_fill_interrupt_transfer(). - * - * \subsection asyncsubmit Submission - * - * When you have allocated a transfer and filled it, you can submit it using - * libusb_submit_transfer(). This function returns immediately but can be - * regarded as firing off the I/O request in the background. - * - * \subsection asynccomplete Completion handling - * - * After a transfer has been submitted, one of four things can happen to it: - * - * - The transfer completes (i.e. some data was transferred) - * - The transfer has a timeout and the timeout expires before all data is - * transferred - * - The transfer fails due to an error - * - The transfer is cancelled - * - * Each of these will cause the user-specified transfer callback function to - * be invoked. It is up to the callback function to determine which of the - * above actually happened and to act accordingly. - * - * The user-specified callback is passed a pointer to the libusb_transfer - * structure which was used to setup and submit the transfer. At completion - * time, libusb has populated this structure with results of the transfer: - * success or failure reason, number of bytes of data transferred, etc. See - * the libusb_transfer structure documentation for more information. - * - * \subsection Deallocation - * - * When a transfer has completed (i.e. the callback function has been invoked), - * you are advised to free the transfer (unless you wish to resubmit it, see - * below). Transfers are deallocated with libusb_free_transfer(). - * - * It is undefined behaviour to free a transfer which has not completed. - * - * \section asyncresubmit Resubmission - * - * You may be wondering why allocation, filling, and submission are all - * separated above where they could reasonably be combined into a single - * operation. - * - * The reason for separation is to allow you to resubmit transfers without - * having to allocate new ones every time. This is especially useful for - * common situations dealing with interrupt endpoints - you allocate one - * transfer, fill and submit it, and when it returns with results you just - * resubmit it for the next interrupt. - * - * \section asynccancel Cancellation - * - * Another advantage of using the asynchronous interface is that you have - * the ability to cancel transfers which have not yet completed. This is - * done by calling the libusb_cancel_transfer() function. - * - * libusb_cancel_transfer() is asynchronous/non-blocking in itself. When the - * cancellation actually completes, the transfer's callback function will - * be invoked, and the callback function should check the transfer status to - * determine that it was cancelled. - * - * Freeing the transfer after it has been cancelled but before cancellation - * has completed will result in undefined behaviour. - * - * When a transfer is cancelled, some of the data may have been transferred. - * libusb will communicate this to you in the transfer callback. Do not assume - * that no data was transferred. - * - * \section bulk_overflows Overflows on device-to-host bulk/interrupt endpoints - * - * If your device does not have predictable transfer sizes (or it misbehaves), - * your application may submit a request for data on an IN endpoint which is - * smaller than the data that the device wishes to send. In some circumstances - * this will cause an overflow, which is a nasty condition to deal with. See - * the \ref packetoverflow page for discussion. - * - * \section asyncctrl Considerations for control transfers - * - * The <tt>libusb_transfer</tt> structure is generic and hence does not - * include specific fields for the control-specific setup packet structure. - * - * In order to perform a control transfer, you must place the 8-byte setup - * packet at the start of the data buffer. To simplify this, you could - * cast the buffer pointer to type struct libusb_control_setup, or you can - * use the helper function libusb_fill_control_setup(). - * - * The wLength field placed in the setup packet must be the length you would - * expect to be sent in the setup packet: the length of the payload that - * follows (or the expected maximum number of bytes to receive). However, - * the length field of the libusb_transfer object must be the length of - * the data buffer - i.e. it should be wLength <em>plus</em> the size of - * the setup packet (LIBUSB_CONTROL_SETUP_SIZE). - * - * If you use the helper functions, this is simplified for you: - * -# Allocate a buffer of size LIBUSB_CONTROL_SETUP_SIZE plus the size of the - * data you are sending/requesting. - * -# Call libusb_fill_control_setup() on the data buffer, using the transfer - * request size as the wLength value (i.e. do not include the extra space you - * allocated for the control setup). - * -# If this is a host-to-device transfer, place the data to be transferred - * in the data buffer, starting at offset LIBUSB_CONTROL_SETUP_SIZE. - * -# Call libusb_fill_control_transfer() to associate the data buffer with - * the transfer (and to set the remaining details such as callback and timeout). - * - Note that there is no parameter to set the length field of the transfer. - * The length is automatically inferred from the wLength field of the setup - * packet. - * -# Submit the transfer. - * - * The multi-byte control setup fields (wValue, wIndex and wLength) must - * be given in little-endian byte order (the endianness of the USB bus). - * Endianness conversion is transparently handled by - * libusb_fill_control_setup() which is documented to accept host-endian - * values. - * - * Further considerations are needed when handling transfer completion in - * your callback function: - * - As you might expect, the setup packet will still be sitting at the start - * of the data buffer. - * - If this was a device-to-host transfer, the received data will be sitting - * at offset LIBUSB_CONTROL_SETUP_SIZE into the buffer. - * - The actual_length field of the transfer structure is relative to the - * wLength of the setup packet, rather than the size of the data buffer. So, - * if your wLength was 4, your transfer's <tt>length</tt> was 12, then you - * should expect an <tt>actual_length</tt> of 4 to indicate that the data was - * transferred in entirity. - * - * To simplify parsing of setup packets and obtaining the data from the - * correct offset, you may wish to use the libusb_control_transfer_get_data() - * and libusb_control_transfer_get_setup() functions within your transfer - * callback. - * - * Even though control endpoints do not halt, a completed control transfer - * may have a LIBUSB_TRANSFER_STALL status code. This indicates the control - * request was not supported. - * - * \section asyncintr Considerations for interrupt transfers - * - * All interrupt transfers are performed using the polling interval presented - * by the bInterval value of the endpoint descriptor. - * - * \section asynciso Considerations for isochronous transfers - * - * Isochronous transfers are more complicated than transfers to - * non-isochronous endpoints. - * - * To perform I/O to an isochronous endpoint, allocate the transfer by calling - * libusb_alloc_transfer() with an appropriate number of isochronous packets. - * - * During filling, set \ref libusb_transfer::type "type" to - * \ref libusb_transfer_type::LIBUSB_TRANSFER_TYPE_ISOCHRONOUS - * "LIBUSB_TRANSFER_TYPE_ISOCHRONOUS", and set - * \ref libusb_transfer::num_iso_packets "num_iso_packets" to a value less than - * or equal to the number of packets you requested during allocation. - * libusb_alloc_transfer() does not set either of these fields for you, given - * that you might not even use the transfer on an isochronous endpoint. - * - * Next, populate the length field for the first num_iso_packets entries in - * the \ref libusb_transfer::iso_packet_desc "iso_packet_desc" array. Section - * 5.6.3 of the USB2 specifications describe how the maximum isochronous - * packet length is determined by the wMaxPacketSize field in the endpoint - * descriptor. - * Two functions can help you here: - * - * - libusb_get_max_iso_packet_size() is an easy way to determine the max - * packet size for an isochronous endpoint. Note that the maximum packet - * size is actually the maximum number of bytes that can be transmitted in - * a single microframe, therefore this function multiplies the maximum number - * of bytes per transaction by the number of transaction opportunities per - * microframe. - * - libusb_set_iso_packet_lengths() assigns the same length to all packets - * within a transfer, which is usually what you want. - * - * For outgoing transfers, you'll obviously fill the buffer and populate the - * packet descriptors in hope that all the data gets transferred. For incoming - * transfers, you must ensure the buffer has sufficient capacity for - * the situation where all packets transfer the full amount of requested data. - * - * Completion handling requires some extra consideration. The - * \ref libusb_transfer::actual_length "actual_length" field of the transfer - * is meaningless and should not be examined; instead you must refer to the - * \ref libusb_iso_packet_descriptor::actual_length "actual_length" field of - * each individual packet. - * - * The \ref libusb_transfer::status "status" field of the transfer is also a - * little misleading: - * - If the packets were submitted and the isochronous data microframes - * completed normally, status will have value - * \ref libusb_transfer_status::LIBUSB_TRANSFER_COMPLETED - * "LIBUSB_TRANSFER_COMPLETED". Note that bus errors and software-incurred - * delays are not counted as transfer errors; the transfer.status field may - * indicate COMPLETED even if some or all of the packets failed. Refer to - * the \ref libusb_iso_packet_descriptor::status "status" field of each - * individual packet to determine packet failures. - * - The status field will have value - * \ref libusb_transfer_status::LIBUSB_TRANSFER_ERROR - * "LIBUSB_TRANSFER_ERROR" only when serious errors were encountered. - * - Other transfer status codes occur with normal behaviour. - * - * The data for each packet will be found at an offset into the buffer that - * can be calculated as if each prior packet completed in full. The - * libusb_get_iso_packet_buffer() and libusb_get_iso_packet_buffer_simple() - * functions may help you here. - * - * \section asyncmem Memory caveats - * - * In most circumstances, it is not safe to use stack memory for transfer - * buffers. This is because the function that fired off the asynchronous - * transfer may return before libusb has finished using the buffer, and when - * the function returns it's stack gets destroyed. This is true for both - * host-to-device and device-to-host transfers. - * - * The only case in which it is safe to use stack memory is where you can - * guarantee that the function owning the stack space for the buffer does not - * return until after the transfer's callback function has completed. In every - * other case, you need to use heap memory instead. - * - * \section asyncflags Fine control - * - * Through using this asynchronous interface, you may find yourself repeating - * a few simple operations many times. You can apply a bitwise OR of certain - * flags to a transfer to simplify certain things: - * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_SHORT_NOT_OK - * "LIBUSB_TRANSFER_SHORT_NOT_OK" results in transfers which transferred - * less than the requested amount of data being marked with status - * \ref libusb_transfer_status::LIBUSB_TRANSFER_ERROR "LIBUSB_TRANSFER_ERROR" - * (they would normally be regarded as COMPLETED) - * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER - * "LIBUSB_TRANSFER_FREE_BUFFER" allows you to ask libusb to free the transfer - * buffer when freeing the transfer. - * - \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_TRANSFER - * "LIBUSB_TRANSFER_FREE_TRANSFER" causes libusb to automatically free the - * transfer after the transfer callback returns. - * - * \section asyncevent Event handling - * - * In accordance of the aim of being a lightweight library, libusb does not - * create threads internally. This means that libusb code does not execute - * at any time other than when your application is calling a libusb function. - * However, an asynchronous model requires that libusb perform work at various - * points in time - namely processing the results of previously-submitted - * transfers and invoking the user-supplied callback function. - * - * This gives rise to the libusb_handle_events() function which your - * application must call into when libusb has work do to. This gives libusb - * the opportunity to reap pending transfers, invoke callbacks, etc. - * - * The first issue to discuss here is how your application can figure out - * when libusb has work to do. In fact, there are two naive options which - * do not actually require your application to know this: - * -# Periodically call libusb_handle_events() in non-blocking mode at fixed - * short intervals from your main loop - * -# Repeatedly call libusb_handle_events() in blocking mode from a dedicated - * thread. - * - * The first option is plainly not very nice, and will cause unnecessary - * CPU wakeups leading to increased power usage and decreased battery life. - * The second option is not very nice either, but may be the nicest option - * available to you if the "proper" approach can not be applied to your - * application (read on...). - * - * The recommended option is to integrate libusb with your application main - * event loop. libusb exposes a set of file descriptors which allow you to do - * this. Your main loop is probably already calling poll() or select() or a - * variant on a set of file descriptors for other event sources (e.g. keyboard - * button presses, mouse movements, network sockets, etc). You then add - * libusb's file descriptors to your poll()/select() calls, and when activity - * is detected on such descriptors you know it is time to call - * libusb_handle_events(). - * - * There is one final event handling complication. libusb supports - * asynchronous transfers which time out after a specified time period, and - * this requires that libusb is called into at or after the timeout so that - * the timeout can be handled. So, in addition to considering libusb's file - * descriptors in your main event loop, you must also consider that libusb - * sometimes needs to be called into at fixed points in time even when there - * is no file descriptor activity. - * - * For the details on retrieving the set of file descriptors and determining - * the next timeout, see the \ref poll "polling and timing" API documentation. - */ - -/** - * @defgroup poll Polling and timing - * - * This page documents libusb's functions for polling events and timing. - * These functions are only necessary for users of the - * \ref asyncio "asynchronous API". If you are only using the simpler - * \ref syncio "synchronous API" then you do not need to ever call these - * functions. - * - * The justification for the functionality described here has already been - * discussed in the \ref asyncevent "event handling" section of the - * asynchronous API documentation. In summary, libusb does not create internal - * threads for event processing and hence relies on your application calling - * into libusb at certain points in time so that pending events can be handled. - * In order to know precisely when libusb needs to be called into, libusb - * offers you a set of pollable file descriptors and information about when - * the next timeout expires. - * - * If you are using the asynchronous I/O API, you must take one of the two - * following options, otherwise your I/O will not complete. - * - * \section pollsimple The simple option - * - * If your application revolves solely around libusb and does not need to - * handle other event sources, you can have a program structure as follows: -\code -// initialize libusb -// find and open device -// maybe fire off some initial async I/O - -while (user_has_not_requested_exit) - libusb_handle_events(ctx); - -// clean up and exit -\endcode - * - * With such a simple main loop, you do not have to worry about managing - * sets of file descriptors or handling timeouts. libusb_handle_events() will - * handle those details internally. - * - * \section pollmain The more advanced option - * - * \note This functionality is currently only available on Unix-like platforms. - * On Windows, libusb_get_pollfds() simply returns NULL. Exposing event sources - * on Windows will require some further thought and design. - * - * In more advanced applications, you will already have a main loop which - * is monitoring other event sources: network sockets, X11 events, mouse - * movements, etc. Through exposing a set of file descriptors, libusb is - * designed to cleanly integrate into such main loops. - * - * In addition to polling file descriptors for the other event sources, you - * take a set of file descriptors from libusb and monitor those too. When you - * detect activity on libusb's file descriptors, you call - * libusb_handle_events_timeout() in non-blocking mode. - * - * What's more, libusb may also need to handle events at specific moments in - * time. No file descriptor activity is generated at these times, so your - * own application needs to be continually aware of when the next one of these - * moments occurs (through calling libusb_get_next_timeout()), and then it - * needs to call libusb_handle_events_timeout() in non-blocking mode when - * these moments occur. This means that you need to adjust your - * poll()/select() timeout accordingly. - * - * libusb provides you with a set of file descriptors to poll and expects you - * to poll all of them, treating them as a single entity. The meaning of each - * file descriptor in the set is an internal implementation detail, - * platform-dependent and may vary from release to release. Don't try and - * interpret the meaning of the file descriptors, just do as libusb indicates, - * polling all of them at once. - * - * In pseudo-code, you want something that looks like: -\code -// initialise libusb - -libusb_get_pollfds(ctx) -while (user has not requested application exit) { - libusb_get_next_timeout(ctx); - poll(on libusb file descriptors plus any other event sources of interest, - using a timeout no larger than the value libusb just suggested) - if (poll() indicated activity on libusb file descriptors) - libusb_handle_events_timeout(ctx, &zero_tv); - if (time has elapsed to or beyond the libusb timeout) - libusb_handle_events_timeout(ctx, &zero_tv); - // handle events from other sources here -} - -// clean up and exit -\endcode - * - * \subsection polltime Notes on time-based events - * - * The above complication with having to track time and call into libusb at - * specific moments is a bit of a headache. For maximum compatibility, you do - * need to write your main loop as above, but you may decide that you can - * restrict the supported platforms of your application and get away with - * a more simplistic scheme. - * - * These time-based event complications are \b not required on the following - * platforms: - * - Darwin - * - Linux, provided that the following version requirements are satisfied: - * - Linux v2.6.27 or newer, compiled with timerfd support - * - glibc v2.9 or newer - * - libusb v1.0.5 or newer - * - * Under these configurations, libusb_get_next_timeout() will \em always return - * 0, so your main loop can be simplified to: -\code -// initialise libusb - -libusb_get_pollfds(ctx) -while (user has not requested application exit) { - poll(on libusb file descriptors plus any other event sources of interest, - using any timeout that you like) - if (poll() indicated activity on libusb file descriptors) - libusb_handle_events_timeout(ctx, &zero_tv); - // handle events from other sources here -} - -// clean up and exit -\endcode - * - * Do remember that if you simplify your main loop to the above, you will - * lose compatibility with some platforms (including legacy Linux platforms, - * and <em>any future platforms supported by libusb which may have time-based - * event requirements</em>). The resultant problems will likely appear as - * strange bugs in your application. - * - * You can use the libusb_pollfds_handle_timeouts() function to do a runtime - * check to see if it is safe to ignore the time-based event complications. - * If your application has taken the shortcut of ignoring libusb's next timeout - * in your main loop, then you are advised to check the return value of - * libusb_pollfds_handle_timeouts() during application startup, and to abort - * if the platform does suffer from these timing complications. - * - * \subsection fdsetchange Changes in the file descriptor set - * - * The set of file descriptors that libusb uses as event sources may change - * during the life of your application. Rather than having to repeatedly - * call libusb_get_pollfds(), you can set up notification functions for when - * the file descriptor set changes using libusb_set_pollfd_notifiers(). - * - * \subsection mtissues Multi-threaded considerations - * - * Unfortunately, the situation is complicated further when multiple threads - * come into play. If two threads are monitoring the same file descriptors, - * the fact that only one thread will be woken up when an event occurs causes - * some headaches. - * - * The events lock, event waiters lock, and libusb_handle_events_locked() - * entities are added to solve these problems. You do not need to be concerned - * with these entities otherwise. - * - * See the extra documentation: \ref mtasync - */ - -/** \page mtasync Multi-threaded applications and asynchronous I/O - * - * libusb is a thread-safe library, but extra considerations must be applied - * to applications which interact with libusb from multiple threads. - * - * The underlying issue that must be addressed is that all libusb I/O - * revolves around monitoring file descriptors through the poll()/select() - * system calls. This is directly exposed at the - * \ref asyncio "asynchronous interface" but it is important to note that the - * \ref syncio "synchronous interface" is implemented on top of the - * asynchonrous interface, therefore the same considerations apply. - * - * The issue is that if two or more threads are concurrently calling poll() - * or select() on libusb's file descriptors then only one of those threads - * will be woken up when an event arrives. The others will be completely - * oblivious that anything has happened. - * - * Consider the following pseudo-code, which submits an asynchronous transfer - * then waits for its completion. This style is one way you could implement a - * synchronous interface on top of the asynchronous interface (and libusb - * does something similar, albeit more advanced due to the complications - * explained on this page). - * -\code -void cb(struct libusb_transfer *transfer) -{ - int *completed = transfer->user_data; - *completed = 1; -} - -void myfunc() { - struct libusb_transfer *transfer; - unsigned char buffer[LIBUSB_CONTROL_SETUP_SIZE]; - int completed = 0; - - transfer = libusb_alloc_transfer(0); - libusb_fill_control_setup(buffer, - LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, 0x04, 0x01, 0, 0); - libusb_fill_control_transfer(transfer, dev, buffer, cb, &completed, 1000); - libusb_submit_transfer(transfer); - - while (!completed) { - poll(libusb file descriptors, 120*1000); - if (poll indicates activity) - libusb_handle_events_timeout(ctx, &zero_tv); - } - printf("completed!"); - // other code here -} -\endcode - * - * Here we are <em>serializing</em> completion of an asynchronous event - * against a condition - the condition being completion of a specific transfer. - * The poll() loop has a long timeout to minimize CPU usage during situations - * when nothing is happening (it could reasonably be unlimited). - * - * If this is the only thread that is polling libusb's file descriptors, there - * is no problem: there is no danger that another thread will swallow up the - * event that we are interested in. On the other hand, if there is another - * thread polling the same descriptors, there is a chance that it will receive - * the event that we were interested in. In this situation, <tt>myfunc()</tt> - * will only realise that the transfer has completed on the next iteration of - * the loop, <em>up to 120 seconds later.</em> Clearly a two-minute delay is - * undesirable, and don't even think about using short timeouts to circumvent - * this issue! - * - * The solution here is to ensure that no two threads are ever polling the - * file descriptors at the same time. A naive implementation of this would - * impact the capabilities of the library, so libusb offers the scheme - * documented below to ensure no loss of functionality. - * - * Before we go any further, it is worth mentioning that all libusb-wrapped - * event handling procedures fully adhere to the scheme documented below. - * This includes libusb_handle_events() and its variants, and all the - * synchronous I/O functions - libusb hides this headache from you. - * - * \section Using libusb_handle_events() from multiple threads - * - * Even when only using libusb_handle_events() and synchronous I/O functions, - * you can still have a race condition. You might be tempted to solve the - * above with libusb_handle_events() like so: - * -\code - libusb_submit_transfer(transfer); - - while (!completed) { - libusb_handle_events(ctx); - } - printf("completed!"); -\endcode - * - * This however has a race between the checking of completed and - * libusb_handle_events() acquiring the events lock, so another thread - * could have completed the transfer, resulting in this thread hanging - * until either a timeout or another event occurs. See also commit - * 6696512aade99bb15d6792af90ae329af270eba6 which fixes this in the - * synchronous API implementation of libusb. - * - * Fixing this race requires checking the variable completed only after - * taking the event lock, which defeats the concept of just calling - * libusb_handle_events() without worrying about locking. This is why - * libusb-1.0.9 introduces the new libusb_handle_events_timeout_completed() - * and libusb_handle_events_completed() functions, which handles doing the - * completion check for you after they have acquired the lock: - * -\code - libusb_submit_transfer(transfer); - - while (!completed) { - libusb_handle_events_completed(ctx, &completed); - } - printf("completed!"); -\endcode - * - * This nicely fixes the race in our example. Note that if all you want to - * do is submit a single transfer and wait for its completion, then using - * one of the synchronous I/O functions is much easier. - * - * \section eventlock The events lock - * - * The problem is when we consider the fact that libusb exposes file - * descriptors to allow for you to integrate asynchronous USB I/O into - * existing main loops, effectively allowing you to do some work behind - * libusb's back. If you do take libusb's file descriptors and pass them to - * poll()/select() yourself, you need to be aware of the associated issues. - * - * The first concept to be introduced is the events lock. The events lock - * is used to serialize threads that want to handle events, such that only - * one thread is handling events at any one time. - * - * You must take the events lock before polling libusb file descriptors, - * using libusb_lock_events(). You must release the lock as soon as you have - * aborted your poll()/select() loop, using libusb_unlock_events(). - * - * \section threadwait Letting other threads do the work for you - * - * Although the events lock is a critical part of the solution, it is not - * enough on it's own. You might wonder if the following is sufficient... -\code - libusb_lock_events(ctx); - while (!completed) { - poll(libusb file descriptors, 120*1000); - if (poll indicates activity) - libusb_handle_events_timeout(ctx, &zero_tv); - } - libusb_unlock_events(ctx); -\endcode - * ...and the answer is that it is not. This is because the transfer in the - * code shown above may take a long time (say 30 seconds) to complete, and - * the lock is not released until the transfer is completed. - * - * Another thread with similar code that wants to do event handling may be - * working with a transfer that completes after a few milliseconds. Despite - * having such a quick completion time, the other thread cannot check that - * status of its transfer until the code above has finished (30 seconds later) - * due to contention on the lock. - * - * To solve this, libusb offers you a mechanism to determine when another - * thread is handling events. It also offers a mechanism to block your thread - * until the event handling thread has completed an event (and this mechanism - * does not involve polling of file descriptors). - * - * After determining that another thread is currently handling events, you - * obtain the <em>event waiters</em> lock using libusb_lock_event_waiters(). - * You then re-check that some other thread is still handling events, and if - * so, you call libusb_wait_for_event(). - * - * libusb_wait_for_event() puts your application to sleep until an event - * occurs, or until a thread releases the events lock. When either of these - * things happen, your thread is woken up, and should re-check the condition - * it was waiting on. It should also re-check that another thread is handling - * events, and if not, it should start handling events itself. - * - * This looks like the following, as pseudo-code: -\code -retry: -if (libusb_try_lock_events(ctx) == 0) { - // we obtained the event lock: do our own event handling - while (!completed) { - if (!libusb_event_handling_ok(ctx)) { - libusb_unlock_events(ctx); - goto retry; - } - poll(libusb file descriptors, 120*1000); - if (poll indicates activity) - libusb_handle_events_locked(ctx, 0); - } - libusb_unlock_events(ctx); -} else { - // another thread is doing event handling. wait for it to signal us that - // an event has completed - libusb_lock_event_waiters(ctx); - - while (!completed) { - // now that we have the event waiters lock, double check that another - // thread is still handling events for us. (it may have ceased handling - // events in the time it took us to reach this point) - if (!libusb_event_handler_active(ctx)) { - // whoever was handling events is no longer doing so, try again - libusb_unlock_event_waiters(ctx); - goto retry; - } - - libusb_wait_for_event(ctx, NULL); - } - libusb_unlock_event_waiters(ctx); -} -printf("completed!\n"); -\endcode - * - * A naive look at the above code may suggest that this can only support - * one event waiter (hence a total of 2 competing threads, the other doing - * event handling), because the event waiter seems to have taken the event - * waiters lock while waiting for an event. However, the system does support - * multiple event waiters, because libusb_wait_for_event() actually drops - * the lock while waiting, and reaquires it before continuing. - * - * We have now implemented code which can dynamically handle situations where - * nobody is handling events (so we should do it ourselves), and it can also - * handle situations where another thread is doing event handling (so we can - * piggyback onto them). It is also equipped to handle a combination of - * the two, for example, another thread is doing event handling, but for - * whatever reason it stops doing so before our condition is met, so we take - * over the event handling. - * - * Four functions were introduced in the above pseudo-code. Their importance - * should be apparent from the code shown above. - * -# libusb_try_lock_events() is a non-blocking function which attempts - * to acquire the events lock but returns a failure code if it is contended. - * -# libusb_event_handling_ok() checks that libusb is still happy for your - * thread to be performing event handling. Sometimes, libusb needs to - * interrupt the event handler, and this is how you can check if you have - * been interrupted. If this function returns 0, the correct behaviour is - * for you to give up the event handling lock, and then to repeat the cycle. - * The following libusb_try_lock_events() will fail, so you will become an - * events waiter. For more information on this, read \ref fullstory below. - * -# libusb_handle_events_locked() is a variant of - * libusb_handle_events_timeout() that you can call while holding the - * events lock. libusb_handle_events_timeout() itself implements similar - * logic to the above, so be sure not to call it when you are - * "working behind libusb's back", as is the case here. - * -# libusb_event_handler_active() determines if someone is currently - * holding the events lock - * - * You might be wondering why there is no function to wake up all threads - * blocked on libusb_wait_for_event(). This is because libusb can do this - * internally: it will wake up all such threads when someone calls - * libusb_unlock_events() or when a transfer completes (at the point after its - * callback has returned). - * - * \subsection fullstory The full story - * - * The above explanation should be enough to get you going, but if you're - * really thinking through the issues then you may be left with some more - * questions regarding libusb's internals. If you're curious, read on, and if - * not, skip to the next section to avoid confusing yourself! - * - * The immediate question that may spring to mind is: what if one thread - * modifies the set of file descriptors that need to be polled while another - * thread is doing event handling? - * - * There are 2 situations in which this may happen. - * -# libusb_open() will add another file descriptor to the poll set, - * therefore it is desirable to interrupt the event handler so that it - * restarts, picking up the new descriptor. - * -# libusb_close() will remove a file descriptor from the poll set. There - * are all kinds of race conditions that could arise here, so it is - * important that nobody is doing event handling at this time. - * - * libusb handles these issues internally, so application developers do not - * have to stop their event handlers while opening/closing devices. Here's how - * it works, focusing on the libusb_close() situation first: - * - * -# During initialization, libusb opens an internal pipe, and it adds the read - * end of this pipe to the set of file descriptors to be polled. - * -# During libusb_close(), libusb writes some dummy data on this control pipe. - * This immediately interrupts the event handler. libusb also records - * internally that it is trying to interrupt event handlers for this - * high-priority event. - * -# At this point, some of the functions described above start behaving - * differently: - * - libusb_event_handling_ok() starts returning 1, indicating that it is NOT - * OK for event handling to continue. - * - libusb_try_lock_events() starts returning 1, indicating that another - * thread holds the event handling lock, even if the lock is uncontended. - * - libusb_event_handler_active() starts returning 1, indicating that - * another thread is doing event handling, even if that is not true. - * -# The above changes in behaviour result in the event handler stopping and - * giving up the events lock very quickly, giving the high-priority - * libusb_close() operation a "free ride" to acquire the events lock. All - * threads that are competing to do event handling become event waiters. - * -# With the events lock held inside libusb_close(), libusb can safely remove - * a file descriptor from the poll set, in the safety of knowledge that - * nobody is polling those descriptors or trying to access the poll set. - * -# After obtaining the events lock, the close operation completes very - * quickly (usually a matter of milliseconds) and then immediately releases - * the events lock. - * -# At the same time, the behaviour of libusb_event_handling_ok() and friends - * reverts to the original, documented behaviour. - * -# The release of the events lock causes the threads that are waiting for - * events to be woken up and to start competing to become event handlers - * again. One of them will succeed; it will then re-obtain the list of poll - * descriptors, and USB I/O will then continue as normal. - * - * libusb_open() is similar, and is actually a more simplistic case. Upon a - * call to libusb_open(): - * - * -# The device is opened and a file descriptor is added to the poll set. - * -# libusb sends some dummy data on the control pipe, and records that it - * is trying to modify the poll descriptor set. - * -# The event handler is interrupted, and the same behaviour change as for - * libusb_close() takes effect, causing all event handling threads to become - * event waiters. - * -# The libusb_open() implementation takes its free ride to the events lock. - * -# Happy that it has successfully paused the events handler, libusb_open() - * releases the events lock. - * -# The event waiter threads are all woken up and compete to become event - * handlers again. The one that succeeds will obtain the list of poll - * descriptors again, which will include the addition of the new device. - * - * \subsection concl Closing remarks - * - * The above may seem a little complicated, but hopefully I have made it clear - * why such complications are necessary. Also, do not forget that this only - * applies to applications that take libusb's file descriptors and integrate - * them into their own polling loops. - * - * You may decide that it is OK for your multi-threaded application to ignore - * some of the rules and locks detailed above, because you don't think that - * two threads can ever be polling the descriptors at the same time. If that - * is the case, then that's good news for you because you don't have to worry. - * But be careful here; remember that the synchronous I/O functions do event - * handling internally. If you have one thread doing event handling in a loop - * (without implementing the rules and locking semantics documented above) - * and another trying to send a synchronous USB transfer, you will end up with - * two threads monitoring the same descriptors, and the above-described - * undesirable behaviour occuring. The solution is for your polling thread to - * play by the rules; the synchronous I/O functions do so, and this will result - * in them getting along in perfect harmony. - * - * If you do have a dedicated thread doing event handling, it is perfectly - * legal for it to take the event handling lock for long periods of time. Any - * synchronous I/O functions you call from other threads will transparently - * fall back to the "event waiters" mechanism detailed above. The only - * consideration that your event handling thread must apply is the one related - * to libusb_event_handling_ok(): you must call this before every poll(), and - * give up the events lock if instructed. - */ - -int usbi_io_init(struct libusb_context *ctx) -{ - int r; - - usbi_mutex_init(&ctx->flying_transfers_lock, NULL); - usbi_mutex_init(&ctx->pollfds_lock, NULL); - usbi_mutex_init(&ctx->pollfd_modify_lock, NULL); - usbi_mutex_init_recursive(&ctx->events_lock, NULL); - usbi_mutex_init(&ctx->event_waiters_lock, NULL); - usbi_cond_init(&ctx->event_waiters_cond, NULL); - list_init(&ctx->flying_transfers); - list_init(&ctx->pollfds); - - /* FIXME should use an eventfd on kernels that support it */ - r = usbi_pipe(ctx->ctrl_pipe); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; - goto err; - } - - r = usbi_add_pollfd(ctx, ctx->ctrl_pipe[0], POLLIN); - if (r < 0) - goto err_close_pipe; - -#ifdef USBI_TIMERFD_AVAILABLE - ctx->timerfd = timerfd_create(usbi_backend->get_timerfd_clockid(), - TFD_NONBLOCK); - if (ctx->timerfd >= 0) { - usbi_dbg("using timerfd for timeouts"); - r = usbi_add_pollfd(ctx, ctx->timerfd, POLLIN); - if (r < 0) { - usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]); - close(ctx->timerfd); - goto err_close_pipe; - } - } else { - usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno); - ctx->timerfd = -1; - } -#endif - - return 0; - -err_close_pipe: - usbi_close(ctx->ctrl_pipe[0]); - usbi_close(ctx->ctrl_pipe[1]); -err: - usbi_mutex_destroy(&ctx->flying_transfers_lock); - usbi_mutex_destroy(&ctx->pollfds_lock); - usbi_mutex_destroy(&ctx->pollfd_modify_lock); - usbi_mutex_destroy(&ctx->events_lock); - usbi_mutex_destroy(&ctx->event_waiters_lock); - usbi_cond_destroy(&ctx->event_waiters_cond); - return r; -} - -void usbi_io_exit(struct libusb_context *ctx) -{ - usbi_remove_pollfd(ctx, ctx->ctrl_pipe[0]); - usbi_close(ctx->ctrl_pipe[0]); - usbi_close(ctx->ctrl_pipe[1]); -#ifdef USBI_TIMERFD_AVAILABLE - if (usbi_using_timerfd(ctx)) { - usbi_remove_pollfd(ctx, ctx->timerfd); - close(ctx->timerfd); - } -#endif - usbi_mutex_destroy(&ctx->flying_transfers_lock); - usbi_mutex_destroy(&ctx->pollfds_lock); - usbi_mutex_destroy(&ctx->pollfd_modify_lock); - usbi_mutex_destroy(&ctx->events_lock); - usbi_mutex_destroy(&ctx->event_waiters_lock); - usbi_cond_destroy(&ctx->event_waiters_cond); -} - -static int calculate_timeout(struct usbi_transfer *transfer) -{ - int r; - struct timespec current_time; - unsigned int timeout = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout; - - if (!timeout) - return 0; - - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, ¤t_time); - if (r < 0) { - usbi_err(ITRANSFER_CTX(transfer), - "failed to read monotonic clock, errno=%d", errno); - return r; - } - - current_time.tv_sec += timeout / 1000; - current_time.tv_nsec += (timeout % 1000) * 1000000; - - if (current_time.tv_nsec > 1000000000) { - current_time.tv_nsec -= 1000000000; - current_time.tv_sec++; - } - - TIMESPEC_TO_TIMEVAL(&transfer->timeout, ¤t_time); - return 0; -} - -/* add a transfer to the (timeout-sorted) active transfers list. - * returns 1 if the transfer has a timeout and it is the timeout next to - * expire */ -static int add_to_flying_list(struct usbi_transfer *transfer) -{ - struct usbi_transfer *cur; - struct timeval *timeout = &transfer->timeout; - struct libusb_context *ctx = ITRANSFER_CTX(transfer); - int r = 0; - int first = 1; - - usbi_mutex_lock(&ctx->flying_transfers_lock); - - /* if we have no other flying transfers, start the list with this one */ - if (list_empty(&ctx->flying_transfers)) { - list_add(&transfer->list, &ctx->flying_transfers); - if (timerisset(timeout)) - r = 1; - goto out; - } - - /* if we have infinite timeout, append to end of list */ - if (!timerisset(timeout)) { - list_add_tail(&transfer->list, &ctx->flying_transfers); - goto out; - } - - /* otherwise, find appropriate place in list */ - list_for_each_entry(cur, &ctx->flying_transfers, list, struct usbi_transfer) { - /* find first timeout that occurs after the transfer in question */ - struct timeval *cur_tv = &cur->timeout; - - if (!timerisset(cur_tv) || (cur_tv->tv_sec > timeout->tv_sec) || - (cur_tv->tv_sec == timeout->tv_sec && - cur_tv->tv_usec > timeout->tv_usec)) { - list_add_tail(&transfer->list, &cur->list); - r = first; - goto out; - } - first = 0; - } - - /* otherwise we need to be inserted at the end */ - list_add_tail(&transfer->list, &ctx->flying_transfers); -out: - usbi_mutex_unlock(&ctx->flying_transfers_lock); - return r; -} - -/** \ingroup asyncio - * Allocate a libusb transfer with a specified number of isochronous packet - * descriptors. The returned transfer is pre-initialized for you. When the new - * transfer is no longer needed, it should be freed with - * libusb_free_transfer(). - * - * Transfers intended for non-isochronous endpoints (e.g. control, bulk, - * interrupt) should specify an iso_packets count of zero. - * - * For transfers intended for isochronous endpoints, specify an appropriate - * number of packet descriptors to be allocated as part of the transfer. - * The returned transfer is not specially initialized for isochronous I/O; - * you are still required to set the - * \ref libusb_transfer::num_iso_packets "num_iso_packets" and - * \ref libusb_transfer::type "type" fields accordingly. - * - * It is safe to allocate a transfer with some isochronous packets and then - * use it on a non-isochronous endpoint. If you do this, ensure that at time - * of submission, num_iso_packets is 0 and that type is set appropriately. - * - * \param iso_packets number of isochronous packet descriptors to allocate - * \returns a newly allocated transfer, or NULL on error - */ -DEFAULT_VISIBILITY -struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer( - int iso_packets) -{ - size_t os_alloc_size = usbi_backend->transfer_priv_size - + (usbi_backend->add_iso_packet_size * iso_packets); - size_t alloc_size = sizeof(struct usbi_transfer) - + sizeof(struct libusb_transfer) - + (sizeof(struct libusb_iso_packet_descriptor) * iso_packets) - + os_alloc_size; - struct usbi_transfer *itransfer = malloc(alloc_size); - if (!itransfer) - return NULL; - - memset(itransfer, 0, alloc_size); - itransfer->num_iso_packets = iso_packets; - usbi_mutex_init(&itransfer->lock, NULL); - return USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); -} - -/** \ingroup asyncio - * Free a transfer structure. This should be called for all transfers - * allocated with libusb_alloc_transfer(). - * - * If the \ref libusb_transfer_flags::LIBUSB_TRANSFER_FREE_BUFFER - * "LIBUSB_TRANSFER_FREE_BUFFER" flag is set and the transfer buffer is - * non-NULL, this function will also free the transfer buffer using the - * standard system memory allocator (e.g. free()). - * - * It is legal to call this function with a NULL transfer. In this case, - * the function will simply return safely. - * - * It is not legal to free an active transfer (one which has been submitted - * and has not yet completed). - * - * \param transfer the transfer to free - */ -void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer) -{ - struct usbi_transfer *itransfer; - if (!transfer) - return; - - if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER && transfer->buffer) - free(transfer->buffer); - - itransfer = LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - usbi_mutex_destroy(&itransfer->lock); - free(itransfer); -} - -/** \ingroup asyncio - * Submit a transfer. This function will fire off the USB transfer and then - * return immediately. - * - * \param transfer the transfer to submit - * \returns 0 on success - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns LIBUSB_ERROR_BUSY if the transfer has already been submitted. - * \returns another LIBUSB_ERROR code on other failure - */ -int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer) -{ - struct libusb_context *ctx = TRANSFER_CTX(transfer); - struct usbi_transfer *itransfer = - LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - int r; - int first; - - usbi_mutex_lock(&itransfer->lock); - itransfer->transferred = 0; - itransfer->flags = 0; - r = calculate_timeout(itransfer); - if (r < 0) { - r = LIBUSB_ERROR_OTHER; - goto out; - } - - first = add_to_flying_list(itransfer); - r = usbi_backend->submit_transfer(itransfer); - if (r) { - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_del(&itransfer->list); - usbi_mutex_unlock(&ctx->flying_transfers_lock); - } -#ifdef USBI_TIMERFD_AVAILABLE - else if (first && usbi_using_timerfd(ctx)) { - /* if this transfer has the lowest timeout of all active transfers, - * rearm the timerfd with this transfer's timeout */ - const struct itimerspec it = { {0, 0}, - { itransfer->timeout.tv_sec, itransfer->timeout.tv_usec * 1000 } }; - usbi_dbg("arm timerfd for timeout in %dms (first in line)", transfer->timeout); - r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL); - if (r < 0) - r = LIBUSB_ERROR_OTHER; - } -#else - (void)first; -#endif - -out: - usbi_mutex_unlock(&itransfer->lock); - return r; -} - -/** \ingroup asyncio - * Asynchronously cancel a previously submitted transfer. - * This function returns immediately, but this does not indicate cancellation - * is complete. Your callback function will be invoked at some later time - * with a transfer status of - * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED - * "LIBUSB_TRANSFER_CANCELLED." - * - * \param transfer the transfer to cancel - * \returns 0 on success - * \returns LIBUSB_ERROR_NOT_FOUND if the transfer is already complete or - * cancelled. - * \returns a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer) -{ - struct usbi_transfer *itransfer = - LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); - int r; - - usbi_dbg(""); - usbi_mutex_lock(&itransfer->lock); - r = usbi_backend->cancel_transfer(itransfer); - if (r < 0) { - usbi_err(TRANSFER_CTX(transfer), - "cancel transfer failed error %d", r); - - if (r == LIBUSB_ERROR_NO_DEVICE) - itransfer->flags |= USBI_TRANSFER_DEVICE_DISAPPEARED; - } - - itransfer->flags |= USBI_TRANSFER_CANCELLING; - - usbi_mutex_unlock(&itransfer->lock); - return r; -} - -#ifdef USBI_TIMERFD_AVAILABLE -static int disarm_timerfd(struct libusb_context *ctx) -{ - const struct itimerspec disarm_timer = { { 0, 0 }, { 0, 0 } }; - int r; - - usbi_dbg(""); - r = timerfd_settime(ctx->timerfd, 0, &disarm_timer, NULL); - if (r < 0) - return LIBUSB_ERROR_OTHER; - else - return 0; -} - -/* iterates through the flying transfers, and rearms the timerfd based on the - * next upcoming timeout. - * must be called with flying_list locked. - * returns 0 if there was no timeout to arm, 1 if the next timeout was armed, - * or a LIBUSB_ERROR code on failure. - */ -static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) -{ - struct usbi_transfer *transfer; - - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - struct timeval *cur_tv = &transfer->timeout; - - /* if we've reached transfers of infinite timeout, then we have no - * arming to do */ - if (!timerisset(cur_tv)) - return 0; - - /* act on first transfer that is not already cancelled */ - if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) { - int r; - const struct itimerspec it = { {0, 0}, - { cur_tv->tv_sec, cur_tv->tv_usec * 1000 } }; - usbi_dbg("next timeout originally %dms", USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout); - r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL); - if (r < 0) - return LIBUSB_ERROR_OTHER; - return 1; - } - } - - return 0; -} -#else -static int disarm_timerfd(struct libusb_context *ctx) -{ - (void)ctx; - return 0; -} -static int arm_timerfd_for_next_timeout(struct libusb_context *ctx) -{ - (void)ctx; - return 0; -} -#endif - -/* Handle completion of a transfer (completion might be an error condition). - * This will invoke the user-supplied callback function, which may end up - * freeing the transfer. Therefore you cannot use the transfer structure - * after calling this function, and you should free all backend-specific - * data before calling it. - * Do not call this function with the usbi_transfer lock held. User-specified - * callback functions may attempt to directly resubmit the transfer, which - * will attempt to take the lock. */ -int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, - enum libusb_transfer_status status) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = TRANSFER_CTX(transfer); - uint8_t flags; - int r; - - /* FIXME: could be more intelligent with the timerfd here. we don't need - * to disarm the timerfd if there was no timer running, and we only need - * to rearm the timerfd if the transfer that expired was the one with - * the shortest timeout. */ - - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_del(&itransfer->list); - r = arm_timerfd_for_next_timeout(ctx); - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (r < 0) { - return r; - } else if (r == 0) { - r = disarm_timerfd(ctx); - if (r < 0) - return r; - } - - if (status == LIBUSB_TRANSFER_COMPLETED - && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { - int rqlen = transfer->length; - if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) - rqlen -= LIBUSB_CONTROL_SETUP_SIZE; - if (rqlen != itransfer->transferred) { - usbi_dbg("interpreting short transfer as error"); - status = LIBUSB_TRANSFER_ERROR; - } - } - - flags = transfer->flags; - transfer->status = status; - transfer->actual_length = itransfer->transferred; - if (transfer->callback) - transfer->callback(transfer); - /* transfer might have been freed by the above call, do not use from - * this point. */ - if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) - libusb_free_transfer(transfer); - usbi_mutex_lock(&ctx->event_waiters_lock); - usbi_cond_broadcast(&ctx->event_waiters_cond); - usbi_mutex_unlock(&ctx->event_waiters_lock); - return 0; -} - -/* Similar to usbi_handle_transfer_completion() but exclusively for transfers - * that were asynchronously cancelled. The same concerns w.r.t. freeing of - * transfers exist here. - * Do not call this function with the usbi_transfer lock held. User-specified - * callback functions may attempt to directly resubmit the transfer, which - * will attempt to take the lock. */ -int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer) -{ - /* if the URB was cancelled due to timeout, report timeout to the user */ - if (transfer->flags & USBI_TRANSFER_TIMED_OUT) { - usbi_dbg("detected timeout cancellation"); - return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT); - } - - /* otherwise its a normal async cancel */ - return usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED); -} - -/** \ingroup poll - * Attempt to acquire the event handling lock. This lock is used to ensure that - * only one thread is monitoring libusb event sources at any one time. - * - * You only need to use this lock if you are developing an application - * which calls poll() or select() on libusb's file descriptors directly. - * If you stick to libusb's event handling loop functions (e.g. - * libusb_handle_events()) then you do not need to be concerned with this - * locking. - * - * While holding this lock, you are trusted to actually be handling events. - * If you are no longer handling events, you must call libusb_unlock_events() - * as soon as possible. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 if the lock was obtained successfully - * \returns 1 if the lock was not obtained (i.e. another thread holds the lock) - * \see \ref mtasync - */ -int API_EXPORTED libusb_try_lock_events(libusb_context *ctx) -{ - int r; - USBI_GET_CONTEXT(ctx); - - /* is someone else waiting to modify poll fds? if so, don't let this thread - * start event handling */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - r = ctx->pollfd_modify; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - if (r) { - usbi_dbg("someone else is modifying poll fds"); - return 1; - } - - r = usbi_mutex_trylock(&ctx->events_lock); - if (r) - return 1; - - ctx->event_handler_active = 1; - return 0; -} - -/** \ingroup poll - * Acquire the event handling lock, blocking until successful acquisition if - * it is contended. This lock is used to ensure that only one thread is - * monitoring libusb event sources at any one time. - * - * You only need to use this lock if you are developing an application - * which calls poll() or select() on libusb's file descriptors directly. - * If you stick to libusb's event handling loop functions (e.g. - * libusb_handle_events()) then you do not need to be concerned with this - * locking. - * - * While holding this lock, you are trusted to actually be handling events. - * If you are no longer handling events, you must call libusb_unlock_events() - * as soon as possible. - * - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_lock_events(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - usbi_mutex_lock(&ctx->events_lock); - ctx->event_handler_active = 1; -} - -/** \ingroup poll - * Release the lock previously acquired with libusb_try_lock_events() or - * libusb_lock_events(). Releasing this lock will wake up any threads blocked - * on libusb_wait_for_event(). - * - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_unlock_events(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - ctx->event_handler_active = 0; - usbi_mutex_unlock(&ctx->events_lock); - - /* FIXME: perhaps we should be a bit more efficient by not broadcasting - * the availability of the events lock when we are modifying pollfds - * (check ctx->pollfd_modify)? */ - usbi_mutex_lock(&ctx->event_waiters_lock); - usbi_cond_broadcast(&ctx->event_waiters_cond); - usbi_mutex_unlock(&ctx->event_waiters_lock); -} - -/** \ingroup poll - * Determine if it is still OK for this thread to be doing event handling. - * - * Sometimes, libusb needs to temporarily pause all event handlers, and this - * is the function you should use before polling file descriptors to see if - * this is the case. - * - * If this function instructs your thread to give up the events lock, you - * should just continue the usual logic that is documented in \ref mtasync. - * On the next iteration, your thread will fail to obtain the events lock, - * and will hence become an event waiter. - * - * This function should be called while the events lock is held: you don't - * need to worry about the results of this function if your thread is not - * the current event handler. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 1 if event handling can start or continue - * \returns 0 if this thread must give up the events lock - * \see \ref fullstory "Multi-threaded I/O: the full story" - */ -int API_EXPORTED libusb_event_handling_ok(libusb_context *ctx) -{ - int r; - USBI_GET_CONTEXT(ctx); - - /* is someone else waiting to modify poll fds? if so, don't let this thread - * continue event handling */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - r = ctx->pollfd_modify; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - if (r) { - usbi_dbg("someone else is modifying poll fds"); - return 0; - } - - return 1; -} - - -/** \ingroup poll - * Determine if an active thread is handling events (i.e. if anyone is holding - * the event handling lock). - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 1 if a thread is handling events - * \returns 0 if there are no threads currently handling events - * \see \ref mtasync - */ -int API_EXPORTED libusb_event_handler_active(libusb_context *ctx) -{ - int r; - USBI_GET_CONTEXT(ctx); - - /* is someone else waiting to modify poll fds? if so, don't let this thread - * start event handling -- indicate that event handling is happening */ - usbi_mutex_lock(&ctx->pollfd_modify_lock); - r = ctx->pollfd_modify; - usbi_mutex_unlock(&ctx->pollfd_modify_lock); - if (r) { - usbi_dbg("someone else is modifying poll fds"); - return 1; - } - - return ctx->event_handler_active; -} - -/** \ingroup poll - * Acquire the event waiters lock. This lock is designed to be obtained under - * the situation where you want to be aware when events are completed, but - * some other thread is event handling so calling libusb_handle_events() is not - * allowed. - * - * You then obtain this lock, re-check that another thread is still handling - * events, then call libusb_wait_for_event(). - * - * You only need to use this lock if you are developing an application - * which calls poll() or select() on libusb's file descriptors directly, - * <b>and</b> may potentially be handling events from 2 threads simultaenously. - * If you stick to libusb's event handling loop functions (e.g. - * libusb_handle_events()) then you do not need to be concerned with this - * locking. - * - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_lock_event_waiters(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - usbi_mutex_lock(&ctx->event_waiters_lock); -} - -/** \ingroup poll - * Release the event waiters lock. - * \param ctx the context to operate on, or NULL for the default context - * \see \ref mtasync - */ -void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx) -{ - USBI_GET_CONTEXT(ctx); - usbi_mutex_unlock(&ctx->event_waiters_lock); -} - -/** \ingroup poll - * Wait for another thread to signal completion of an event. Must be called - * with the event waiters lock held, see libusb_lock_event_waiters(). - * - * This function will block until any of the following conditions are met: - * -# The timeout expires - * -# A transfer completes - * -# A thread releases the event handling lock through libusb_unlock_events() - * - * Condition 1 is obvious. Condition 2 unblocks your thread <em>after</em> - * the callback for the transfer has completed. Condition 3 is important - * because it means that the thread that was previously handling events is no - * longer doing so, so if any events are to complete, another thread needs to - * step up and start event handling. - * - * This function releases the event waiters lock before putting your thread - * to sleep, and reacquires the lock as it is being woken up. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv maximum timeout for this blocking function. A NULL value - * indicates unlimited timeout. - * \returns 0 after a transfer completes or another thread stops event handling - * \returns 1 if the timeout expired - * \see \ref mtasync - */ -int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) -{ - struct timespec timeout; - int r; - - USBI_GET_CONTEXT(ctx); - if (tv == NULL) { - usbi_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock); - return 0; - } - - r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout); - if (r < 0) { - usbi_err(ctx, "failed to read realtime clock, error %d", errno); - return LIBUSB_ERROR_OTHER; - } - - timeout.tv_sec += tv->tv_sec; - timeout.tv_nsec += tv->tv_usec * 1000; - if (timeout.tv_nsec > 1000000000) { - timeout.tv_nsec -= 1000000000; - timeout.tv_sec++; - } - - r = usbi_cond_timedwait(&ctx->event_waiters_cond, - &ctx->event_waiters_lock, &timeout); - return (r == ETIMEDOUT); -} - -static void handle_timeout(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - int r; - - itransfer->flags |= USBI_TRANSFER_TIMED_OUT; - r = libusb_cancel_transfer(transfer); - if (r < 0) - usbi_warn(TRANSFER_CTX(transfer), - "async cancel failed %d errno=%d", r, errno); -} - -static int handle_timeouts_locked(struct libusb_context *ctx) -{ - int r; - struct timespec systime_ts; - struct timeval systime; - struct usbi_transfer *transfer; - - if (list_empty(&ctx->flying_transfers)) - return 0; - - /* get current time */ - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &systime_ts); - if (r < 0) - return r; - - TIMESPEC_TO_TIMEVAL(&systime, &systime_ts); - - /* iterate through flying transfers list, finding all transfers that - * have expired timeouts */ - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - struct timeval *cur_tv = &transfer->timeout; - - /* if we've reached transfers of infinite timeout, we're all done */ - if (!timerisset(cur_tv)) - return 0; - - /* ignore timeouts we've already handled */ - if (transfer->flags & (USBI_TRANSFER_TIMED_OUT | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) - continue; - - /* if transfer has non-expired timeout, nothing more to do */ - if ((cur_tv->tv_sec > systime.tv_sec) || - (cur_tv->tv_sec == systime.tv_sec && - cur_tv->tv_usec > systime.tv_usec)) - return 0; - - /* otherwise, we've got an expired timeout to handle */ - handle_timeout(transfer); - } - return 0; -} - -static int handle_timeouts(struct libusb_context *ctx) -{ - int r; - USBI_GET_CONTEXT(ctx); - usbi_mutex_lock(&ctx->flying_transfers_lock); - r = handle_timeouts_locked(ctx); - usbi_mutex_unlock(&ctx->flying_transfers_lock); - return r; -} - -#ifdef USBI_TIMERFD_AVAILABLE -static int handle_timerfd_trigger(struct libusb_context *ctx) -{ - int r; - - r = disarm_timerfd(ctx); - if (r < 0) - return r; - - usbi_mutex_lock(&ctx->flying_transfers_lock); - - /* process the timeout that just happened */ - r = handle_timeouts_locked(ctx); - if (r < 0) - goto out; - - /* arm for next timeout*/ - r = arm_timerfd_for_next_timeout(ctx); - -out: - usbi_mutex_unlock(&ctx->flying_transfers_lock); - return r; -} -#endif - -/* do the actual event handling. assumes that no other thread is concurrently - * doing the same thing. */ -static int handle_events(struct libusb_context *ctx, struct timeval *tv) -{ - int r; - struct usbi_pollfd *ipollfd; - POLL_NFDS_TYPE nfds = 0; - struct pollfd *fds; - int i = -1; - int timeout_ms; - - usbi_mutex_lock(&ctx->pollfds_lock); - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - nfds++; - - /* TODO: malloc when number of fd's changes, not on every poll */ - fds = malloc(sizeof(*fds) * nfds); - if (!fds) { - usbi_mutex_unlock(&ctx->pollfds_lock); - return LIBUSB_ERROR_NO_MEM; - } - - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) { - struct libusb_pollfd *pollfd = &ipollfd->pollfd; - int fd = pollfd->fd; - i++; - fds[i].fd = fd; - fds[i].events = pollfd->events; - fds[i].revents = 0; - } - usbi_mutex_unlock(&ctx->pollfds_lock); - - timeout_ms = (tv->tv_sec * 1000) + (tv->tv_usec / 1000); - - /* round up to next millisecond */ - if (tv->tv_usec % 1000) - timeout_ms++; - - usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms); - r = usbi_poll(fds, nfds, timeout_ms); - usbi_dbg("poll() returned %d", r); - if (r == 0) { - free(fds); - return handle_timeouts(ctx); - } else if (r == -1 && errno == EINTR) { - free(fds); - return LIBUSB_ERROR_INTERRUPTED; - } else if (r < 0) { - free(fds); - usbi_err(ctx, "poll failed %d err=%d\n", r, errno); - return LIBUSB_ERROR_IO; - } - - /* fd[0] is always the ctrl pipe */ - if (fds[0].revents) { - /* another thread wanted to interrupt event handling, and it succeeded! - * handle any other events that cropped up at the same time, and - * simply return */ - usbi_dbg("caught a fish on the control pipe"); - - if (r == 1) { - r = 0; - goto handled; - } else { - /* prevent OS backend from trying to handle events on ctrl pipe */ - fds[0].revents = 0; - r--; - } - } - -#ifdef USBI_TIMERFD_AVAILABLE - /* on timerfd configurations, fds[1] is the timerfd */ - if (usbi_using_timerfd(ctx) && fds[1].revents) { - /* timerfd indicates that a timeout has expired */ - int ret; - usbi_dbg("timerfd triggered"); - - ret = handle_timerfd_trigger(ctx); - if (ret < 0) { - /* return error code */ - r = ret; - goto handled; - } else if (r == 1) { - /* no more active file descriptors, nothing more to do */ - r = 0; - goto handled; - } else { - /* more events pending... - * prevent OS backend from trying to handle events on timerfd */ - fds[1].revents = 0; - r--; - } - } -#endif - - r = usbi_backend->handle_events(ctx, fds, nfds, r); - if (r) - usbi_err(ctx, "backend handle_events failed with error %d", r); - -handled: - free(fds); - return r; -} - -/* returns the smallest of: - * 1. timeout of next URB - * 2. user-supplied timeout - * returns 1 if there is an already-expired timeout, otherwise returns 0 - * and populates out - */ -static int get_next_timeout(libusb_context *ctx, struct timeval *tv, - struct timeval *out) -{ - struct timeval timeout; - int r = libusb_get_next_timeout(ctx, &timeout); - if (r) { - /* timeout already expired? */ - if (!timerisset(&timeout)) - return 1; - - /* choose the smallest of next URB timeout or user specified timeout */ - if (timercmp(&timeout, tv, <)) - *out = timeout; - else - *out = *tv; - } else { - *out = *tv; - } - return 0; -} - -/** \ingroup poll - * Handle any pending events. - * - * libusb determines "pending events" by checking if any timeouts have expired - * and by checking the set of file descriptors for activity. - * - * If a zero timeval is passed, this function will handle any already-pending - * events and then immediately return in non-blocking style. - * - * If a non-zero timeval is passed and no events are currently pending, this - * function will block waiting for events to handle up until the specified - * timeout. If an event arrives or a signal is raised, this function will - * return early. - * - * If the parameter completed is not NULL then <em>after obtaining the event - * handling lock</em> this function will return immediately if the integer - * pointed to is not 0. This allows for race free waiting for the completion - * of a specific transfer. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or an all zero - * timeval struct for non-blocking mode - * \param completed pointer to completion integer to check, or NULL - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see \ref mtasync - */ -int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx, - struct timeval *tv, int *completed) -{ - int r; - struct timeval poll_timeout; - - USBI_GET_CONTEXT(ctx); - r = get_next_timeout(ctx, tv, &poll_timeout); - if (r) { - /* timeout already expired */ - return handle_timeouts(ctx); - } - -retry: - if (libusb_try_lock_events(ctx) == 0) { - if (completed == NULL || !*completed) { - /* we obtained the event lock: do our own event handling */ - usbi_dbg("doing our own event handling"); - r = handle_events(ctx, &poll_timeout); - } - libusb_unlock_events(ctx); - return r; - } - - /* another thread is doing event handling. wait for pthread events that - * notify event completion. */ - libusb_lock_event_waiters(ctx); - - if (completed && *completed) - goto already_done; - - if (!libusb_event_handler_active(ctx)) { - /* we hit a race: whoever was event handling earlier finished in the - * time it took us to reach this point. try the cycle again. */ - libusb_unlock_event_waiters(ctx); - usbi_dbg("event handler was active but went away, retrying"); - goto retry; - } - - usbi_dbg("another thread is doing event handling"); - r = libusb_wait_for_event(ctx, &poll_timeout); - -already_done: - libusb_unlock_event_waiters(ctx); - - if (r < 0) - return r; - else if (r == 1) - return handle_timeouts(ctx); - else - return 0; -} - -/** \ingroup poll - * Handle any pending events - * - * Like libusb_handle_events_timeout_completed(), but without the completed - * parameter, calling this function is equivalent to calling - * libusb_handle_events_timeout_completed() with a NULL completed parameter. - * - * This function is kept primarily for backwards compatibility. - * All new code should call libusb_handle_events_completed() or - * libusb_handle_events_timeout_completed() to avoid race conditions. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or an all zero - * timeval struct for non-blocking mode - * \returns 0 on success, or a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx, - struct timeval *tv) -{ - return libusb_handle_events_timeout_completed(ctx, tv, NULL); -} - -/** \ingroup poll - * Handle any pending events in blocking mode. There is currently a timeout - * hardcoded at 60 seconds but we plan to make it unlimited in future. For - * finer control over whether this function is blocking or non-blocking, or - * for control over the timeout, use libusb_handle_events_timeout_completed() - * instead. - * - * This function is kept primarily for backwards compatibility. - * All new code should call libusb_handle_events_completed() or - * libusb_handle_events_timeout_completed() to avoid race conditions. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 on success, or a LIBUSB_ERROR code on failure - */ -int API_EXPORTED libusb_handle_events(libusb_context *ctx) -{ - struct timeval tv; - tv.tv_sec = 60; - tv.tv_usec = 0; - return libusb_handle_events_timeout_completed(ctx, &tv, NULL); -} - -/** \ingroup poll - * Handle any pending events in blocking mode. - * - * Like libusb_handle_events(), with the addition of a completed parameter - * to allow for race free waiting for the completion of a specific transfer. - * - * See libusb_handle_events_timeout_completed() for details on the completed - * parameter. - * - * \param ctx the context to operate on, or NULL for the default context - * \param completed pointer to completion integer to check, or NULL - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see \ref mtasync - */ -int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx, - int *completed) -{ - struct timeval tv; - tv.tv_sec = 60; - tv.tv_usec = 0; - return libusb_handle_events_timeout_completed(ctx, &tv, completed); -} - -/** \ingroup poll - * Handle any pending events by polling file descriptors, without checking if - * any other threads are already doing so. Must be called with the event lock - * held, see libusb_lock_events(). - * - * This function is designed to be called under the situation where you have - * taken the event lock and are calling poll()/select() directly on libusb's - * file descriptors (as opposed to using libusb_handle_events() or similar). - * You detect events on libusb's descriptors, so you then call this function - * with a zero timeout value (while still holding the event lock). - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv the maximum time to block waiting for events, or zero for - * non-blocking mode - * \returns 0 on success, or a LIBUSB_ERROR code on failure - * \see \ref mtasync - */ -int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx, - struct timeval *tv) -{ - int r; - struct timeval poll_timeout; - - USBI_GET_CONTEXT(ctx); - r = get_next_timeout(ctx, tv, &poll_timeout); - if (r) { - /* timeout already expired */ - return handle_timeouts(ctx); - } - - return handle_events(ctx, &poll_timeout); -} - -/** \ingroup poll - * Determines whether your application must apply special timing considerations - * when monitoring libusb's file descriptors. - * - * This function is only useful for applications which retrieve and poll - * libusb's file descriptors in their own main loop (\ref pollmain). - * - * Ordinarily, libusb's event handler needs to be called into at specific - * moments in time (in addition to times when there is activity on the file - * descriptor set). The usual approach is to use libusb_get_next_timeout() - * to learn about when the next timeout occurs, and to adjust your - * poll()/select() timeout accordingly so that you can make a call into the - * library at that time. - * - * Some platforms supported by libusb do not come with this baggage - any - * events relevant to timing will be represented by activity on the file - * descriptor set, and libusb_get_next_timeout() will always return 0. - * This function allows you to detect whether you are running on such a - * platform. - * - * Since v1.0.5. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns 0 if you must call into libusb at times determined by - * libusb_get_next_timeout(), or 1 if all timeout events are handled internally - * or through regular activity on the file descriptors. - * \see \ref pollmain "Polling libusb file descriptors for event handling" - */ -int API_EXPORTED libusb_pollfds_handle_timeouts(libusb_context *ctx) -{ -#if defined(USBI_TIMERFD_AVAILABLE) - USBI_GET_CONTEXT(ctx); - return usbi_using_timerfd(ctx); -#else - (void)ctx; - return 0; -#endif -} - -/** \ingroup poll - * Determine the next internal timeout that libusb needs to handle. You only - * need to use this function if you are calling poll() or select() or similar - * on libusb's file descriptors yourself - you do not need to use it if you - * are calling libusb_handle_events() or a variant directly. - * - * You should call this function in your main loop in order to determine how - * long to wait for select() or poll() to return results. libusb needs to be - * called into at this timeout, so you should use it as an upper bound on - * your select() or poll() call. - * - * When the timeout has expired, call into libusb_handle_events_timeout() - * (perhaps in non-blocking mode) so that libusb can handle the timeout. - * - * This function may return 1 (success) and an all-zero timeval. If this is - * the case, it indicates that libusb has a timeout that has already expired - * so you should call libusb_handle_events_timeout() or similar immediately. - * A return code of 0 indicates that there are no pending timeouts. - * - * On some platforms, this function will always returns 0 (no pending - * timeouts). See \ref polltime. - * - * \param ctx the context to operate on, or NULL for the default context - * \param tv output location for a relative time against the current - * clock in which libusb must be called into in order to process timeout events - * \returns 0 if there are no pending timeouts, 1 if a timeout was returned, - * or LIBUSB_ERROR_OTHER on failure - */ -int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx, - struct timeval *tv) -{ - struct usbi_transfer *transfer; - struct timespec cur_ts; - struct timeval cur_tv; - struct timeval *next_timeout; - int r; - int found = 0; - - USBI_GET_CONTEXT(ctx); - if (usbi_using_timerfd(ctx)) - return 0; - - usbi_mutex_lock(&ctx->flying_transfers_lock); - if (list_empty(&ctx->flying_transfers)) { - usbi_mutex_unlock(&ctx->flying_transfers_lock); - usbi_dbg("no URBs, no timeout!"); - return 0; - } - - /* find next transfer which hasn't already been processed as timed out */ - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - if (transfer->flags & (USBI_TRANSFER_TIMED_OUT | USBI_TRANSFER_OS_HANDLES_TIMEOUT)) - continue; - - /* no timeout for this transfer? */ - if (!timerisset(&transfer->timeout)) - continue; - - found = 1; - break; - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (!found) { - usbi_dbg("no URB with timeout or all handled by OS; no timeout!"); - return 0; - } - - next_timeout = &transfer->timeout; - - r = usbi_backend->clock_gettime(USBI_CLOCK_MONOTONIC, &cur_ts); - if (r < 0) { - usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno); - return LIBUSB_ERROR_OTHER; - } - TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts); - - if (!timercmp(&cur_tv, next_timeout, <)) { - usbi_dbg("first timeout already expired"); - timerclear(tv); - } else { - timersub(next_timeout, &cur_tv, tv); - usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec); - } - - return 1; -} - -/** \ingroup poll - * Register notification functions for file descriptor additions/removals. - * These functions will be invoked for every new or removed file descriptor - * that libusb uses as an event source. - * - * To remove notifiers, pass NULL values for the function pointers. - * - * Note that file descriptors may have been added even before you register - * these notifiers (e.g. at libusb_init() time). - * - * Additionally, note that the removal notifier may be called during - * libusb_exit() (e.g. when it is closing file descriptors that were opened - * and added to the poll set at libusb_init() time). If you don't want this, - * remove the notifiers immediately before calling libusb_exit(). - * - * \param ctx the context to operate on, or NULL for the default context - * \param added_cb pointer to function for addition notifications - * \param removed_cb pointer to function for removal notifications - * \param user_data User data to be passed back to callbacks (useful for - * passing context information) - */ -void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx, - libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, - void *user_data) -{ - USBI_GET_CONTEXT(ctx); - ctx->fd_added_cb = added_cb; - ctx->fd_removed_cb = removed_cb; - ctx->fd_cb_user_data = user_data; -} - -/* Add a file descriptor to the list of file descriptors to be monitored. - * events should be specified as a bitmask of events passed to poll(), e.g. - * POLLIN and/or POLLOUT. */ -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events) -{ - struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd)); - if (!ipollfd) - return LIBUSB_ERROR_NO_MEM; - - usbi_dbg("add fd %d events %d", fd, events); - ipollfd->pollfd.fd = fd; - ipollfd->pollfd.events = events; - usbi_mutex_lock(&ctx->pollfds_lock); - list_add_tail(&ipollfd->list, &ctx->pollfds); - usbi_mutex_unlock(&ctx->pollfds_lock); - - if (ctx->fd_added_cb) - ctx->fd_added_cb(fd, events, ctx->fd_cb_user_data); - return 0; -} - -/* Remove a file descriptor from the list of file descriptors to be polled. */ -void usbi_remove_pollfd(struct libusb_context *ctx, int fd) -{ - struct usbi_pollfd *ipollfd; - int found = 0; - - usbi_dbg("remove fd %d", fd); - usbi_mutex_lock(&ctx->pollfds_lock); - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - if (ipollfd->pollfd.fd == fd) { - found = 1; - break; - } - - if (!found) { - usbi_dbg("couldn't find fd %d to remove", fd); - usbi_mutex_unlock(&ctx->pollfds_lock); - return; - } - - list_del(&ipollfd->list); - usbi_mutex_unlock(&ctx->pollfds_lock); - free(ipollfd); - if (ctx->fd_removed_cb) - ctx->fd_removed_cb(fd, ctx->fd_cb_user_data); -} - -/** \ingroup poll - * Retrieve a list of file descriptors that should be polled by your main loop - * as libusb event sources. - * - * The returned list is NULL-terminated and should be freed with free() when - * done. The actual list contents must not be touched. - * - * As file descriptors are a Unix-specific concept, this function is not - * available on Windows and will always return NULL. - * - * \param ctx the context to operate on, or NULL for the default context - * \returns a NULL-terminated list of libusb_pollfd structures - * \returns NULL on error - * \returns NULL on platforms where the functionality is not available - */ -DEFAULT_VISIBILITY -const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( - libusb_context *ctx) -{ -#ifndef OS_WINDOWS - struct libusb_pollfd **ret = NULL; - struct usbi_pollfd *ipollfd; - size_t i = 0; - size_t cnt = 0; - USBI_GET_CONTEXT(ctx); - - usbi_mutex_lock(&ctx->pollfds_lock); - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - cnt++; - - ret = calloc(cnt + 1, sizeof(struct libusb_pollfd *)); - if (!ret) - goto out; - - list_for_each_entry(ipollfd, &ctx->pollfds, list, struct usbi_pollfd) - ret[i++] = (struct libusb_pollfd *) ipollfd; - ret[cnt] = NULL; - -out: - usbi_mutex_unlock(&ctx->pollfds_lock); - return (const struct libusb_pollfd **) ret; -#else - return NULL; -#endif -} - -/* Backends call this from handle_events to report disconnection of a device. - * The transfers get cancelled appropriately. - */ -void usbi_handle_disconnect(struct libusb_device_handle *handle) -{ - struct usbi_transfer *cur; - struct usbi_transfer *to_cancel; - - usbi_dbg("device %d.%d", - handle->dev->bus_number, handle->dev->device_address); - - /* terminate all pending transfers with the LIBUSB_TRANSFER_NO_DEVICE - * status code. - * - * this is a bit tricky because: - * 1. we can't do transfer completion while holding flying_transfers_lock - * 2. the transfers list can change underneath us - if we were to build a - * list of transfers to complete (while holding look), the situation - * might be different by the time we come to free them - * - * so we resort to a loop-based approach as below - * FIXME: is this still potentially racy? - */ - - while (1) { - usbi_mutex_lock(&HANDLE_CTX(handle)->flying_transfers_lock); - to_cancel = NULL; - list_for_each_entry(cur, &HANDLE_CTX(handle)->flying_transfers, list, struct usbi_transfer) - if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == handle) { - to_cancel = cur; - break; - } - usbi_mutex_unlock(&HANDLE_CTX(handle)->flying_transfers_lock); - - if (!to_cancel) - break; - - usbi_backend->clear_transfer_priv(to_cancel); - usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE); - } - -} diff --git a/third_party/libusb/libusb/libusb-1.0.def b/third_party/libusb/libusb/libusb-1.0.def deleted file mode 100644 index 96abd17..0000000 --- a/third_party/libusb/libusb/libusb-1.0.def +++ /dev/null @@ -1,118 +0,0 @@ -LIBRARY -EXPORTS - libusb_alloc_transfer - libusb_alloc_transfer@4 = libusb_alloc_transfer - libusb_attach_kernel_driver - libusb_attach_kernel_driver@8 = libusb_attach_kernel_driver - libusb_bulk_transfer - libusb_bulk_transfer@24 = libusb_bulk_transfer - libusb_cancel_transfer - libusb_cancel_transfer@4 = libusb_cancel_transfer - libusb_claim_interface - libusb_claim_interface@8 = libusb_claim_interface - libusb_clear_halt - libusb_clear_halt@8 = libusb_clear_halt - libusb_close - libusb_close@4 = libusb_close - libusb_control_transfer - libusb_control_transfer@32 = libusb_control_transfer - libusb_detach_kernel_driver - libusb_detach_kernel_driver@8 = libusb_detach_kernel_driver - libusb_error_name - libusb_error_name@4 = libusb_error_name - libusb_event_handler_active - libusb_event_handler_active@4 = libusb_event_handler_active - libusb_event_handling_ok - libusb_event_handling_ok@4 = libusb_event_handling_ok - libusb_exit - libusb_exit@4 = libusb_exit - libusb_free_config_descriptor - libusb_free_config_descriptor@4 = libusb_free_config_descriptor - libusb_free_device_list - libusb_free_device_list@8 = libusb_free_device_list - libusb_free_transfer - libusb_free_transfer@4 = libusb_free_transfer - libusb_get_active_config_descriptor - libusb_get_active_config_descriptor@8 = libusb_get_active_config_descriptor - libusb_get_bus_number - libusb_get_bus_number@4 = libusb_get_bus_number - libusb_get_config_descriptor - libusb_get_config_descriptor@12 = libusb_get_config_descriptor - libusb_get_config_descriptor_by_value - libusb_get_config_descriptor_by_value@12 = libusb_get_config_descriptor_by_value - libusb_get_configuration - libusb_get_configuration@8 = libusb_get_configuration - libusb_get_device - libusb_get_device@4 = libusb_get_device - libusb_get_device_address - libusb_get_device_address@4 = libusb_get_device_address - libusb_get_device_descriptor - libusb_get_device_descriptor@8 = libusb_get_device_descriptor - libusb_get_device_list - libusb_get_device_list@8 = libusb_get_device_list - libusb_get_device_speed - libusb_get_device_speed@4 = libusb_get_device_speed - libusb_get_max_iso_packet_size - libusb_get_max_iso_packet_size@8 = libusb_get_max_iso_packet_size - libusb_get_max_packet_size - libusb_get_max_packet_size@8 = libusb_get_max_packet_size - libusb_get_next_timeout - libusb_get_next_timeout@8 = libusb_get_next_timeout - libusb_get_pollfds - libusb_get_pollfds@4 = libusb_get_pollfds - libusb_get_string_descriptor_ascii - libusb_get_string_descriptor_ascii@16 = libusb_get_string_descriptor_ascii - libusb_handle_events - libusb_handle_events@4 = libusb_handle_events - libusb_handle_events_completed - libusb_handle_events_completed@8 = libusb_handle_events_completed - libusb_handle_events_locked - libusb_handle_events_locked@8 = libusb_handle_events_locked - libusb_handle_events_timeout - libusb_handle_events_timeout@8 = libusb_handle_events_timeout - libusb_handle_events_timeout_completed - libusb_handle_events_timeout_completed@12 = libusb_handle_events_timeout_completed - libusb_has_capability - libusb_has_capability@4 = libusb_has_capability - libusb_init - libusb_init@4 = libusb_init - libusb_interrupt_transfer - libusb_interrupt_transfer@24 = libusb_interrupt_transfer - libusb_kernel_driver_active - libusb_kernel_driver_active@8 = libusb_kernel_driver_active - libusb_lock_event_waiters - libusb_lock_event_waiters@4 = libusb_lock_event_waiters - libusb_lock_events - libusb_lock_events@4 = libusb_lock_events - libusb_open - libusb_open@8 = libusb_open - libusb_open_device_with_vid_pid - libusb_open_device_with_vid_pid@12 = libusb_open_device_with_vid_pid - libusb_pollfds_handle_timeouts - libusb_pollfds_handle_timeouts@4 = libusb_pollfds_handle_timeouts - libusb_ref_device - libusb_ref_device@4 = libusb_ref_device - libusb_release_interface - libusb_release_interface@8 = libusb_release_interface - libusb_reset_device - libusb_reset_device@4 = libusb_reset_device - libusb_set_configuration - libusb_set_configuration@8 = libusb_set_configuration - libusb_set_debug - libusb_set_debug@8 = libusb_set_debug - libusb_set_interface_alt_setting - libusb_set_interface_alt_setting@12 = libusb_set_interface_alt_setting - libusb_set_pollfd_notifiers - libusb_set_pollfd_notifiers@16 = libusb_set_pollfd_notifiers - libusb_submit_transfer - libusb_submit_transfer@4 = libusb_submit_transfer - libusb_try_lock_events - libusb_try_lock_events@4 = libusb_try_lock_events - libusb_unlock_event_waiters - libusb_unlock_event_waiters@4 = libusb_unlock_event_waiters - libusb_unlock_events - libusb_unlock_events@4 = libusb_unlock_events - libusb_unref_device - libusb_unref_device@4 = libusb_unref_device - libusb_wait_for_event - libusb_wait_for_event@8 = libusb_wait_for_event diff --git a/third_party/libusb/libusb/libusb-1.0.rc b/third_party/libusb/libusb/libusb-1.0.rc deleted file mode 100644 index 0171f17..0000000 --- a/third_party/libusb/libusb/libusb-1.0.rc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * For Windows: input this file to the Resoure Compiler to produce a binary - * .res file. This is then embedded in the resultant library (like any other - * compilation object). - * The information can then be queried using standard APIs and can also be - * viewed with utilities such as Windows Explorer. - */ -#include "winresrc.h" - -#include "version.h" -#ifndef LIBUSB_VERSIONSTRING -#define LU_STR(s) #s -#define LU_XSTR(s) LU_STR(s) -#if LIBUSB_NANO > 0 -#define LIBUSB_VERSIONSTRING \ - LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \ - LU_XSTR(LIBUSB_MICRO) "." LU_XSTR(LIBUSB_NANO) LIBUSB_RC "\0" -#else -#define LIBUSB_VERSIONSTRING \ - LU_XSTR(LIBUSB_MAJOR) "." LU_XSTR(LIBUSB_MINOR) "." \ - LU_XSTR(LIBUSB_MICRO) LIBUSB_RC "\0" -#endif -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO - PRODUCTVERSION LIBUSB_MAJOR,LIBUSB_MINOR,LIBUSB_MICRO,LIBUSB_NANO - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "\0" - VALUE "CompanyName", "libusb.org\0" - VALUE "FileDescription", "C library for writing portable USB drivers in userspace\0" - VALUE "FileVersion", LIBUSB_VERSIONSTRING - VALUE "InternalName", "libusb\0" - VALUE "LegalCopyright", "See individual source files, GNU LGPL v2.1 or later.\0" - VALUE "LegalTrademarks", "http://www.gnu.org/licenses/lgpl-2.1.html\0" - VALUE "OriginalFilename", "libusb-1.0.dll\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "libusb-1.0\0" - VALUE "ProductVersion", LIBUSB_VERSIONSTRING - VALUE "SpecialBuild", "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END diff --git a/third_party/libusb/libusb/libusb.h b/third_party/libusb/libusb/libusb.h deleted file mode 100644 index de2d050..0000000 --- a/third_party/libusb/libusb/libusb.h +++ /dev/null @@ -1,1394 +0,0 @@ -/* - * Public libusb header file - * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_H -#define LIBUSB_H - -#ifdef _MSC_VER -/* on MS environments, the inline keyword is available in C++ only */ -#define inline __inline -/* ssize_t is also not available (copy/paste from MinGW) */ -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -#undef ssize_t -#ifdef _WIN64 - typedef __int64 ssize_t; -#else - typedef int ssize_t; -#endif /* _WIN64 */ -#endif /* _SSIZE_T_DEFINED */ -#endif /* _MSC_VER */ - -/* stdint.h is also not usually available on MS */ -#if defined(_MSC_VER) && (_MSC_VER < 1600) && (!defined(_STDINT)) && (!defined(_STDINT_H)) -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -#else -#include <stdint.h> -#endif - -#include <sys/types.h> -#include <time.h> -#include <limits.h> - -#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) -#include <sys/time.h> -#endif - -/* 'interface' might be defined as a macro on Windows, so we need to - * undefine it so as not to break the current libusb API, because - * libusb_config_descriptor has an 'interface' member - * As this can be problematic if you include windows.h after libusb.h - * in your sources, we force windows.h to be included first. */ -#if defined(_WIN32) || defined(__CYGWIN__) -#include <windows.h> -#if defined(interface) -#undef interface -#endif -#endif - -/** \def LIBUSB_CALL - * \ingroup misc - * libusb's Windows calling convention. - * - * Under Windows, the selection of available compilers and configurations - * means that, unlike other platforms, there is not <em>one true calling - * convention</em> (calling convention: the manner in which parameters are - * passed to funcions in the generated assembly code). - * - * Matching the Windows API itself, libusb uses the WINAPI convention (which - * translates to the <tt>stdcall</tt> convention) and guarantees that the - * library is compiled in this way. The public header file also includes - * appropriate annotations so that your own software will use the right - * convention, even if another convention is being used by default within - * your codebase. - * - * The one consideration that you must apply in your software is to mark - * all functions which you use as libusb callbacks with this LIBUSB_CALL - * annotation, so that they too get compiled for the correct calling - * convention. - * - * On non-Windows operating systems, this macro is defined as nothing. This - * means that you can apply it to your code without worrying about - * cross-platform compatibility. - */ -/* LIBUSB_CALL must be defined on both definition and declaration of libusb - * functions. You'd think that declaration would be enough, but cygwin will - * complain about conflicting types unless both are marked this way. - * The placement of this macro is important too; it must appear after the - * return type, before the function name. See internal documentation for - * API_EXPORTED. - */ -#if defined(_WIN32) || defined(__CYGWIN__) -#define LIBUSB_CALL WINAPI -#else -#define LIBUSB_CALL -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** \def libusb_cpu_to_le16 - * \ingroup misc - * Convert a 16-bit value from host-endian to little-endian format. On - * little endian systems, this function does nothing. On big endian systems, - * the bytes are swapped. - * \param x the host-endian value to convert - * \returns the value in little-endian byte order - */ -static inline uint16_t libusb_cpu_to_le16(const uint16_t x) -{ - union { - uint8_t b8[2]; - uint16_t b16; - } _tmp; - _tmp.b8[1] = x >> 8; - _tmp.b8[0] = x & 0xff; - return _tmp.b16; -} - -/** \def libusb_le16_to_cpu - * \ingroup misc - * Convert a 16-bit value from little-endian to host-endian format. On - * little endian systems, this function does nothing. On big endian systems, - * the bytes are swapped. - * \param x the little-endian value to convert - * \returns the value in host-endian byte order - */ -#define libusb_le16_to_cpu libusb_cpu_to_le16 - -/* standard USB stuff */ - -/** \ingroup desc - * Device and/or Interface Class codes */ -enum libusb_class_code { - /** In the context of a \ref libusb_device_descriptor "device descriptor", - * this bDeviceClass value indicates that each interface specifies its - * own class information and all interfaces operate independently. - */ - LIBUSB_CLASS_PER_INTERFACE = 0, - - /** Audio class */ - LIBUSB_CLASS_AUDIO = 1, - - /** Communications class */ - LIBUSB_CLASS_COMM = 2, - - /** Human Interface Device class */ - LIBUSB_CLASS_HID = 3, - - /** Physical */ - LIBUSB_CLASS_PHYSICAL = 5, - - /** Printer class */ - LIBUSB_CLASS_PRINTER = 7, - - /** Image class */ - LIBUSB_CLASS_PTP = 6, /* legacy name from libusb-0.1 usb.h */ - LIBUSB_CLASS_IMAGE = 6, - - /** Mass storage class */ - LIBUSB_CLASS_MASS_STORAGE = 8, - - /** Hub class */ - LIBUSB_CLASS_HUB = 9, - - /** Data class */ - LIBUSB_CLASS_DATA = 10, - - /** Smart Card */ - LIBUSB_CLASS_SMART_CARD = 0x0b, - - /** Content Security */ - LIBUSB_CLASS_CONTENT_SECURITY = 0x0d, - - /** Video */ - LIBUSB_CLASS_VIDEO = 0x0e, - - /** Personal Healthcare */ - LIBUSB_CLASS_PERSONAL_HEALTHCARE = 0x0f, - - /** Diagnostic Device */ - LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc, - - /** Wireless class */ - LIBUSB_CLASS_WIRELESS = 0xe0, - - /** Application class */ - LIBUSB_CLASS_APPLICATION = 0xfe, - - /** Class is vendor-specific */ - LIBUSB_CLASS_VENDOR_SPEC = 0xff -}; - -/** \ingroup desc - * Descriptor types as defined by the USB specification. */ -enum libusb_descriptor_type { - /** Device descriptor. See libusb_device_descriptor. */ - LIBUSB_DT_DEVICE = 0x01, - - /** Configuration descriptor. See libusb_config_descriptor. */ - LIBUSB_DT_CONFIG = 0x02, - - /** String descriptor */ - LIBUSB_DT_STRING = 0x03, - - /** Interface descriptor. See libusb_interface_descriptor. */ - LIBUSB_DT_INTERFACE = 0x04, - - /** Endpoint descriptor. See libusb_endpoint_descriptor. */ - LIBUSB_DT_ENDPOINT = 0x05, - - /** HID descriptor */ - LIBUSB_DT_HID = 0x21, - - /** HID report descriptor */ - LIBUSB_DT_REPORT = 0x22, - - /** Physical descriptor */ - LIBUSB_DT_PHYSICAL = 0x23, - - /** Hub descriptor */ - LIBUSB_DT_HUB = 0x29 -}; - -/* Descriptor sizes per descriptor type */ -#define LIBUSB_DT_DEVICE_SIZE 18 -#define LIBUSB_DT_CONFIG_SIZE 9 -#define LIBUSB_DT_INTERFACE_SIZE 9 -#define LIBUSB_DT_ENDPOINT_SIZE 7 -#define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ -#define LIBUSB_DT_HUB_NONVAR_SIZE 7 - -#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ -#define LIBUSB_ENDPOINT_DIR_MASK 0x80 - -/** \ingroup desc - * Endpoint direction. Values for bit 7 of the - * \ref libusb_endpoint_descriptor::bEndpointAddress "endpoint address" scheme. - */ -enum libusb_endpoint_direction { - /** In: device-to-host */ - LIBUSB_ENDPOINT_IN = 0x80, - - /** Out: host-to-device */ - LIBUSB_ENDPOINT_OUT = 0x00 -}; - -#define LIBUSB_TRANSFER_TYPE_MASK 0x03 /* in bmAttributes */ - -/** \ingroup desc - * Endpoint transfer type. Values for bits 0:1 of the - * \ref libusb_endpoint_descriptor::bmAttributes "endpoint attributes" field. - */ -enum libusb_transfer_type { - /** Control endpoint */ - LIBUSB_TRANSFER_TYPE_CONTROL = 0, - - /** Isochronous endpoint */ - LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1, - - /** Bulk endpoint */ - LIBUSB_TRANSFER_TYPE_BULK = 2, - - /** Interrupt endpoint */ - LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 -}; - -/** \ingroup misc - * Standard requests, as defined in table 9-3 of the USB2 specifications */ -enum libusb_standard_request { - /** Request status of the specific recipient */ - LIBUSB_REQUEST_GET_STATUS = 0x00, - - /** Clear or disable a specific feature */ - LIBUSB_REQUEST_CLEAR_FEATURE = 0x01, - - /* 0x02 is reserved */ - - /** Set or enable a specific feature */ - LIBUSB_REQUEST_SET_FEATURE = 0x03, - - /* 0x04 is reserved */ - - /** Set device address for all future accesses */ - LIBUSB_REQUEST_SET_ADDRESS = 0x05, - - /** Get the specified descriptor */ - LIBUSB_REQUEST_GET_DESCRIPTOR = 0x06, - - /** Used to update existing descriptors or add new descriptors */ - LIBUSB_REQUEST_SET_DESCRIPTOR = 0x07, - - /** Get the current device configuration value */ - LIBUSB_REQUEST_GET_CONFIGURATION = 0x08, - - /** Set device configuration */ - LIBUSB_REQUEST_SET_CONFIGURATION = 0x09, - - /** Return the selected alternate setting for the specified interface */ - LIBUSB_REQUEST_GET_INTERFACE = 0x0A, - - /** Select an alternate interface for the specified interface */ - LIBUSB_REQUEST_SET_INTERFACE = 0x0B, - - /** Set then report an endpoint's synchronization frame */ - LIBUSB_REQUEST_SYNCH_FRAME = 0x0C -}; - -/** \ingroup misc - * Request type bits of the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control - * transfers. */ -enum libusb_request_type { - /** Standard */ - LIBUSB_REQUEST_TYPE_STANDARD = (0x00 << 5), - - /** Class */ - LIBUSB_REQUEST_TYPE_CLASS = (0x01 << 5), - - /** Vendor */ - LIBUSB_REQUEST_TYPE_VENDOR = (0x02 << 5), - - /** Reserved */ - LIBUSB_REQUEST_TYPE_RESERVED = (0x03 << 5) -}; - -/** \ingroup misc - * Recipient bits of the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field in control - * transfers. Values 4 through 31 are reserved. */ -enum libusb_request_recipient { - /** Device */ - LIBUSB_RECIPIENT_DEVICE = 0x00, - - /** Interface */ - LIBUSB_RECIPIENT_INTERFACE = 0x01, - - /** Endpoint */ - LIBUSB_RECIPIENT_ENDPOINT = 0x02, - - /** Other */ - LIBUSB_RECIPIENT_OTHER = 0x03 -}; - -#define LIBUSB_ISO_SYNC_TYPE_MASK 0x0C - -/** \ingroup desc - * Synchronization type for isochronous endpoints. Values for bits 2:3 of the - * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in - * libusb_endpoint_descriptor. - */ -enum libusb_iso_sync_type { - /** No synchronization */ - LIBUSB_ISO_SYNC_TYPE_NONE = 0, - - /** Asynchronous */ - LIBUSB_ISO_SYNC_TYPE_ASYNC = 1, - - /** Adaptive */ - LIBUSB_ISO_SYNC_TYPE_ADAPTIVE = 2, - - /** Synchronous */ - LIBUSB_ISO_SYNC_TYPE_SYNC = 3 -}; - -#define LIBUSB_ISO_USAGE_TYPE_MASK 0x30 - -/** \ingroup desc - * Usage type for isochronous endpoints. Values for bits 4:5 of the - * \ref libusb_endpoint_descriptor::bmAttributes "bmAttributes" field in - * libusb_endpoint_descriptor. - */ -enum libusb_iso_usage_type { - /** Data endpoint */ - LIBUSB_ISO_USAGE_TYPE_DATA = 0, - - /** Feedback endpoint */ - LIBUSB_ISO_USAGE_TYPE_FEEDBACK = 1, - - /** Implicit feedback Data endpoint */ - LIBUSB_ISO_USAGE_TYPE_IMPLICIT = 2 -}; - -/** \ingroup desc - * A structure representing the standard USB device descriptor. This - * descriptor is documented in section 9.6.1 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_device_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this - * context. */ - uint8_t bDescriptorType; - - /** USB specification release number in binary-coded decimal. A value of - * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ - uint16_t bcdUSB; - - /** USB-IF class code for the device. See \ref libusb_class_code. */ - uint8_t bDeviceClass; - - /** USB-IF subclass code for the device, qualified by the bDeviceClass - * value */ - uint8_t bDeviceSubClass; - - /** USB-IF protocol code for the device, qualified by the bDeviceClass and - * bDeviceSubClass values */ - uint8_t bDeviceProtocol; - - /** Maximum packet size for endpoint 0 */ - uint8_t bMaxPacketSize0; - - /** USB-IF vendor ID */ - uint16_t idVendor; - - /** USB-IF product ID */ - uint16_t idProduct; - - /** Device release number in binary-coded decimal */ - uint16_t bcdDevice; - - /** Index of string descriptor describing manufacturer */ - uint8_t iManufacturer; - - /** Index of string descriptor describing product */ - uint8_t iProduct; - - /** Index of string descriptor containing device serial number */ - uint8_t iSerialNumber; - - /** Number of possible configurations */ - uint8_t bNumConfigurations; -}; - -/** \ingroup desc - * A structure representing the standard USB endpoint descriptor. This - * descriptor is documented in section 9.6.3 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_endpoint_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_ENDPOINT LIBUSB_DT_ENDPOINT in - * this context. */ - uint8_t bDescriptorType; - - /** The address of the endpoint described by this descriptor. Bits 0:3 are - * the endpoint number. Bits 4:6 are reserved. Bit 7 indicates direction, - * see \ref libusb_endpoint_direction. - */ - uint8_t bEndpointAddress; - - /** Attributes which apply to the endpoint when it is configured using - * the bConfigurationValue. Bits 0:1 determine the transfer type and - * correspond to \ref libusb_transfer_type. Bits 2:3 are only used for - * isochronous endpoints and correspond to \ref libusb_iso_sync_type. - * Bits 4:5 are also only used for isochronous endpoints and correspond to - * \ref libusb_iso_usage_type. Bits 6:7 are reserved. - */ - uint8_t bmAttributes; - - /** Maximum packet size this endpoint is capable of sending/receiving. */ - uint16_t wMaxPacketSize; - - /** Interval for polling endpoint for data transfers. */ - uint8_t bInterval; - - /** For audio devices only: the rate at which synchronization feedback - * is provided. */ - uint8_t bRefresh; - - /** For audio devices only: the address if the synch endpoint */ - uint8_t bSynchAddress; - - /** Extra descriptors. If libusb encounters unknown endpoint descriptors, - * it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A structure representing the standard USB interface descriptor. This - * descriptor is documented in section 9.6.5 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_interface_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_INTERFACE LIBUSB_DT_INTERFACE - * in this context. */ - uint8_t bDescriptorType; - - /** Number of this interface */ - uint8_t bInterfaceNumber; - - /** Value used to select this alternate setting for this interface */ - uint8_t bAlternateSetting; - - /** Number of endpoints used by this interface (excluding the control - * endpoint). */ - uint8_t bNumEndpoints; - - /** USB-IF class code for this interface. See \ref libusb_class_code. */ - uint8_t bInterfaceClass; - - /** USB-IF subclass code for this interface, qualified by the - * bInterfaceClass value */ - uint8_t bInterfaceSubClass; - - /** USB-IF protocol code for this interface, qualified by the - * bInterfaceClass and bInterfaceSubClass values */ - uint8_t bInterfaceProtocol; - - /** Index of string descriptor describing this interface */ - uint8_t iInterface; - - /** Array of endpoint descriptors. This length of this array is determined - * by the bNumEndpoints field. */ - const struct libusb_endpoint_descriptor *endpoint; - - /** Extra descriptors. If libusb encounters unknown interface descriptors, - * it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup desc - * A collection of alternate settings for a particular USB interface. - */ -struct libusb_interface { - /** Array of interface descriptors. The length of this array is determined - * by the num_altsetting field. */ - const struct libusb_interface_descriptor *altsetting; - - /** The number of alternate settings that belong to this interface */ - int num_altsetting; -}; - -/** \ingroup desc - * A structure representing the standard USB configuration descriptor. This - * descriptor is documented in section 9.6.3 of the USB 2.0 specification. - * All multiple-byte fields are represented in host-endian format. - */ -struct libusb_config_descriptor { - /** Size of this descriptor (in bytes) */ - uint8_t bLength; - - /** Descriptor type. Will have value - * \ref libusb_descriptor_type::LIBUSB_DT_CONFIG LIBUSB_DT_CONFIG - * in this context. */ - uint8_t bDescriptorType; - - /** Total length of data returned for this configuration */ - uint16_t wTotalLength; - - /** Number of interfaces supported by this configuration */ - uint8_t bNumInterfaces; - - /** Identifier value for this configuration */ - uint8_t bConfigurationValue; - - /** Index of string descriptor describing this configuration */ - uint8_t iConfiguration; - - /** Configuration characteristics */ - uint8_t bmAttributes; - - /** Maximum power consumption of the USB device from this bus in this - * configuration when the device is fully opreation. Expressed in units - * of 2 mA. */ - uint8_t MaxPower; - - /** Array of interfaces supported by this configuration. The length of - * this array is determined by the bNumInterfaces field. */ - const struct libusb_interface *interface; - - /** Extra descriptors. If libusb encounters unknown configuration - * descriptors, it will store them here, should you wish to parse them. */ - const unsigned char *extra; - - /** Length of the extra descriptors, in bytes. */ - int extra_length; -}; - -/** \ingroup asyncio - * Setup packet for control transfers. */ -struct libusb_control_setup { - /** Request type. Bits 0:4 determine recipient, see - * \ref libusb_request_recipient. Bits 5:6 determine type, see - * \ref libusb_request_type. Bit 7 determines data transfer direction, see - * \ref libusb_endpoint_direction. - */ - uint8_t bmRequestType; - - /** Request. If the type bits of bmRequestType are equal to - * \ref libusb_request_type::LIBUSB_REQUEST_TYPE_STANDARD - * "LIBUSB_REQUEST_TYPE_STANDARD" then this field refers to - * \ref libusb_standard_request. For other cases, use of this field is - * application-specific. */ - uint8_t bRequest; - - /** Value. Varies according to request */ - uint16_t wValue; - - /** Index. Varies according to request, typically used to pass an index - * or offset */ - uint16_t wIndex; - - /** Number of bytes to transfer */ - uint16_t wLength; -}; - -#define LIBUSB_CONTROL_SETUP_SIZE (sizeof(struct libusb_control_setup)) - -/* libusb */ - -struct libusb_context; -struct libusb_device; -struct libusb_device_handle; - -/** \ingroup lib - * Structure representing a libusb session. The concept of individual libusb - * sessions allows for your program to use two libraries (or dynamically - * load two modules) which both independently use libusb. This will prevent - * interference between the individual libusb users - for example - * libusb_set_debug() will not affect the other user of the library, and - * libusb_exit() will not destroy resources that the other user is still - * using. - * - * Sessions are created by libusb_init() and destroyed through libusb_exit(). - * If your application is guaranteed to only ever include a single libusb - * user (i.e. you), you do not have to worry about contexts: pass NULL in - * every function call where a context is required. The default context - * will be used. - * - * For more information, see \ref contexts. - */ -typedef struct libusb_context libusb_context; - -/** \ingroup dev - * Structure representing a USB device detected on the system. This is an - * opaque type for which you are only ever provided with a pointer, usually - * originating from libusb_get_device_list(). - * - * Certain operations can be performed on a device, but in order to do any - * I/O you will have to first obtain a device handle using libusb_open(). - * - * Devices are reference counted with libusb_device_ref() and - * libusb_device_unref(), and are freed when the reference count reaches 0. - * New devices presented by libusb_get_device_list() have a reference count of - * 1, and libusb_free_device_list() can optionally decrease the reference count - * on all devices in the list. libusb_open() adds another reference which is - * later destroyed by libusb_close(). - */ -typedef struct libusb_device libusb_device; - - -/** \ingroup dev - * Structure representing a handle on a USB device. This is an opaque type for - * which you are only ever provided with a pointer, usually originating from - * libusb_open(). - * - * A device handle is used to perform I/O and other operations. When finished - * with a device handle, you should call libusb_close(). - */ -typedef struct libusb_device_handle libusb_device_handle; - -/** \ingroup dev - * Speed codes. Indicates the speed at which the device is operating. - */ -enum libusb_speed { - /** The OS doesn't report or know the device speed. */ - LIBUSB_SPEED_UNKNOWN = 0, - - /** The device is operating at low speed (1.5MBit/s). */ - LIBUSB_SPEED_LOW = 1, - - /** The device is operating at full speed (12MBit/s). */ - LIBUSB_SPEED_FULL = 2, - - /** The device is operating at high speed (480MBit/s). */ - LIBUSB_SPEED_HIGH = 3, - - /** The device is operating at super speed (5000MBit/s). */ - LIBUSB_SPEED_SUPER = 4, -}; - -/** \ingroup misc - * Error codes. Most libusb functions return 0 on success or one of these - * codes on failure. - * You can call \ref libusb_error_name() to retrieve a string representation - * of an error code. - */ -enum libusb_error { - /** Success (no error) */ - LIBUSB_SUCCESS = 0, - - /** Input/output error */ - LIBUSB_ERROR_IO = -1, - - /** Invalid parameter */ - LIBUSB_ERROR_INVALID_PARAM = -2, - - /** Access denied (insufficient permissions) */ - LIBUSB_ERROR_ACCESS = -3, - - /** No such device (it may have been disconnected) */ - LIBUSB_ERROR_NO_DEVICE = -4, - - /** Entity not found */ - LIBUSB_ERROR_NOT_FOUND = -5, - - /** Resource busy */ - LIBUSB_ERROR_BUSY = -6, - - /** Operation timed out */ - LIBUSB_ERROR_TIMEOUT = -7, - - /** Overflow */ - LIBUSB_ERROR_OVERFLOW = -8, - - /** Pipe error */ - LIBUSB_ERROR_PIPE = -9, - - /** System call interrupted (perhaps due to signal) */ - LIBUSB_ERROR_INTERRUPTED = -10, - - /** Insufficient memory */ - LIBUSB_ERROR_NO_MEM = -11, - - /** Operation not supported or unimplemented on this platform */ - LIBUSB_ERROR_NOT_SUPPORTED = -12, - - /* NB! Remember to update libusb_error_name() - when adding new error codes here. */ - - /** Other error */ - LIBUSB_ERROR_OTHER = -99 -}; - -/** \ingroup asyncio - * Transfer status codes */ -enum libusb_transfer_status { - /** Transfer completed without error. Note that this does not indicate - * that the entire amount of requested data was transferred. */ - LIBUSB_TRANSFER_COMPLETED, - - /** Transfer failed */ - LIBUSB_TRANSFER_ERROR, - - /** Transfer timed out */ - LIBUSB_TRANSFER_TIMED_OUT, - - /** Transfer was cancelled */ - LIBUSB_TRANSFER_CANCELLED, - - /** For bulk/interrupt endpoints: halt condition detected (endpoint - * stalled). For control endpoints: control request not supported. */ - LIBUSB_TRANSFER_STALL, - - /** Device was disconnected */ - LIBUSB_TRANSFER_NO_DEVICE, - - /** Device sent more data than requested */ - LIBUSB_TRANSFER_OVERFLOW -}; - -/** \ingroup asyncio - * libusb_transfer.flags values */ -enum libusb_transfer_flags { - /** Report short frames as errors */ - LIBUSB_TRANSFER_SHORT_NOT_OK = 1<<0, - - /** Automatically free() transfer buffer during libusb_free_transfer() */ - LIBUSB_TRANSFER_FREE_BUFFER = 1<<1, - - /** Automatically call libusb_free_transfer() after callback returns. - * If this flag is set, it is illegal to call libusb_free_transfer() - * from your transfer callback, as this will result in a double-free - * when this flag is acted upon. */ - LIBUSB_TRANSFER_FREE_TRANSFER = 1<<2 -}; - -/** \ingroup asyncio - * Isochronous packet descriptor. */ -struct libusb_iso_packet_descriptor { - /** Length of data to request in this packet */ - unsigned int length; - - /** Amount of data that was actually transferred */ - unsigned int actual_length; - - /** Status code for this packet */ - enum libusb_transfer_status status; -}; - -struct libusb_transfer; - -/** \ingroup asyncio - * Asynchronous transfer callback function type. When submitting asynchronous - * transfers, you pass a pointer to a callback function of this type via the - * \ref libusb_transfer::callback "callback" member of the libusb_transfer - * structure. libusb will call this function later, when the transfer has - * completed or failed. See \ref asyncio for more information. - * \param transfer The libusb_transfer struct the callback function is being - * notified about. - */ -typedef void (LIBUSB_CALL *libusb_transfer_cb_fn)(struct libusb_transfer *transfer); - -/** \ingroup asyncio - * The generic USB transfer structure. The user populates this structure and - * then submits it in order to request a transfer. After the transfer has - * completed, the library populates the transfer with the results and passes - * it back to the user. - */ -struct libusb_transfer { - /** Handle of the device that this transfer will be submitted to */ - libusb_device_handle *dev_handle; - - /** A bitwise OR combination of \ref libusb_transfer_flags. */ - uint8_t flags; - - /** Address of the endpoint where this transfer will be sent. */ - unsigned char endpoint; - - /** Type of the endpoint from \ref libusb_transfer_type */ - unsigned char type; - - /** Timeout for this transfer in millseconds. A value of 0 indicates no - * timeout. */ - unsigned int timeout; - - /** The status of the transfer. Read-only, and only for use within - * transfer callback function. - * - * If this is an isochronous transfer, this field may read COMPLETED even - * if there were errors in the frames. Use the - * \ref libusb_iso_packet_descriptor::status "status" field in each packet - * to determine if errors occurred. */ - enum libusb_transfer_status status; - - /** Length of the data buffer */ - int length; - - /** Actual length of data that was transferred. Read-only, and only for - * use within transfer callback function. Not valid for isochronous - * endpoint transfers. */ - int actual_length; - - /** Callback function. This will be invoked when the transfer completes, - * fails, or is cancelled. */ - libusb_transfer_cb_fn callback; - - /** User context data to pass to the callback function. */ - void *user_data; - - /** Data buffer */ - unsigned char *buffer; - - /** Number of isochronous packets. Only used for I/O with isochronous - * endpoints. */ - int num_iso_packets; - - /** Isochronous packet descriptors, for isochronous transfers only. */ - struct libusb_iso_packet_descriptor iso_packet_desc -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) - [] /* valid C99 code */ -#else - [0] /* non-standard, but usually working code */ -#endif - ; -}; - -/** \ingroup misc - * Capabilities supported by this instance of libusb. Test if the running - * library supports a given capability by calling - * \ref libusb_has_capability(). - */ -enum libusb_capability { - /** The libusb_get_device_speed() API is available. */ - LIBUSB_CAN_GET_DEVICE_SPEED = 0, -}; - -int LIBUSB_CALL libusb_init(libusb_context **ctx); -void LIBUSB_CALL libusb_exit(libusb_context *ctx); -void LIBUSB_CALL libusb_set_debug(libusb_context *ctx, int level); -int LIBUSB_CALL libusb_has_capability(uint32_t capability); -const char * LIBUSB_CALL libusb_error_name(int errcode); - -ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, - libusb_device ***list); -void LIBUSB_CALL libusb_free_device_list(libusb_device **list, - int unref_devices); -libusb_device * LIBUSB_CALL libusb_ref_device(libusb_device *dev); -void LIBUSB_CALL libusb_unref_device(libusb_device *dev); - -int LIBUSB_CALL libusb_get_configuration(libusb_device_handle *dev, - int *config); -int LIBUSB_CALL libusb_get_device_descriptor(libusb_device *dev, - struct libusb_device_descriptor *desc); -int LIBUSB_CALL libusb_get_active_config_descriptor(libusb_device *dev, - struct libusb_config_descriptor **config); -int LIBUSB_CALL libusb_get_config_descriptor(libusb_device *dev, - uint8_t config_index, struct libusb_config_descriptor **config); -int LIBUSB_CALL libusb_get_config_descriptor_by_value(libusb_device *dev, - uint8_t bConfigurationValue, struct libusb_config_descriptor **config); -void LIBUSB_CALL libusb_free_config_descriptor( - struct libusb_config_descriptor *config); -uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev); -uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device *dev); -int LIBUSB_CALL libusb_get_device_speed(libusb_device *dev); -int LIBUSB_CALL libusb_get_max_packet_size(libusb_device *dev, - unsigned char endpoint); -int LIBUSB_CALL libusb_get_max_iso_packet_size(libusb_device *dev, - unsigned char endpoint); - -int LIBUSB_CALL libusb_open(libusb_device *dev, libusb_device_handle **handle); -void LIBUSB_CALL libusb_close(libusb_device_handle *dev_handle); -libusb_device * LIBUSB_CALL libusb_get_device(libusb_device_handle *dev_handle); - -int LIBUSB_CALL libusb_set_configuration(libusb_device_handle *dev, - int configuration); -int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev, - int interface_number); - -libusb_device_handle * LIBUSB_CALL libusb_open_device_with_vid_pid( - libusb_context *ctx, uint16_t vendor_id, uint16_t product_id); - -int LIBUSB_CALL libusb_set_interface_alt_setting(libusb_device_handle *dev, - int interface_number, int alternate_setting); -int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev, - unsigned char endpoint); -int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev); - -int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev, - int interface_number); -int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev, - int interface_number); - -/* async I/O */ - -/** \ingroup asyncio - * Get the data section of a control transfer. This convenience function is here - * to remind you that the data does not start until 8 bytes into the actual - * buffer, as the setup packet comes first. - * - * Calling this function only makes sense from a transfer callback function, - * or situations where you have already allocated a suitably sized buffer at - * transfer->buffer. - * - * \param transfer a transfer - * \returns pointer to the first byte of the data section - */ -static inline unsigned char *libusb_control_transfer_get_data( - struct libusb_transfer *transfer) -{ - return transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; -} - -/** \ingroup asyncio - * Get the control setup packet of a control transfer. This convenience - * function is here to remind you that the control setup occupies the first - * 8 bytes of the transfer data buffer. - * - * Calling this function only makes sense from a transfer callback function, - * or situations where you have already allocated a suitably sized buffer at - * transfer->buffer. - * - * \param transfer a transfer - * \returns a casted pointer to the start of the transfer data buffer - */ -static inline struct libusb_control_setup *libusb_control_transfer_get_setup( - struct libusb_transfer *transfer) -{ - return (struct libusb_control_setup *) transfer->buffer; -} - -/** \ingroup asyncio - * Helper function to populate the setup packet (first 8 bytes of the data - * buffer) for a control transfer. The wIndex, wValue and wLength values should - * be given in host-endian byte order. - * - * \param buffer buffer to output the setup packet into - * \param bmRequestType see the - * \ref libusb_control_setup::bmRequestType "bmRequestType" field of - * \ref libusb_control_setup - * \param bRequest see the - * \ref libusb_control_setup::bRequest "bRequest" field of - * \ref libusb_control_setup - * \param wValue see the - * \ref libusb_control_setup::wValue "wValue" field of - * \ref libusb_control_setup - * \param wIndex see the - * \ref libusb_control_setup::wIndex "wIndex" field of - * \ref libusb_control_setup - * \param wLength see the - * \ref libusb_control_setup::wLength "wLength" field of - * \ref libusb_control_setup - */ -static inline void libusb_fill_control_setup(unsigned char *buffer, - uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - uint16_t wLength) -{ - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; - setup->bmRequestType = bmRequestType; - setup->bRequest = bRequest; - setup->wValue = libusb_cpu_to_le16(wValue); - setup->wIndex = libusb_cpu_to_le16(wIndex); - setup->wLength = libusb_cpu_to_le16(wLength); -} - -struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(int iso_packets); -int LIBUSB_CALL libusb_submit_transfer(struct libusb_transfer *transfer); -int LIBUSB_CALL libusb_cancel_transfer(struct libusb_transfer *transfer); -void LIBUSB_CALL libusb_free_transfer(struct libusb_transfer *transfer); - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a control transfer. - * - * If you pass a transfer buffer to this function, the first 8 bytes will - * be interpreted as a control setup packet, and the wLength field will be - * used to automatically populate the \ref libusb_transfer::length "length" - * field of the transfer. Therefore the recommended approach is: - * -# Allocate a suitably sized data buffer (including space for control setup) - * -# Call libusb_fill_control_setup() - * -# If this is a host-to-device transfer with a data stage, put the data - * in place after the setup packet - * -# Call this function - * -# Call libusb_submit_transfer() - * - * It is also legal to pass a NULL buffer to this function, in which case this - * function will not attempt to populate the length field. Remember that you - * must then populate the buffer and length fields later. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param buffer data buffer. If provided, this function will interpret the - * first 8 bytes as a setup packet and infer the transfer length from that. - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_control_transfer( - struct libusb_transfer *transfer, libusb_device_handle *dev_handle, - unsigned char *buffer, libusb_transfer_cb_fn callback, void *user_data, - unsigned int timeout) -{ - struct libusb_control_setup *setup = (struct libusb_control_setup *) buffer; - transfer->dev_handle = dev_handle; - transfer->endpoint = 0; - transfer->type = LIBUSB_TRANSFER_TYPE_CONTROL; - transfer->timeout = timeout; - transfer->buffer = buffer; - if (setup) - transfer->length = LIBUSB_CONTROL_SETUP_SIZE - + libusb_le16_to_cpu(setup->wLength); - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for a bulk transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_bulk_transfer(struct libusb_transfer *transfer, - libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *buffer, int length, libusb_transfer_cb_fn callback, - void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_BULK; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an interrupt transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_interrupt_transfer( - struct libusb_transfer *transfer, libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *buffer, int length, - libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Helper function to populate the required \ref libusb_transfer fields - * for an isochronous transfer. - * - * \param transfer the transfer to populate - * \param dev_handle handle of the device that will handle the transfer - * \param endpoint address of the endpoint where this transfer will be sent - * \param buffer data buffer - * \param length length of data buffer - * \param num_iso_packets the number of isochronous packets - * \param callback callback function to be invoked on transfer completion - * \param user_data user data to pass to callback function - * \param timeout timeout for the transfer in milliseconds - */ -static inline void libusb_fill_iso_transfer(struct libusb_transfer *transfer, - libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *buffer, int length, int num_iso_packets, - libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout) -{ - transfer->dev_handle = dev_handle; - transfer->endpoint = endpoint; - transfer->type = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS; - transfer->timeout = timeout; - transfer->buffer = buffer; - transfer->length = length; - transfer->num_iso_packets = num_iso_packets; - transfer->user_data = user_data; - transfer->callback = callback; -} - -/** \ingroup asyncio - * Convenience function to set the length of all packets in an isochronous - * transfer, based on the num_iso_packets field in the transfer structure. - * - * \param transfer a transfer - * \param length the length to set in each isochronous packet descriptor - * \see libusb_get_max_packet_size() - */ -static inline void libusb_set_iso_packet_lengths( - struct libusb_transfer *transfer, unsigned int length) -{ - int i; - for (i = 0; i < transfer->num_iso_packets; i++) - transfer->iso_packet_desc[i].length = length; -} - -/** \ingroup asyncio - * Convenience function to locate the position of an isochronous packet - * within the buffer of an isochronous transfer. - * - * This is a thorough function which loops through all preceding packets, - * accumulating their lengths to find the position of the specified packet. - * Typically you will assign equal lengths to each packet in the transfer, - * and hence the above method is sub-optimal. You may wish to use - * libusb_get_iso_packet_buffer_simple() instead. - * - * \param transfer a transfer - * \param packet the packet to return the address of - * \returns the base address of the packet buffer inside the transfer buffer, - * or NULL if the packet does not exist. - * \see libusb_get_iso_packet_buffer_simple() - */ -static inline unsigned char *libusb_get_iso_packet_buffer( - struct libusb_transfer *transfer, unsigned int packet) -{ - int i; - size_t offset = 0; - int _packet; - - /* oops..slight bug in the API. packet is an unsigned int, but we use - * signed integers almost everywhere else. range-check and convert to - * signed to avoid compiler warnings. FIXME for libusb-2. */ - if (packet > INT_MAX) - return NULL; - _packet = packet; - - if (_packet >= transfer->num_iso_packets) - return NULL; - - for (i = 0; i < _packet; i++) - offset += transfer->iso_packet_desc[i].length; - - return transfer->buffer + offset; -} - -/** \ingroup asyncio - * Convenience function to locate the position of an isochronous packet - * within the buffer of an isochronous transfer, for transfers where each - * packet is of identical size. - * - * This function relies on the assumption that every packet within the transfer - * is of identical size to the first packet. Calculating the location of - * the packet buffer is then just a simple calculation: - * <tt>buffer + (packet_size * packet)</tt> - * - * Do not use this function on transfers other than those that have identical - * packet lengths for each packet. - * - * \param transfer a transfer - * \param packet the packet to return the address of - * \returns the base address of the packet buffer inside the transfer buffer, - * or NULL if the packet does not exist. - * \see libusb_get_iso_packet_buffer() - */ -static inline unsigned char *libusb_get_iso_packet_buffer_simple( - struct libusb_transfer *transfer, unsigned int packet) -{ - int _packet; - - /* oops..slight bug in the API. packet is an unsigned int, but we use - * signed integers almost everywhere else. range-check and convert to - * signed to avoid compiler warnings. FIXME for libusb-2. */ - if (packet > INT_MAX) - return NULL; - _packet = packet; - - if (_packet >= transfer->num_iso_packets) - return NULL; - - return transfer->buffer + (transfer->iso_packet_desc[0].length * _packet); -} - -/* sync I/O */ - -int LIBUSB_CALL libusb_control_transfer(libusb_device_handle *dev_handle, - uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout); - -int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - -int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, - int *actual_length, unsigned int timeout); - -/** \ingroup desc - * Retrieve a descriptor from the default control pipe. - * This is a convenience function which formulates the appropriate control - * message to retrieve the descriptor. - * - * \param dev a device handle - * \param desc_type the descriptor type, see \ref libusb_descriptor_type - * \param desc_index the index of the descriptor to retrieve - * \param data output buffer for descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - */ -static inline int libusb_get_descriptor(libusb_device_handle *dev, - uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length) -{ - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, - (uint16_t) length, 1000); -} - -/** \ingroup desc - * Retrieve a descriptor from a device. - * This is a convenience function which formulates the appropriate control - * message to retrieve the descriptor. The string returned is Unicode, as - * detailed in the USB specifications. - * - * \param dev a device handle - * \param desc_index the index of the descriptor to retrieve - * \param langid the language ID for the string descriptor - * \param data output buffer for descriptor - * \param length size of data buffer - * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure - * \see libusb_get_string_descriptor_ascii() - */ -static inline int libusb_get_string_descriptor(libusb_device_handle *dev, - uint8_t desc_index, uint16_t langid, unsigned char *data, int length) -{ - return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, - LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, - langid, data, (uint16_t) length, 1000); -} - -int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev, - uint8_t desc_index, unsigned char *data, int length); - -/* polling and timeouts */ - -int LIBUSB_CALL libusb_try_lock_events(libusb_context *ctx); -void LIBUSB_CALL libusb_lock_events(libusb_context *ctx); -void LIBUSB_CALL libusb_unlock_events(libusb_context *ctx); -int LIBUSB_CALL libusb_event_handling_ok(libusb_context *ctx); -int LIBUSB_CALL libusb_event_handler_active(libusb_context *ctx); -void LIBUSB_CALL libusb_lock_event_waiters(libusb_context *ctx); -void LIBUSB_CALL libusb_unlock_event_waiters(libusb_context *ctx); -int LIBUSB_CALL libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); - -int LIBUSB_CALL libusb_handle_events_timeout(libusb_context *ctx, - struct timeval *tv); -int LIBUSB_CALL libusb_handle_events_timeout_completed(libusb_context *ctx, - struct timeval *tv, int *completed); -int LIBUSB_CALL libusb_handle_events(libusb_context *ctx); -int LIBUSB_CALL libusb_handle_events_completed(libusb_context *ctx, int *completed); -int LIBUSB_CALL libusb_handle_events_locked(libusb_context *ctx, - struct timeval *tv); -int LIBUSB_CALL libusb_pollfds_handle_timeouts(libusb_context *ctx); -int LIBUSB_CALL libusb_get_next_timeout(libusb_context *ctx, - struct timeval *tv); - -/** \ingroup poll - * File descriptor for polling - */ -struct libusb_pollfd { - /** Numeric file descriptor */ - int fd; - - /** Event flags to poll for from <poll.h>. POLLIN indicates that you - * should monitor this file descriptor for becoming ready to read from, - * and POLLOUT indicates that you should monitor this file descriptor for - * nonblocking write readiness. */ - short events; -}; - -/** \ingroup poll - * Callback function, invoked when a new file descriptor should be added - * to the set of file descriptors monitored for events. - * \param fd the new file descriptor - * \param events events to monitor for, see \ref libusb_pollfd for a - * description - * \param user_data User data pointer specified in - * libusb_set_pollfd_notifiers() call - * \see libusb_set_pollfd_notifiers() - */ -typedef void (LIBUSB_CALL *libusb_pollfd_added_cb)(int fd, short events, - void *user_data); - -/** \ingroup poll - * Callback function, invoked when a file descriptor should be removed from - * the set of file descriptors being monitored for events. After returning - * from this callback, do not use that file descriptor again. - * \param fd the file descriptor to stop monitoring - * \param user_data User data pointer specified in - * libusb_set_pollfd_notifiers() call - * \see libusb_set_pollfd_notifiers() - */ -typedef void (LIBUSB_CALL *libusb_pollfd_removed_cb)(int fd, void *user_data); - -const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds( - libusb_context *ctx); -void LIBUSB_CALL libusb_set_pollfd_notifiers(libusb_context *ctx, - libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, - void *user_data); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/third_party/libusb/libusb/libusbi.h b/third_party/libusb/libusb/libusbi.h deleted file mode 100644 index fe9b7af..0000000 --- a/third_party/libusb/libusb/libusbi.h +++ /dev/null @@ -1,889 +0,0 @@ -/* - * Internal header for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSBI_H -#define LIBUSBI_H - -#include <config.h> - -#include <stddef.h> -#include <stdint.h> -#include <time.h> -#ifdef HAVE_POLL_H -#include <poll.h> -#endif - -#include <libusb.h> - -/* Inside the libusb code, mark all public functions as follows: - * return_type API_EXPORTED function_name(params) { ... } - * But if the function returns a pointer, mark it as follows: - * DEFAULT_VISIBILITY return_type * LIBUSB_CALL function_name(params) { ... } - * In the libusb public header, mark all declarations as: - * return_type LIBUSB_CALL function_name(params); - */ -#define API_EXPORTED LIBUSB_CALL DEFAULT_VISIBILITY - -#define DEVICE_DESC_LENGTH 18 - -#define USB_MAXENDPOINTS 32 -#define USB_MAXINTERFACES 32 -#define USB_MAXCONFIG 8 - -struct list_head { - struct list_head *prev, *next; -}; - -/* Get an entry from the list - * ptr - the address of this list_head element in "type" - * type - the data type that contains "member" - * member - the list_head element in "type" - */ -#define list_entry(ptr, type, member) \ - ((type *)((uintptr_t)(ptr) - (uintptr_t)(&((type *)0L)->member))) - -/* Get each entry from a list - * pos - A structure pointer has a "member" element - * head - list head - * member - the list_head element in "pos" - * type - the type of the first parameter - */ -#define list_for_each_entry(pos, head, member, type) \ - for (pos = list_entry((head)->next, type, member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, type, member)) - -#define list_for_each_entry_safe(pos, n, head, member, type) \ - for (pos = list_entry((head)->next, type, member), \ - n = list_entry(pos->member.next, type, member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, type, member)) - -#define list_empty(entry) ((entry)->next == (entry)) - -static inline void list_init(struct list_head *entry) -{ - entry->prev = entry->next = entry; -} - -static inline void list_add(struct list_head *entry, struct list_head *head) -{ - entry->next = head->next; - entry->prev = head; - - head->next->prev = entry; - head->next = entry; -} - -static inline void list_add_tail(struct list_head *entry, - struct list_head *head) -{ - entry->next = head; - entry->prev = head->prev; - - head->prev->next = entry; - head->prev = entry; -} - -static inline void list_del(struct list_head *entry) -{ - entry->next->prev = entry->prev; - entry->prev->next = entry->next; -} - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *mptr = (ptr); \ - (type *)( (char *)mptr - offsetof(type,member) );}) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0) - -enum usbi_log_level { - LOG_LEVEL_DEBUG, - LOG_LEVEL_INFO, - LOG_LEVEL_WARNING, - LOG_LEVEL_ERROR, -}; - -void usbi_log(struct libusb_context *ctx, enum usbi_log_level level, - const char *function, const char *format, ...); - -#if !defined(_MSC_VER) || _MSC_VER > 1200 - -#ifdef ENABLE_LOGGING -#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__) -#else -#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0) -#endif - -#ifdef ENABLE_DEBUG_LOGGING -#define usbi_dbg(...) _usbi_log(NULL, LOG_LEVEL_DEBUG, __VA_ARGS__) -#else -#define usbi_dbg(...) do {} while(0) -#endif - -#define usbi_info(ctx, ...) _usbi_log(ctx, LOG_LEVEL_INFO, __VA_ARGS__) -#define usbi_warn(ctx, ...) _usbi_log(ctx, LOG_LEVEL_WARNING, __VA_ARGS__) -#define usbi_err(ctx, ...) _usbi_log(ctx, LOG_LEVEL_ERROR, __VA_ARGS__) - -#else /* !defined(_MSC_VER) || _MSC_VER > 1200 */ - -void usbi_log_v(struct libusb_context *ctx, enum usbi_log_level level, - const char *function, const char *format, va_list args); - -#ifdef ENABLE_LOGGING -#define LOG_BODY(ctxt, level) \ -{ \ - va_list args; \ - va_start (args, format); \ - usbi_log_v(ctxt, level, "", format, args); \ - va_end(args); \ -} -#else -#define LOG_BODY(ctxt, level) do { (void)(ctxt); } while(0) -#endif - -static inline void usbi_info(struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LOG_LEVEL_INFO) -static inline void usbi_warn(struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LOG_LEVEL_WARNING) -static inline void usbi_err( struct libusb_context *ctx, const char *format, - ...) - LOG_BODY(ctx,LOG_LEVEL_ERROR) - -static inline void usbi_dbg(const char *format, ...) -#ifdef ENABLE_DEBUG_LOGGING - LOG_BODY(NULL,LOG_LEVEL_DEBUG) -#else -{ } -#endif - -#endif /* !defined(_MSC_VER) || _MSC_VER > 1200 */ - -#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context -#define DEVICE_CTX(dev) ((dev)->ctx) -#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) -#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) -#define ITRANSFER_CTX(transfer) \ - (TRANSFER_CTX(USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) - -/* Internal abstractions for thread synchronization and poll */ -#if defined(THREADS_POSIX) -#include <os/threads_posix.h> -#elif defined(OS_WINDOWS) -#include <os/threads_windows.h> -#endif - -#if defined(OS_LINUX) || defined(OS_DARWIN) -#include <unistd.h> -#include <os/poll_posix.h> -#elif defined(OS_WINDOWS) -#include <os/poll_windows.h> -#endif - -extern struct libusb_context *usbi_default_context; - -struct libusb_context { - int debug; - int debug_fixed; - - /* internal control pipe, used for interrupting event handling when - * something needs to modify poll fds. */ - int ctrl_pipe[2]; - - struct list_head usb_devs; - usbi_mutex_t usb_devs_lock; - - /* A list of open handles. Backends are free to traverse this if required. - */ - struct list_head open_devs; - usbi_mutex_t open_devs_lock; - - /* this is a list of in-flight transfer handles, sorted by timeout - * expiration. URBs to timeout the soonest are placed at the beginning of - * the list, URBs that will time out later are placed after, and urbs with - * infinite timeout are always placed at the very end. */ - struct list_head flying_transfers; - usbi_mutex_t flying_transfers_lock; - - /* list of poll fds */ - struct list_head pollfds; - usbi_mutex_t pollfds_lock; - - /* a counter that is set when we want to interrupt event handling, in order - * to modify the poll fd set. and a lock to protect it. */ - unsigned int pollfd_modify; - usbi_mutex_t pollfd_modify_lock; - - /* user callbacks for pollfd changes */ - libusb_pollfd_added_cb fd_added_cb; - libusb_pollfd_removed_cb fd_removed_cb; - void *fd_cb_user_data; - - /* ensures that only one thread is handling events at any one time */ - usbi_mutex_t events_lock; - - /* used to see if there is an active thread doing event handling */ - int event_handler_active; - - /* used to wait for event completion in threads other than the one that is - * event handling */ - usbi_mutex_t event_waiters_lock; - usbi_cond_t event_waiters_cond; - -#ifdef USBI_TIMERFD_AVAILABLE - /* used for timeout handling, if supported by OS. - * this timerfd is maintained to trigger on the next pending timeout */ - int timerfd; -#endif -}; - -#ifdef USBI_TIMERFD_AVAILABLE -#define usbi_using_timerfd(ctx) ((ctx)->timerfd >= 0) -#else -#define usbi_using_timerfd(ctx) (0) -#endif - -struct libusb_device { - /* lock protects refcnt, everything else is finalized at initialization - * time */ - usbi_mutex_t lock; - int refcnt; - - struct libusb_context *ctx; - - uint8_t bus_number; - uint8_t device_address; - uint8_t num_configurations; - enum libusb_speed speed; - - struct list_head list; - unsigned long session_data; - unsigned char os_priv[0]; -}; - -struct libusb_device_handle { - /* lock protects claimed_interfaces */ - usbi_mutex_t lock; - unsigned long claimed_interfaces; - - struct list_head list; - struct libusb_device *dev; - unsigned char os_priv[0]; -}; - -enum { - USBI_CLOCK_MONOTONIC, - USBI_CLOCK_REALTIME -}; - -/* in-memory transfer layout: - * - * 1. struct usbi_transfer - * 2. struct libusb_transfer (which includes iso packets) [variable size] - * 3. os private data [variable size] - * - * from a libusb_transfer, you can get the usbi_transfer by rewinding the - * appropriate number of bytes. - * the usbi_transfer includes the number of allocated packets, so you can - * determine the size of the transfer and hence the start and length of the - * OS-private data. - */ - -struct usbi_transfer { - int num_iso_packets; - struct list_head list; - struct timeval timeout; - int transferred; - uint8_t flags; - - /* this lock is held during libusb_submit_transfer() and - * libusb_cancel_transfer() (allowing the OS backend to prevent duplicate - * cancellation, submission-during-cancellation, etc). the OS backend - * should also take this lock in the handle_events path, to prevent the user - * cancelling the transfer from another thread while you are processing - * its completion (presumably there would be races within your OS backend - * if this were possible). */ - usbi_mutex_t lock; -}; - -enum usbi_transfer_flags { - /* The transfer has timed out */ - USBI_TRANSFER_TIMED_OUT = 1 << 0, - - /* Set by backend submit_transfer() if the OS handles timeout */ - USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 1, - - /* Cancellation was requested via libusb_cancel_transfer() */ - USBI_TRANSFER_CANCELLING = 1 << 2, - - /* Operation on the transfer failed because the device disappeared */ - USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 3, -}; - -#define USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer) \ - ((struct libusb_transfer *)(((unsigned char *)(transfer)) \ - + sizeof(struct usbi_transfer))) -#define LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer) \ - ((struct usbi_transfer *)(((unsigned char *)(transfer)) \ - - sizeof(struct usbi_transfer))) - -static inline void *usbi_transfer_get_os_priv(struct usbi_transfer *transfer) -{ - return ((unsigned char *)transfer) + sizeof(struct usbi_transfer) - + sizeof(struct libusb_transfer) - + (transfer->num_iso_packets - * sizeof(struct libusb_iso_packet_descriptor)); -} - -/* bus structures */ - -/* All standard descriptors have these 2 fields in common */ -struct usb_descriptor_header { - uint8_t bLength; - uint8_t bDescriptorType; -}; - -/* shared data and functions */ - -int usbi_io_init(struct libusb_context *ctx); -void usbi_io_exit(struct libusb_context *ctx); - -struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, - unsigned long session_id); -struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, - unsigned long session_id); -int usbi_sanitize_device(struct libusb_device *dev); -void usbi_handle_disconnect(struct libusb_device_handle *handle); - -int usbi_handle_transfer_completion(struct usbi_transfer *itransfer, - enum libusb_transfer_status status); -int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer); - -int usbi_parse_descriptor(unsigned char *source, const char *descriptor, - void *dest, int host_endian); -int usbi_get_config_index_by_value(struct libusb_device *dev, - uint8_t bConfigurationValue, int *idx); - -/* polling */ - -struct usbi_pollfd { - /* must come first */ - struct libusb_pollfd pollfd; - - struct list_head list; -}; - -int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); -void usbi_remove_pollfd(struct libusb_context *ctx, int fd); -void usbi_fd_notification(struct libusb_context *ctx); - -/* device discovery */ - -/* we traverse usbfs without knowing how many devices we are going to find. - * so we create this discovered_devs model which is similar to a linked-list - * which grows when required. it can be freed once discovery has completed, - * eliminating the need for a list node in the libusb_device structure - * itself. */ -struct discovered_devs { - size_t len; - size_t capacity; - struct libusb_device *devices[0]; -}; - -struct discovered_devs *discovered_devs_append( - struct discovered_devs *discdevs, struct libusb_device *dev); - -/* OS abstraction */ - -/* This is the interface that OS backends need to implement. - * All fields are mandatory, except ones explicitly noted as optional. */ -struct usbi_os_backend { - /* A human-readable name for your backend, e.g. "Linux usbfs" */ - const char *name; - - /* Perform initialization of your backend. You might use this function - * to determine specific capabilities of the system, allocate required - * data structures for later, etc. - * - * This function is called when a libusb user initializes the library - * prior to use. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*init)(struct libusb_context *ctx); - - /* Deinitialization. Optional. This function should destroy anything - * that was set up by init. - * - * This function is called when the user deinitializes the library. - */ - void (*exit)(void); - - /* Enumerate all the USB devices on the system, returning them in a list - * of discovered devices. - * - * Your implementation should enumerate all devices on the system, - * regardless of whether they have been seen before or not. - * - * When you have found a device, compute a session ID for it. The session - * ID should uniquely represent that particular device for that particular - * connection session since boot (i.e. if you disconnect and reconnect a - * device immediately after, it should be assigned a different session ID). - * If your OS cannot provide a unique session ID as described above, - * presenting a session ID of (bus_number << 8 | device_address) should - * be sufficient. Bus numbers and device addresses wrap and get reused, - * but that is an unlikely case. - * - * After computing a session ID for a device, call - * usbi_get_device_by_session_id(). This function checks if libusb already - * knows about the device, and if so, it provides you with a libusb_device - * structure for it. - * - * If usbi_get_device_by_session_id() returns NULL, it is time to allocate - * a new device structure for the device. Call usbi_alloc_device() to - * obtain a new libusb_device structure with reference count 1. Populate - * the bus_number and device_address attributes of the new device, and - * perform any other internal backend initialization you need to do. At - * this point, you should be ready to provide device descriptors and so - * on through the get_*_descriptor functions. Finally, call - * usbi_sanitize_device() to perform some final sanity checks on the - * device. Assuming all of the above succeeded, we can now continue. - * If any of the above failed, remember to unreference the device that - * was returned by usbi_alloc_device(). - * - * At this stage we have a populated libusb_device structure (either one - * that was found earlier, or one that we have just allocated and - * populated). This can now be added to the discovered devices list - * using discovered_devs_append(). Note that discovered_devs_append() - * may reallocate the list, returning a new location for it, and also - * note that reallocation can fail. Your backend should handle these - * error conditions appropriately. - * - * This function should not generate any bus I/O and should not block. - * If I/O is required (e.g. reading the active configuration value), it is - * OK to ignore these suggestions :) - * - * This function is executed when the user wishes to retrieve a list - * of USB devices connected to the system. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*get_device_list)(struct libusb_context *ctx, - struct discovered_devs **discdevs); - - /* Open a device for I/O and other USB operations. The device handle - * is preallocated for you, you can retrieve the device in question - * through handle->dev. - * - * Your backend should allocate any internal resources required for I/O - * and other operations so that those operations can happen (hopefully) - * without hiccup. This is also a good place to inform libusb that it - * should monitor certain file descriptors related to this device - - * see the usbi_add_pollfd() function. - * - * This function should not generate any bus I/O and should not block. - * - * This function is called when the user attempts to obtain a device - * handle for a device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_ACCESS if the user has insufficient permissions - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since - * discovery - * - another LIBUSB_ERROR code on other failure - * - * Do not worry about freeing the handle on failed open, the upper layers - * do this for you. - */ - int (*open)(struct libusb_device_handle *handle); - - /* Close a device such that the handle cannot be used again. Your backend - * should destroy any resources that were allocated in the open path. - * This may also be a good place to call usbi_remove_pollfd() to inform - * libusb of any file descriptors associated with this device that should - * no longer be monitored. - * - * This function is called when the user closes a device handle. - */ - void (*close)(struct libusb_device_handle *handle); - - /* Retrieve the device descriptor from a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. Alternatively, you may be able - * to retrieve it from a kernel interface (some Linux setups can do this) - * still without generating bus I/O. - * - * This function is expected to write DEVICE_DESC_LENGTH (18) bytes into - * buffer, which is guaranteed to be big enough. - * - * This function is called when sanity-checking a device before adding - * it to the list of discovered devices, and also when the user requests - * to read the device descriptor. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return 0 on success or a LIBUSB_ERROR code on failure. - */ - int (*get_device_descriptor)(struct libusb_device *device, - unsigned char *buffer, int *host_endian); - - /* Get the ACTIVE configuration descriptor for a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. You may also have to keep track - * of which configuration is active when the user changes it. - * - * This function is expected to write len bytes of data into buffer, which - * is guaranteed to be big enough. If you can only do a partial write, - * return an error code. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state - * - another LIBUSB_ERROR code on other failure - */ - int (*get_active_config_descriptor)(struct libusb_device *device, - unsigned char *buffer, size_t len, int *host_endian); - - /* Get a specific configuration descriptor for a device. - * - * The descriptor should be retrieved from memory, NOT via bus I/O to the - * device. This means that you may have to cache it in a private structure - * during get_device_list enumeration. - * - * The requested descriptor is expressed as a zero-based index (i.e. 0 - * indicates that we are requesting the first descriptor). The index does - * not (necessarily) equal the bConfigurationValue of the configuration - * being requested. - * - * This function is expected to write len bytes of data into buffer, which - * is guaranteed to be big enough. If you can only do a partial write, - * return an error code. - * - * This function is expected to return the descriptor in bus-endian format - * (LE). If it returns the multi-byte values in host-endian format, - * set the host_endian output parameter to "1". - * - * Return 0 on success or a LIBUSB_ERROR code on failure. - */ - int (*get_config_descriptor)(struct libusb_device *device, - uint8_t config_index, unsigned char *buffer, size_t len, - int *host_endian); - - /* Get the bConfigurationValue for the active configuration for a device. - * Optional. This should only be implemented if you can retrieve it from - * cache (don't generate I/O). - * - * If you cannot retrieve this from cache, either do not implement this - * function, or return LIBUSB_ERROR_NOT_SUPPORTED. This will cause - * libusb to retrieve the information through a standard control transfer. - * - * This function must be non-blocking. - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - LIBUSB_ERROR_NOT_SUPPORTED if the value cannot be retrieved without - * blocking - * - another LIBUSB_ERROR code on other failure. - */ - int (*get_configuration)(struct libusb_device_handle *handle, int *config); - - /* Set the active configuration for a device. - * - * A configuration value of -1 should put the device in unconfigured state. - * - * This function can block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the configuration does not exist - * - LIBUSB_ERROR_BUSY if interfaces are currently claimed (and hence - * configuration cannot be changed) - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure. - */ - int (*set_configuration)(struct libusb_device_handle *handle, int config); - - /* Claim an interface. When claimed, the application can then perform - * I/O to an interface's endpoints. - * - * This function should not generate any bus I/O and should not block. - * Interface claiming is a logical operation that simply ensures that - * no other drivers/applications are using the interface, and after - * claiming, no other drivers/applicatiosn can use the interface because - * we now "own" it. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist - * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*claim_interface)(struct libusb_device_handle *handle, int interface_number); - - /* Release a previously claimed interface. - * - * This function should also generate a SET_INTERFACE control request, - * resetting the alternate setting of that interface to 0. It's OK for - * this function to block as a result. - * - * You will only ever be asked to release an interface which was - * successfully claimed earlier. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*release_interface)(struct libusb_device_handle *handle, int interface_number); - - /* Set the alternate setting for an interface. - * - * You will only ever be asked to set the alternate setting for an - * interface which was successfully claimed earlier. - * - * It's OK for this function to block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the alternate setting does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*set_interface_altsetting)(struct libusb_device_handle *handle, - int interface_number, int altsetting); - - /* Clear a halt/stall condition on an endpoint. - * - * It's OK for this function to block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if the endpoint does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*clear_halt)(struct libusb_device_handle *handle, - unsigned char endpoint); - - /* Perform a USB port reset to reinitialize a device. - * - * If possible, the handle should still be usable after the reset - * completes, assuming that the device descriptors did not change during - * reset and all previous interface state can be restored. - * - * If something changes, or you cannot easily locate/verify the resetted - * device, return LIBUSB_ERROR_NOT_FOUND. This prompts the application - * to close the old handle and re-enumerate the device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if re-enumeration is required, or if the device - * has been disconnected since it was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*reset_device)(struct libusb_device_handle *handle); - - /* Determine if a kernel driver is active on an interface. Optional. - * - * The presence of a kernel driver on an interface indicates that any - * calls to claim_interface would fail with the LIBUSB_ERROR_BUSY code. - * - * Return: - * - 0 if no driver is active - * - 1 if a driver is active - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*kernel_driver_active)(struct libusb_device_handle *handle, - int interface_number); - - /* Detach a kernel driver from an interface. Optional. - * - * After detaching a kernel driver, the interface should be available - * for claim. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - another LIBUSB_ERROR code on other failure - */ - int (*detach_kernel_driver)(struct libusb_device_handle *handle, - int interface_number); - - /* Attach a kernel driver to an interface. Optional. - * - * Reattach a kernel driver to the device. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NOT_FOUND if no kernel driver was active - * - LIBUSB_ERROR_INVALID_PARAM if the interface does not exist - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it - * was opened - * - LIBUSB_ERROR_BUSY if a program or driver has claimed the interface, - * preventing reattachment - * - another LIBUSB_ERROR code on other failure - */ - int (*attach_kernel_driver)(struct libusb_device_handle *handle, - int interface_number); - - /* Destroy a device. Optional. - * - * This function is called when the last reference to a device is - * destroyed. It should free any resources allocated in the get_device_list - * path. - */ - void (*destroy_device)(struct libusb_device *dev); - - /* Submit a transfer. Your implementation should take the transfer, - * morph it into whatever form your platform requires, and submit it - * asynchronously. - * - * This function must not block. - * - * Return: - * - 0 on success - * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * - another LIBUSB_ERROR code on other failure - */ - int (*submit_transfer)(struct usbi_transfer *itransfer); - - /* Cancel a previously submitted transfer. - * - * This function must not block. The transfer cancellation must complete - * later, resulting in a call to usbi_handle_transfer_cancellation() - * from the context of handle_events. - */ - int (*cancel_transfer)(struct usbi_transfer *itransfer); - - /* Clear a transfer as if it has completed or cancelled, but do not - * report any completion/cancellation to the library. You should free - * all private data from the transfer as if you were just about to report - * completion or cancellation. - * - * This function might seem a bit out of place. It is used when libusb - * detects a disconnected device - it calls this function for all pending - * transfers before reporting completion (with the disconnect code) to - * the user. Maybe we can improve upon this internal interface in future. - */ - void (*clear_transfer_priv)(struct usbi_transfer *itransfer); - - /* Handle any pending events. This involves monitoring any active - * transfers and processing their completion or cancellation. - * - * The function is passed an array of pollfd structures (size nfds) - * as a result of the poll() system call. The num_ready parameter - * indicates the number of file descriptors that have reported events - * (i.e. the poll() return value). This should be enough information - * for you to determine which actions need to be taken on the currently - * active transfers. - * - * For any cancelled transfers, call usbi_handle_transfer_cancellation(). - * For completed transfers, call usbi_handle_transfer_completion(). - * For control/bulk/interrupt transfers, populate the "transferred" - * element of the appropriate usbi_transfer structure before calling the - * above functions. For isochronous transfers, populate the status and - * transferred fields of the iso packet descriptors of the transfer. - * - * This function should also be able to detect disconnection of the - * device, reporting that situation with usbi_handle_disconnect(). - * - * When processing an event related to a transfer, you probably want to - * take usbi_transfer.lock to prevent races. See the documentation for - * the usbi_transfer structure. - * - * Return 0 on success, or a LIBUSB_ERROR code on failure. - */ - int (*handle_events)(struct libusb_context *ctx, - struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready); - - /* Get time from specified clock. At least two clocks must be implemented - by the backend: USBI_CLOCK_REALTIME, and USBI_CLOCK_MONOTONIC. - - Description of clocks: - USBI_CLOCK_REALTIME : clock returns time since system epoch. - USBI_CLOCK_MONOTONIC: clock returns time since unspecified start - time (usually boot). - */ - int (*clock_gettime)(int clkid, struct timespec *tp); - -#ifdef USBI_TIMERFD_AVAILABLE - /* clock ID of the clock that should be used for timerfd */ - clockid_t (*get_timerfd_clockid)(void); -#endif - - /* Number of bytes to reserve for per-device private backend data. - * This private data area is accessible through the "os_priv" field of - * struct libusb_device. */ - size_t device_priv_size; - - /* Number of bytes to reserve for per-handle private backend data. - * This private data area is accessible through the "os_priv" field of - * struct libusb_device. */ - size_t device_handle_priv_size; - - /* Number of bytes to reserve for per-transfer private backend data. - * This private data area is accessible by calling - * usbi_transfer_get_os_priv() on the appropriate usbi_transfer instance. - */ - size_t transfer_priv_size; - - /* Mumber of additional bytes for os_priv for each iso packet. - * Can your backend use this? */ - /* FIXME: linux can't use this any more. if other OS's cannot either, - * then remove this */ - size_t add_iso_packet_size; -}; - -extern const struct usbi_os_backend * const usbi_backend; - -extern const struct usbi_os_backend linux_usbfs_backend; -extern const struct usbi_os_backend darwin_backend; -extern const struct usbi_os_backend windows_backend; - -#endif - diff --git a/third_party/libusb/libusb/os/darwin_usb.c b/third_party/libusb/libusb/os/darwin_usb.c deleted file mode 100644 index 0af4e3c..0000000 --- a/third_party/libusb/libusb/os/darwin_usb.c +++ /dev/null @@ -1,1751 +0,0 @@ -/* - * darwin backend for libusb 1.0 - * Copyright (C) 2008-2011 Nathan Hjelm <hjelmn@users.sourceforge.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <mach/clock.h> -#include <mach/clock_types.h> -#include <mach/mach_host.h> -#include <mach/mach_port.h> - -#include <AvailabilityMacros.h> -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - #include <objc/objc-auto.h> -#endif - -#include <IOKit/IOCFBundle.h> -#include <IOKit/usb/IOUSBLib.h> -#include <IOKit/IOCFPlugIn.h> - -#include "darwin_usb.h" - -/* async event thread */ -static pthread_mutex_t libusb_darwin_at_mutex; -static pthread_cond_t libusb_darwin_at_cond; - -static clock_serv_t clock_realtime; -static clock_serv_t clock_monotonic; - -static CFRunLoopRef libusb_darwin_acfl = NULL; /* async cf loop */ -static int initCount = 0; - -/* async event thread */ -static pthread_t libusb_darwin_at; - -static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian); -static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int darwin_reset_device(struct libusb_device_handle *dev_handle); -static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0); - -static const char *darwin_error_str (int result) { - switch (result) { - case kIOReturnSuccess: - return "no error"; - case kIOReturnNotOpen: - return "device not opened for exclusive access"; - case kIOReturnNoDevice: - return "no connection to an IOService"; - case kIOUSBNoAsyncPortErr: - return "no async port has been opened for interface"; - case kIOReturnExclusiveAccess: - return "another process has device opened for exclusive access"; - case kIOUSBPipeStalled: - return "pipe is stalled"; - case kIOReturnError: - return "could not establish a connection to the Darwin kernel"; - case kIOUSBTransactionTimeout: - return "transaction timed out"; - case kIOReturnBadArgument: - return "invalid argument"; - case kIOReturnAborted: - return "transaction aborted"; - case kIOReturnNotResponding: - return "device not responding"; - case kIOReturnOverrun: - return "data overrun"; - case kIOReturnCannotWire: - return "physical memory can not be wired down"; - default: - return "unknown error"; - } -} - -static int darwin_to_libusb (int result) { - switch (result) { - case kIOReturnUnderrun: - case kIOReturnSuccess: - return LIBUSB_SUCCESS; - case kIOReturnNotOpen: - case kIOReturnNoDevice: - return LIBUSB_ERROR_NO_DEVICE; - case kIOReturnExclusiveAccess: - return LIBUSB_ERROR_ACCESS; - case kIOUSBPipeStalled: - return LIBUSB_ERROR_PIPE; - case kIOReturnBadArgument: - return LIBUSB_ERROR_INVALID_PARAM; - case kIOUSBTransactionTimeout: - return LIBUSB_ERROR_TIMEOUT; - case kIOReturnNotResponding: - case kIOReturnAborted: - case kIOReturnError: - case kIOUSBNoAsyncPortErr: - default: - return LIBUSB_ERROR_OTHER; - } -} - - -static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct darwin_interface *cInterface; - - int8_t i, iface; - - usbi_info (HANDLE_CTX(dev_handle), "converting ep address 0x%02x to pipeRef and interface", ep); - - for (iface = 0 ; iface < USB_MAXINTERFACES ; iface++) { - cInterface = &priv->interfaces[iface]; - - if (dev_handle->claimed_interfaces & (1 << iface)) { - for (i = 0 ; i < cInterface->num_endpoints ; i++) { - if (cInterface->endpoint_addrs[i] == ep) { - *pipep = i + 1; - *ifcp = iface; - usbi_info (HANDLE_CTX(dev_handle), "pipe %d on interface %d matches", *pipep, *ifcp); - return 0; - } - } - } - } - - /* No pipe found with the correct endpoint address */ - usbi_warn (HANDLE_CTX(dev_handle), "no pipeRef found with endpoint address 0x%02x.", ep); - - return -1; -} - -static int usb_setup_device_iterator (io_iterator_t *deviceIterator, long location) { - CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); - - if (!matchingDict) - return kIOReturnError; - - if (location) { - CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (propertyMatchDict) { - CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberLongType, &location); - - CFDictionarySetValue (propertyMatchDict, CFSTR(kUSBDevicePropertyLocationID), locationCF); - /* release our reference to the CFNumber (CFDictionarySetValue retains it) */ - CFRelease (locationCF); - - CFDictionarySetValue (matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict); - /* release out reference to the CFMutableDictionaryRef (CFDictionarySetValue retains it) */ - CFRelease (propertyMatchDict); - } - /* else we can still proceed as long as the caller accounts for the possibility of other devices in the iterator */ - } - - return IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, deviceIterator); -} - -static usb_device_t **usb_get_next_device (io_iterator_t deviceIterator, UInt32 *locationp) { - io_cf_plugin_ref_t *plugInInterface = NULL; - usb_device_t **device; - io_service_t usbDevice; - long result; - SInt32 score; - - if (!IOIteratorIsValid (deviceIterator)) - return NULL; - - - while ((usbDevice = IOIteratorNext(deviceIterator))) { - result = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, - &score); - - /* we are done with the usb_device_t */ - (void)IOObjectRelease(usbDevice); - if (kIOReturnSuccess == result && plugInInterface) - break; - - usbi_dbg ("libusb/darwin.c usb_get_next_device: could not set up plugin for service: %s\n", darwin_error_str (result)); - } - - if (!usbDevice) - return NULL; - - (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID), - (LPVOID)&device); - - (*plugInInterface)->Stop(plugInInterface); - IODestroyPlugInInterface (plugInInterface); - - /* get the location from the device */ - if (locationp) - (*(device))->GetLocationID(device, locationp); - - return device; -} - -static kern_return_t darwin_get_device (uint32_t dev_location, usb_device_t ***darwin_device) { - kern_return_t kresult; - UInt32 location; - io_iterator_t deviceIterator; - - kresult = usb_setup_device_iterator (&deviceIterator, dev_location); - if (kresult) - return kresult; - - /* This port of libusb uses locations to keep track of devices. */ - while ((*darwin_device = usb_get_next_device (deviceIterator, &location)) != NULL) { - if (location == dev_location) - break; - - (**darwin_device)->Release(*darwin_device); - } - - IOObjectRelease (deviceIterator); - - if (!(*darwin_device)) - return kIOReturnNoDevice; - - return kIOReturnSuccess; -} - - - -static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) { - struct libusb_context *ctx = (struct libusb_context *)ptr; - struct libusb_device_handle *handle; - struct darwin_device_priv *dpriv; - struct darwin_device_handle_priv *priv; - - io_service_t device; - long location; - bool locationValid; - CFTypeRef locationCF; - UInt32 message; - - usbi_info (ctx, "a device has been detached"); - - while ((device = IOIteratorNext (rem_devices)) != 0) { - /* get the location from the i/o registry */ - locationCF = IORegistryEntryCreateCFProperty (device, CFSTR(kUSBDevicePropertyLocationID), kCFAllocatorDefault, 0); - - IOObjectRelease (device); - - if (!locationCF) - continue; - - locationValid = CFGetTypeID(locationCF) == CFNumberGetTypeID() && - CFNumberGetValue(locationCF, kCFNumberLongType, &location); - - CFRelease (locationCF); - - if (!locationValid) - continue; - - usbi_mutex_lock(&ctx->open_devs_lock); - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - dpriv = (struct darwin_device_priv *)handle->dev->os_priv; - - /* the device may have been opened several times. write to each handle's event descriptor */ - if (dpriv->location == location && handle->os_priv) { - priv = (struct darwin_device_handle_priv *)handle->os_priv; - - message = MESSAGE_DEVICE_GONE; - write (priv->fds[1], &message, sizeof (message)); - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - } -} - -static void darwin_clear_iterator (io_iterator_t iter) { - io_service_t device; - - while ((device = IOIteratorNext (iter)) != 0) - IOObjectRelease (device); -} - -static void *event_thread_main (void *arg0) { - IOReturn kresult; - struct libusb_context *ctx = (struct libusb_context *)arg0; - CFRunLoopRef runloop; - - /* Tell the Objective-C garbage collector about this thread. - This is required because, unlike NSThreads, pthreads are - not automatically registered. Although we don't use - Objective-C, we use CoreFoundation, which does. */ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 - objc_registerThreadWithCollector(); -#endif - - /* hotplug (device removal) source */ - CFRunLoopSourceRef libusb_notification_cfsource; - io_notification_port_t libusb_notification_port; - io_iterator_t libusb_rem_device_iterator; - - usbi_info (ctx, "creating hotplug event source"); - - runloop = CFRunLoopGetCurrent (); - CFRetain (runloop); - - /* add the notification port to the run loop */ - libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault); - libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port); - CFRunLoopAddSource(CFRunLoopGetCurrent (), libusb_notification_cfsource, kCFRunLoopDefaultMode); - - /* create notifications for removed devices */ - kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification, - IOServiceMatching(kIOUSBDeviceClassName), - (IOServiceMatchingCallback)darwin_devices_detached, - (void *)ctx, &libusb_rem_device_iterator); - - if (kresult != kIOReturnSuccess) { - usbi_err (ctx, "could not add hotplug event source: %s", darwin_error_str (kresult)); - - pthread_exit (NULL); - } - - /* arm notifiers */ - darwin_clear_iterator (libusb_rem_device_iterator); - - usbi_info (ctx, "thread ready to receive events"); - - /* let the main thread know about the async runloop */ - libusb_darwin_acfl = CFRunLoopGetCurrent (); - - /* signal the main thread */ - pthread_mutex_lock (&libusb_darwin_at_mutex); - pthread_cond_signal (&libusb_darwin_at_cond); - pthread_mutex_unlock (&libusb_darwin_at_mutex); - - /* run the runloop */ - CFRunLoopRun(); - - usbi_info (ctx, "thread exiting"); - - /* delete notification port */ - IONotificationPortDestroy (libusb_notification_port); - IOObjectRelease (libusb_rem_device_iterator); - - CFRelease (runloop); - - libusb_darwin_acfl = NULL; - - pthread_exit (NULL); -} - -static int darwin_init(struct libusb_context *ctx) { - host_name_port_t host_self; - - if (!(initCount++)) { - /* create the clocks that will be used */ - - host_self = mach_host_self(); - host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime); - host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic); - mach_port_deallocate(mach_task_self(), host_self); - - pthread_mutex_init (&libusb_darwin_at_mutex, NULL); - pthread_cond_init (&libusb_darwin_at_cond, NULL); - - pthread_create (&libusb_darwin_at, NULL, event_thread_main, (void *)ctx); - - pthread_mutex_lock (&libusb_darwin_at_mutex); - while (!libusb_darwin_acfl) - pthread_cond_wait (&libusb_darwin_at_cond, &libusb_darwin_at_mutex); - pthread_mutex_unlock (&libusb_darwin_at_mutex); - } - - return 0; -} - -static void darwin_exit (void) { - if (!(--initCount)) { - mach_port_deallocate(mach_task_self(), clock_realtime); - mach_port_deallocate(mach_task_self(), clock_monotonic); - - /* stop the async runloop */ - CFRunLoopStop (libusb_darwin_acfl); - pthread_join (libusb_darwin_at, NULL); - } -} - -static int darwin_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - - /* return cached copy */ - memmove (buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); - - *host_endian = 0; - - return 0; -} - -static int get_configuration_index (struct libusb_device *dev, int config_value) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - UInt8 i, numConfig; - IOUSBConfigurationDescriptorPtr desc; - IOReturn kresult; - - /* is there a simpler way to determine the index? */ - kresult = (*(priv->device))->GetNumberOfConfigurations (priv->device, &numConfig); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - for (i = 0 ; i < numConfig ; i++) { - (*(priv->device))->GetConfigurationDescriptorPtr (priv->device, i, &desc); - - if (desc->bConfigurationValue == config_value) - return i; - } - - /* configuration not found */ - return LIBUSB_ERROR_OTHER; -} - -static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - int config_index; - - if (0 == priv->active_config) - return LIBUSB_ERROR_INVALID_PARAM; - - config_index = get_configuration_index (dev, priv->active_config); - if (config_index < 0) - return config_index; - - return darwin_get_config_descriptor (dev, config_index, buffer, len, host_endian); -} - -static int darwin_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - IOUSBConfigurationDescriptorPtr desc; - IOReturn kresult; - usb_device_t **device = NULL; - - if (!priv) - return LIBUSB_ERROR_OTHER; - - if (!priv->device) { - kresult = darwin_get_device (priv->location, &device); - if (kresult || !device) { - usbi_err (DEVICE_CTX (dev), "could not find device: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); - } - - /* don't have to open the device to get a config descriptor */ - } else - device = priv->device; - - kresult = (*device)->GetConfigurationDescriptorPtr (device, config_index, &desc); - if (kresult == kIOReturnSuccess) { - /* copy descriptor */ - if (libusb_le16_to_cpu(desc->wTotalLength) < len) - len = libusb_le16_to_cpu(desc->wTotalLength); - - memmove (buffer, desc, len); - - /* GetConfigurationDescriptorPtr returns the descriptor in USB bus order */ - *host_endian = 0; - } - - if (!priv->device) - (*device)->Release (device); - - return darwin_to_libusb (kresult); -} - -/* check whether the os has configured the device */ -static int darwin_check_configuration (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **darwin_device) { - struct darwin_device_priv *priv = (struct darwin_device_priv *)dev->os_priv; - - IOUSBConfigurationDescriptorPtr configDesc; - IOUSBFindInterfaceRequest request; - kern_return_t kresult; - io_iterator_t interface_iterator; - io_service_t firstInterface; - - if (priv->dev_descriptor.bNumConfigurations < 1) { - usbi_err (ctx, "device has no configurations"); - return LIBUSB_ERROR_OTHER; /* no configurations at this speed so we can't use it */ - } - - /* find the first configuration */ - kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc); - priv->first_config = (kIOReturnSuccess == kresult) ? configDesc->bConfigurationValue : 1; - - /* check if the device is already configured. there is probably a better way than iterating over the - to accomplish this (the trick is we need to avoid a call to GetConfigurations since buggy devices - might lock up on the device request) */ - - /* Setup the Interface Request */ - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); - if (kresult) - return darwin_to_libusb (kresult); - - /* iterate once */ - firstInterface = IOIteratorNext(interface_iterator); - - /* done with the interface iterator */ - IOObjectRelease(interface_iterator); - - if (firstInterface) { - IOObjectRelease (firstInterface); - - /* device is configured */ - if (priv->dev_descriptor.bNumConfigurations == 1) - /* to avoid problems with some devices get the configurations value from the configuration descriptor */ - priv->active_config = priv->first_config; - else - /* devices with more than one configuration should work with GetConfiguration */ - (*darwin_device)->GetConfiguration (darwin_device, &priv->active_config); - } else - /* not configured */ - priv->active_config = 0; - - usbi_info (ctx, "active config: %u, first config: %u", priv->active_config, priv->first_config); - - return 0; -} - -static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct libusb_device *dev, usb_device_t **device) { - struct darwin_device_priv *priv; - int retries = 5, delay = 30000; - int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1; - int is_open = 0; - int ret = 0, ret2; - IOUSBDevRequest req; - UInt8 bDeviceClass; - UInt16 idProduct, idVendor; - - (*device)->GetDeviceClass (device, &bDeviceClass); - (*device)->GetDeviceProduct (device, &idProduct); - (*device)->GetDeviceVendor (device, &idVendor); - - priv = (struct darwin_device_priv *)dev->os_priv; - - /* try to open the device (we can usually continue even if this fails) */ - is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess); - - /**** retrieve device descriptor ****/ - do { - /* Set up request for device descriptor */ - memset (&(priv->dev_descriptor), 0, sizeof(IOUSBDeviceDescriptor)); - req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); - req.bRequest = kUSBRqGetDescriptor; - req.wValue = kUSBDeviceDesc << 8; - req.wIndex = 0; - req.wLength = sizeof(priv->dev_descriptor); - req.pData = &(priv->dev_descriptor); - - /* according to Apple's documentation the device must be open for DeviceRequest but we may not be able to open some - * devices and Apple's USB Prober doesn't bother to open the device before issuing a descriptor request. Still, - * to follow the spec as closely as possible, try opening the device */ - - ret = (*(device))->DeviceRequest (device, &req); - - if (kIOReturnOverrun == ret && kUSBDeviceDesc == priv->dev_descriptor.bDescriptorType) - /* received an overrun error but we still received a device descriptor */ - ret = kIOReturnSuccess; - - if (kIOReturnSuccess == ret && (0 == priv->dev_descriptor.idProduct || - 0 == priv->dev_descriptor.bNumConfigurations || - 0 == priv->dev_descriptor.bcdUSB)) { - /* work around for incorrectly configured devices */ - if (try_reconfigure && is_open) { - usbi_dbg("descriptor appears to be invalid. resetting configuration before trying again..."); - - /* set the first configuration */ - (*device)->SetConfiguration(device, 1); - - /* don't try to reconfigure again */ - try_reconfigure = 0; - } - - ret = kIOUSBPipeStalled; - } - - if (kIOReturnSuccess != ret && is_open && try_unsuspend) { - /* device may be suspended. unsuspend it and try again */ -#if DeviceVersion >= 320 - UInt32 info; - - /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */ - (void)(*device)->GetUSBDeviceInformation (device, &info); - - try_unsuspend = info & (1 << kUSBInformationDeviceIsSuspendedBit); -#endif - - if (try_unsuspend) { - /* resume the device */ - ret2 = (*device)->USBDeviceSuspend (device, 0); - if (kIOReturnSuccess != ret2) { - /* prevent log spew from poorly behaving devices. this indicates the - os actually had trouble communicating with the device */ - usbi_dbg("could not retrieve device descriptor. failed to unsuspend: %s",darwin_error_str(ret2)); - } else - unsuspended = 1; - - try_unsuspend = 0; - } - } - - if (kIOReturnSuccess != ret) { - usbi_dbg("kernel responded with code: 0x%08x. sleeping for %d ms before trying again", ret, delay/1000); - /* sleep for a little while before trying again */ - usleep (delay); - } - } while (kIOReturnSuccess != ret && retries--); - - if (unsuspended) - /* resuspend the device */ - (void)(*device)->USBDeviceSuspend (device, 1); - - if (is_open) - (void) (*device)->USBDeviceClose (device); - - if (ret != kIOReturnSuccess) { - /* a debug message was already printed out for this error */ - if (LIBUSB_CLASS_HUB == bDeviceClass) - usbi_dbg ("could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret)); - else - usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s. skipping device", idVendor, idProduct, darwin_error_str (ret)); - - return -1; - } - - usbi_dbg ("device descriptor:"); - usbi_dbg (" bDescriptorType: 0x%02x", priv->dev_descriptor.bDescriptorType); - usbi_dbg (" bcdUSB: 0x%04x", priv->dev_descriptor.bcdUSB); - usbi_dbg (" bDeviceClass: 0x%02x", priv->dev_descriptor.bDeviceClass); - usbi_dbg (" bDeviceSubClass: 0x%02x", priv->dev_descriptor.bDeviceSubClass); - usbi_dbg (" bDeviceProtocol: 0x%02x", priv->dev_descriptor.bDeviceProtocol); - usbi_dbg (" bMaxPacketSize0: 0x%02x", priv->dev_descriptor.bMaxPacketSize0); - usbi_dbg (" idVendor: 0x%04x", priv->dev_descriptor.idVendor); - usbi_dbg (" idProduct: 0x%04x", priv->dev_descriptor.idProduct); - usbi_dbg (" bcdDevice: 0x%04x", priv->dev_descriptor.bcdDevice); - usbi_dbg (" iManufacturer: 0x%02x", priv->dev_descriptor.iManufacturer); - usbi_dbg (" iProduct: 0x%02x", priv->dev_descriptor.iProduct); - usbi_dbg (" iSerialNumber: 0x%02x", priv->dev_descriptor.iSerialNumber); - usbi_dbg (" bNumConfigurations: 0x%02x", priv->dev_descriptor.bNumConfigurations); - - /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */ - if (libusb_le16_to_cpu (priv->dev_descriptor.idProduct) != idProduct) { - /* not a valid device */ - usbi_warn (ctx, "idProduct from iokit (%04x) does not match idProduct in descriptor (%04x). skipping device", - idProduct, libusb_le16_to_cpu (priv->dev_descriptor.idProduct)); - return -1; - } - - return 0; -} - -static int process_new_device (struct libusb_context *ctx, usb_device_t **device, UInt32 locationID, struct discovered_devs **_discdevs) { - struct darwin_device_priv *priv; - struct libusb_device *dev; - struct discovered_devs *discdevs; - UInt16 address; - UInt8 devSpeed; - int ret = 0, need_unref = 0; - - do { - dev = usbi_get_device_by_session_id(ctx, locationID); - if (!dev) { - usbi_info (ctx, "allocating new device for location 0x%08x", locationID); - dev = usbi_alloc_device(ctx, locationID); - need_unref = 1; - } else - usbi_info (ctx, "using existing device for location 0x%08x", locationID); - - if (!dev) { - ret = LIBUSB_ERROR_NO_MEM; - break; - } - - priv = (struct darwin_device_priv *)dev->os_priv; - - (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&address); - - ret = darwin_cache_device_descriptor (ctx, dev, device); - if (ret < 0) - break; - - /* check current active configuration (and cache the first configuration value-- which may be used by claim_interface) */ - ret = darwin_check_configuration (ctx, dev, device); - if (ret < 0) - break; - - dev->bus_number = locationID >> 24; - dev->device_address = address; - - (*device)->GetDeviceSpeed (device, &devSpeed); - - switch (devSpeed) { - case kUSBDeviceSpeedLow: dev->speed = LIBUSB_SPEED_LOW; break; - case kUSBDeviceSpeedFull: dev->speed = LIBUSB_SPEED_FULL; break; - case kUSBDeviceSpeedHigh: dev->speed = LIBUSB_SPEED_HIGH; break; - default: - usbi_warn (ctx, "Got unknown device speed %d", devSpeed); - } - - /* save our location, we'll need this later */ - priv->location = locationID; - snprintf(priv->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", address, priv->dev_descriptor.idVendor, priv->dev_descriptor.idProduct, - priv->dev_descriptor.bDeviceClass, priv->dev_descriptor.bDeviceSubClass); - - ret = usbi_sanitize_device (dev); - if (ret < 0) - break; - - /* append the device to the list of discovered devices */ - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) { - ret = LIBUSB_ERROR_NO_MEM; - break; - } - - *_discdevs = discdevs; - - usbi_info (ctx, "found device with address %d at %s", dev->device_address, priv->sys_path); - } while (0); - - if (need_unref) - libusb_unref_device(dev); - - return ret; -} - -static int darwin_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) { - io_iterator_t deviceIterator; - usb_device_t **device; - kern_return_t kresult; - UInt32 location; - - kresult = usb_setup_device_iterator (&deviceIterator, 0); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - while ((device = usb_get_next_device (deviceIterator, &location)) != NULL) { - (void) process_new_device (ctx, device, location, _discdevs); - - (*(device))->Release(device); - } - - IOObjectRelease(deviceIterator); - - return 0; -} - -static int darwin_open (struct libusb_device_handle *dev_handle) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - usb_device_t **darwin_device; - IOReturn kresult; - - if (0 == dpriv->open_count) { - kresult = darwin_get_device (dpriv->location, &darwin_device); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "could not find device: %s", darwin_error_str (kresult)); - return darwin_to_libusb (kresult); - } - - dpriv->device = darwin_device; - - /* try to open the device */ - kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device); - - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult)); - - switch (kresult) { - case kIOReturnExclusiveAccess: - /* it is possible to perform some actions on a device that is not open so do not return an error */ - priv->is_open = 0; - - break; - default: - (*(dpriv->device))->Release (dpriv->device); - dpriv->device = NULL; - return darwin_to_libusb (kresult); - } - } else { - /* create async event source */ - kresult = (*(dpriv->device))->CreateDeviceAsyncEventSource (dpriv->device, &priv->cfSource); - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "CreateDeviceAsyncEventSource: %s", darwin_error_str(kresult)); - - (*(dpriv->device))->USBDeviceClose (dpriv->device); - (*(dpriv->device))->Release (dpriv->device); - - dpriv->device = NULL; - return darwin_to_libusb (kresult); - } - - priv->is_open = 1; - - CFRetain (libusb_darwin_acfl); - - /* add the cfSource to the aync run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, priv->cfSource, kCFRunLoopCommonModes); - } - } - - /* device opened successfully */ - dpriv->open_count++; - - /* create a file descriptor for notifications */ - pipe (priv->fds); - - /* set the pipe to be non-blocking */ - fcntl (priv->fds[1], F_SETFD, O_NONBLOCK); - - usbi_add_pollfd(HANDLE_CTX(dev_handle), priv->fds[0], POLLIN); - - usbi_info (HANDLE_CTX (dev_handle), "device open for access"); - - return 0; -} - -static void darwin_close (struct libusb_device_handle *dev_handle) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - IOReturn kresult; - int i; - - if (dpriv->open_count == 0) { - /* something is probably very wrong if this is the case */ - usbi_err (HANDLE_CTX (dev_handle), "Close called on a device that was not open!\n"); - return; - } - - dpriv->open_count--; - - /* make sure all interfaces are released */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - libusb_release_interface (dev_handle, i); - - if (0 == dpriv->open_count) { - if (priv->is_open) { - /* delete the device's async event source */ - if (priv->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode); - CFRelease (priv->cfSource); - } - - /* close the device */ - kresult = (*(dpriv->device))->USBDeviceClose(dpriv->device); - if (kresult) { - /* Log the fact that we had a problem closing the file, however failing a - * close isn't really an error, so return success anyway */ - usbi_err (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult)); - } - } - - kresult = (*(dpriv->device))->Release(dpriv->device); - if (kresult) { - /* Log the fact that we had a problem closing the file, however failing a - * close isn't really an error, so return success anyway */ - usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); - } - - dpriv->device = NULL; - } - - /* file descriptors are maintained per-instance */ - usbi_remove_pollfd (HANDLE_CTX (dev_handle), priv->fds[0]); - close (priv->fds[1]); - close (priv->fds[0]); - - priv->fds[0] = priv->fds[1] = -1; -} - -static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - - *config = (int) dpriv->active_config; - - return 0; -} - -static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - IOReturn kresult; - int i; - - /* Setting configuration will invalidate the interface, so we need - to reclaim it. First, dispose of existing interfaces, if any. */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - darwin_release_interface (dev_handle, i); - - kresult = (*(dpriv->device))->SetConfiguration (dpriv->device, config); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - /* Reclaim any interfaces. */ - for (i = 0 ; i < USB_MAXINTERFACES ; i++) - if (dev_handle->claimed_interfaces & (1 << i)) - darwin_claim_interface (dev_handle, i); - - dpriv->active_config = config; - - return 0; -} - -static int darwin_get_interface (usb_device_t **darwin_device, uint8_t ifc, io_service_t *usbInterfacep) { - IOUSBFindInterfaceRequest request; - uint8_t current_interface; - kern_return_t kresult; - io_iterator_t interface_iterator; - - *usbInterfacep = IO_OBJECT_NULL; - - /* Setup the Interface Request */ - request.bInterfaceClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; - request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; - request.bAlternateSetting = kIOUSBFindInterfaceDontCare; - - kresult = (*(darwin_device))->CreateInterfaceIterator(darwin_device, &request, &interface_iterator); - if (kresult) - return kresult; - - for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) { - *usbInterfacep = IOIteratorNext(interface_iterator); - if (current_interface != ifc) - (void) IOObjectRelease (*usbInterfacep); - } - - /* done with the interface iterator */ - IOObjectRelease(interface_iterator); - - return 0; -} - -static int get_endpoints (struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - kern_return_t kresult; - - u_int8_t numep, direction, number; - u_int8_t dont_care1, dont_care3; - u_int16_t dont_care2; - int i; - - usbi_info (HANDLE_CTX (dev_handle), "building table of endpoints."); - - /* retrieve the total number of endpoints on this interface */ - kresult = (*(cInterface->interface))->GetNumEndpoints(cInterface->interface, &numep); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "can't get number of endpoints for interface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* iterate through pipe references */ - for (i = 1 ; i <= numep ; i++) { - kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1, - &dont_care2, &dont_care3); - - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "error getting pipe information for pipe %d: %s", i, darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); - } - - usbi_info (HANDLE_CTX (dev_handle), "interface: %i pipe %i: dir: %i number: %i", iface, i, direction, number); - - cInterface->endpoint_addrs[i - 1] = ((direction << 7 & LIBUSB_ENDPOINT_DIR_MASK) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK)); - } - - cInterface->num_endpoints = numep; - - return 0; -} - -static int darwin_claim_interface(struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - io_service_t usbInterface = IO_OBJECT_NULL; - IOReturn kresult; - IOCFPlugInInterface **plugInInterface = NULL; - SInt32 score; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); - if (kresult != kIOReturnSuccess) - return darwin_to_libusb (kresult); - - /* make sure we have an interface */ - if (!usbInterface && dpriv->first_config != 0) { - usbi_info (HANDLE_CTX (dev_handle), "no interface found; setting configuration: %d", dpriv->first_config); - - /* set the configuration */ - kresult = darwin_set_configuration (dev_handle, dpriv->first_config); - if (kresult != LIBUSB_SUCCESS) { - usbi_err (HANDLE_CTX (dev_handle), "could not set configuration"); - return kresult; - } - - kresult = darwin_get_interface (dpriv->device, iface, &usbInterface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - } - - if (!usbInterface) { - usbi_err (HANDLE_CTX (dev_handle), "interface not found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - /* get an interface to the device's interface */ - kresult = IOCreatePlugInInterfaceForService (usbInterface, kIOUSBInterfaceUserClientTypeID, - kIOCFPlugInInterfaceID, &plugInInterface, &score); - - /* ignore release error */ - (void)IOObjectRelease (usbInterface); - - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "IOCreatePlugInInterfaceForService: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - if (!plugInInterface) { - usbi_err (HANDLE_CTX (dev_handle), "plugin interface not found"); - return LIBUSB_ERROR_NOT_FOUND; - } - - /* Do the actual claim */ - kresult = (*plugInInterface)->QueryInterface(plugInInterface, - CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), - (LPVOID)&cInterface->interface); - /* We no longer need the intermediate plug-in */ - IODestroyPlugInInterface (plugInInterface); - if (kresult || !cInterface->interface) { - usbi_err (HANDLE_CTX (dev_handle), "QueryInterface: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* claim the interface */ - kresult = (*(cInterface->interface))->USBInterfaceOpen(cInterface->interface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceOpen: %s", darwin_error_str(kresult)); - return darwin_to_libusb (kresult); - } - - /* update list of endpoints */ - kresult = get_endpoints (dev_handle, iface); - if (kresult) { - /* this should not happen */ - darwin_release_interface (dev_handle, iface); - usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); - return kresult; - } - - cInterface->cfSource = NULL; - - /* create async event source */ - kresult = (*(cInterface->interface))->CreateInterfaceAsyncEventSource (cInterface->interface, &cInterface->cfSource); - if (kresult != kIOReturnSuccess) { - usbi_err (HANDLE_CTX (dev_handle), "could not create async event source"); - - /* can't continue without an async event source */ - (void)darwin_release_interface (dev_handle, iface); - - return darwin_to_libusb (kresult); - } - - /* add the cfSource to the async thread's run loop */ - CFRunLoopAddSource(libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); - - usbi_info (HANDLE_CTX (dev_handle), "interface opened"); - - return 0; -} - -static int darwin_release_interface(struct libusb_device_handle *dev_handle, int iface) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - IOReturn kresult; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - /* Check to see if an interface is open */ - if (!cInterface->interface) - return LIBUSB_SUCCESS; - - /* clean up endpoint data */ - cInterface->num_endpoints = 0; - - /* delete the interface's async event source */ - if (cInterface->cfSource) { - CFRunLoopRemoveSource (libusb_darwin_acfl, cInterface->cfSource, kCFRunLoopDefaultMode); - CFRelease (cInterface->cfSource); - } - - kresult = (*(cInterface->interface))->USBInterfaceClose(cInterface->interface); - if (kresult) - usbi_err (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult)); - - kresult = (*(cInterface->interface))->Release(cInterface->interface); - if (kresult != kIOReturnSuccess) - usbi_err (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult)); - - cInterface->interface = IO_OBJECT_NULL; - - return darwin_to_libusb (kresult); -} - -static int darwin_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - IOReturn kresult; - - /* current interface */ - struct darwin_interface *cInterface = &priv->interfaces[iface]; - - if (!cInterface->interface) - return LIBUSB_ERROR_NO_DEVICE; - - kresult = (*(cInterface->interface))->SetAlternateInterface (cInterface->interface, altsetting); - if (kresult != kIOReturnSuccess) - darwin_reset_device (dev_handle); - - /* update list of endpoints */ - kresult = get_endpoints (dev_handle, iface); - if (kresult) { - /* this should not happen */ - darwin_release_interface (dev_handle, iface); - usbi_err (HANDLE_CTX (dev_handle), "could not build endpoint table"); - return kresult; - } - - return darwin_to_libusb (kresult); -} - -static int darwin_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)dev_handle->os_priv; - - /* current interface */ - struct darwin_interface *cInterface; - uint8_t pipeRef, iface; - IOReturn kresult; - - /* determine the interface/endpoint to use */ - if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, &iface) != 0) { - usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - -#if (InterfaceVersion < 190) - kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef); -#else - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); -#endif - if (kresult) - usbi_err (HANDLE_CTX (dev_handle), "ClearPipeStall: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_reset_device(struct libusb_device_handle *dev_handle) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - IOReturn kresult; - - kresult = (*(dpriv->device))->ResetDevice (dpriv->device); - if (kresult) - usbi_err (HANDLE_CTX (dev_handle), "ResetDevice: %s", darwin_error_str (kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) { - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)dev_handle->dev->os_priv; - io_service_t usbInterface; - CFTypeRef driver; - IOReturn kresult; - - kresult = darwin_get_interface (dpriv->device, interface, &usbInterface); - if (kresult) { - usbi_err (HANDLE_CTX (dev_handle), "darwin_get_interface: %s", darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); - } - - driver = IORegistryEntryCreateCFProperty (usbInterface, kIOBundleIdentifierKey, kCFAllocatorDefault, 0); - IOObjectRelease (usbInterface); - - if (driver) { - CFRelease (driver); - - return 1; - } - - /* no driver */ - return 0; -} - -/* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */ -static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - (void)dev_handle; - (void)interface; - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) { - (void)dev_handle; - (void)interface; - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void darwin_destroy_device(struct libusb_device *dev) { - (void)dev; -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - - IOReturn ret; - uint8_t is_read; /* 0 = we're reading, 1 = we're writing */ - uint8_t transferType; - /* None of the values below are used in libusb for bulk transfers */ - uint8_t direction, number, interval, pipeRef, iface; - uint16_t maxPacketSize; - - struct darwin_interface *cInterface; - - /* are we reading or writing? */ - is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number, - &transferType, &maxPacketSize, &interval); - - /* submit the request */ - /* timeouts are unavailable on interrupt endpoints */ - if (transferType == kUSBInterrupt) { - if (is_read) - ret = (*(cInterface->interface))->ReadPipeAsync(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, darwin_async_io_callback, itransfer); - else - ret = (*(cInterface->interface))->WritePipeAsync(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, darwin_async_io_callback, itransfer); - } else { - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; - - if (is_read) - ret = (*(cInterface->interface))->ReadPipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, transfer->timeout, transfer->timeout, - darwin_async_io_callback, (void *)itransfer); - else - ret = (*(cInterface->interface))->WritePipeAsyncTO(cInterface->interface, pipeRef, transfer->buffer, - transfer->length, transfer->timeout, transfer->timeout, - darwin_async_io_callback, (void *)itransfer); - } - - if (ret) - usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", is_read ? "In" : "Out", - darwin_error_str(ret), ret); - - return darwin_to_libusb (ret); -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - - IOReturn kresult; - uint8_t is_read; /* 0 = we're writing, 1 = we're reading */ - uint8_t pipeRef, iface; - UInt64 frame; - AbsoluteTime atTime; - int i; - - struct darwin_interface *cInterface; - - /* are we reading or writing? */ - is_read = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - /* construct an array of IOUSBIsocFrames, reuse the old one if possible */ - if (tpriv->isoc_framelist && tpriv->num_iso_packets != transfer->num_iso_packets) { - free(tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } - - if (!tpriv->isoc_framelist) { - tpriv->num_iso_packets = transfer->num_iso_packets; - tpriv->isoc_framelist = (IOUSBIsocFrame*) calloc (transfer->num_iso_packets, sizeof(IOUSBIsocFrame)); - if (!tpriv->isoc_framelist) - return LIBUSB_ERROR_NO_MEM; - } - - /* copy the frame list from the libusb descriptor (the structures differ only is member order) */ - for (i = 0 ; i < transfer->num_iso_packets ; i++) - tpriv->isoc_framelist[i].frReqCount = transfer->iso_packet_desc[i].length; - - /* determine the interface/endpoint to use */ - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - /* Last but not least we need the bus frame number */ - kresult = (*(cInterface->interface))->GetBusFrameNumber(cInterface->interface, &frame, &atTime); - if (kresult) { - usbi_err (TRANSFER_CTX (transfer), "failed to get bus frame number: %d", kresult); - free(tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - - return darwin_to_libusb (kresult); - } - - /* schedule for a frame a little in the future */ - frame += 4; - - if (cInterface->frames[transfer->endpoint] && frame < cInterface->frames[transfer->endpoint]) - frame = cInterface->frames[transfer->endpoint]; - - /* submit the request */ - if (is_read) - kresult = (*(cInterface->interface))->ReadIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, - transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, - itransfer); - else - kresult = (*(cInterface->interface))->WriteIsochPipeAsync(cInterface->interface, pipeRef, transfer->buffer, frame, - transfer->num_iso_packets, tpriv->isoc_framelist, darwin_async_io_callback, - itransfer); - - cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets / 8; - - if (kresult != kIOReturnSuccess) { - usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", is_read ? "In" : "Out", - darwin_error_str(kresult)); - free (tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } - - return darwin_to_libusb (kresult); -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_control_setup *setup = (struct libusb_control_setup *) transfer->buffer; - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - IOReturn kresult; - - bzero(&tpriv->req, sizeof(tpriv->req)); - - /* IOUSBDeviceInterface expects the request in cpu endianess */ - tpriv->req.bmRequestType = setup->bmRequestType; - tpriv->req.bRequest = setup->bRequest; - /* these values should be in bus order from libusb_fill_control_setup */ - tpriv->req.wValue = OSSwapLittleToHostInt16 (setup->wValue); - tpriv->req.wIndex = OSSwapLittleToHostInt16 (setup->wIndex); - tpriv->req.wLength = OSSwapLittleToHostInt16 (setup->wLength); - /* data is stored after the libusb control block */ - tpriv->req.pData = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE; - tpriv->req.completionTimeout = transfer->timeout; - tpriv->req.noDataTimeout = transfer->timeout; - - itransfer->flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT; - - /* all transfers in libusb-1.0 are async */ - - if (transfer->endpoint) { - struct darwin_interface *cInterface; - uint8_t pipeRef, iface; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - kresult = (*(cInterface->interface))->ControlRequestAsyncTO (cInterface->interface, pipeRef, &(tpriv->req), darwin_async_io_callback, itransfer); - } else - /* control request on endpoint 0 */ - kresult = (*(dpriv->device))->DeviceRequestAsyncTO(dpriv->device, &(tpriv->req), darwin_async_io_callback, itransfer); - - if (kresult != kIOReturnSuccess) - usbi_err (TRANSFER_CTX (transfer), "control request failed: %s", darwin_error_str(kresult)); - - return darwin_to_libusb (kresult); -} - -static int darwin_submit_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int cancel_control_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; - IOReturn kresult; - - usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions control pipe"); - - if (!dpriv->device) - return LIBUSB_ERROR_NO_DEVICE; - - kresult = (*(dpriv->device))->USBDeviceAbortPipeZero (dpriv->device); - - return darwin_to_libusb (kresult); -} - -static int darwin_abort_transfers (struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_priv *dpriv = (struct darwin_device_priv *)transfer->dev_handle->dev->os_priv; - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - struct darwin_interface *cInterface; - uint8_t pipeRef, iface; - IOReturn kresult; - - if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface) != 0) { - usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface"); - - return LIBUSB_ERROR_NOT_FOUND; - } - - cInterface = &priv->interfaces[iface]; - - if (!dpriv->device) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_info (ITRANSFER_CTX (itransfer), "WARNING: aborting all transactions on interface %d pipe %d", iface, pipeRef); - - /* abort transactions */ - (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef); - - usbi_info (ITRANSFER_CTX (itransfer), "calling clear pipe stall to clear the data toggle bit"); - - /* clear the data toggle bit */ -#if (InterfaceVersion < 190) - kresult = (*(cInterface->interface))->ClearPipeStall(cInterface->interface, pipeRef); -#else - /* newer versions of darwin support clearing additional bits on the device's endpoint */ - kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef); -#endif - - return darwin_to_libusb (kresult); -} - -static int darwin_cancel_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return cancel_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return darwin_abort_transfers (itransfer); - default: - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void darwin_clear_transfer_priv (struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && tpriv->isoc_framelist) { - free (tpriv->isoc_framelist); - tpriv->isoc_framelist = NULL; - } -} - -static void darwin_async_io_callback (void *refcon, IOReturn result, void *arg0) { - struct usbi_transfer *itransfer = (struct usbi_transfer *)refcon; - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_device_handle_priv *priv = (struct darwin_device_handle_priv *)transfer->dev_handle->os_priv; - UInt32 message, size; - - usbi_info (ITRANSFER_CTX (itransfer), "an async io operation has completed"); - - size = (UInt32) arg0; - - /* send a completion message to the device's file descriptor */ - message = MESSAGE_ASYNC_IO_COMPLETE; - write (priv->fds[1], &message, sizeof (message)); - write (priv->fds[1], &itransfer, sizeof (itransfer)); - write (priv->fds[1], &result, sizeof (IOReturn)); - write (priv->fds[1], &size, sizeof (size)); -} - -static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) { - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) - result = kIOUSBTransactionTimeout; - - switch (result) { - case kIOReturnUnderrun: - case kIOReturnSuccess: - return LIBUSB_TRANSFER_COMPLETED; - case kIOReturnAborted: - return LIBUSB_TRANSFER_CANCELLED; - case kIOUSBPipeStalled: - usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: pipe is stalled"); - return LIBUSB_TRANSFER_STALL; - case kIOReturnOverrun: - usbi_err (ITRANSFER_CTX (itransfer), "transfer error: data overrun"); - return LIBUSB_TRANSFER_OVERFLOW; - case kIOUSBTransactionTimeout: - usbi_err (ITRANSFER_CTX (itransfer), "transfer error: timed out"); - itransfer->flags |= USBI_TRANSFER_TIMED_OUT; - return LIBUSB_TRANSFER_TIMED_OUT; - default: - usbi_err (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result); - return LIBUSB_TRANSFER_ERROR; - } -} - -static void darwin_handle_callback (struct usbi_transfer *itransfer, kern_return_t result, UInt32 io_size) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int isIsoc = LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type; - int isBulk = LIBUSB_TRANSFER_TYPE_BULK == transfer->type; - int isControl = LIBUSB_TRANSFER_TYPE_CONTROL == transfer->type; - int isInterrupt = LIBUSB_TRANSFER_TYPE_INTERRUPT == transfer->type; - int i; - - if (!isIsoc && !isBulk && !isControl && !isInterrupt) { - usbi_err (TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return; - } - - usbi_info (ITRANSFER_CTX (itransfer), "handling %s completion with kernel status %d", - isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", result); - - if (kIOReturnSuccess == result || kIOReturnUnderrun == result) { - if (isIsoc && tpriv->isoc_framelist) { - /* copy isochronous results back */ - - for (i = 0; i < transfer->num_iso_packets ; i++) { - struct libusb_iso_packet_descriptor *lib_desc = &transfer->iso_packet_desc[i]; - lib_desc->status = darwin_to_libusb (tpriv->isoc_framelist[i].frStatus); - lib_desc->actual_length = tpriv->isoc_framelist[i].frActCount; - } - } else if (!isIsoc) - itransfer->transferred += io_size; - } - - /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */ - usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, result)); -} - -static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) { - struct usbi_transfer *itransfer; - UInt32 io_size; - IOReturn kresult; - POLL_NFDS_TYPE i = 0; - ssize_t ret; - UInt32 message; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - struct pollfd *pollfd = &fds[i]; - struct libusb_device_handle *handle; - struct darwin_device_handle_priv *hpriv = NULL; - - usbi_info (ctx, "checking fd %i with revents = %x", fds[i], pollfd->revents); - - if (!pollfd->revents) - continue; - - num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - hpriv = (struct darwin_device_handle_priv *)handle->os_priv; - if (hpriv->fds[0] == pollfd->fd) - break; - } - - if (!(pollfd->revents & POLLERR)) { - ret = read (hpriv->fds[0], &message, sizeof (message)); - if (ret < (ssize_t)sizeof (message)) - continue; - } else - /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */ - message = MESSAGE_DEVICE_GONE; - - switch (message) { - case MESSAGE_DEVICE_GONE: - /* remove the device's async port from the runloop */ - if (hpriv->cfSource) { - if (libusb_darwin_acfl) - CFRunLoopRemoveSource (libusb_darwin_acfl, hpriv->cfSource, kCFRunLoopDefaultMode); - CFRelease (hpriv->cfSource); - hpriv->cfSource = NULL; - } - - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fds[0]); - usbi_handle_disconnect(handle); - - /* done with this device */ - continue; - case MESSAGE_ASYNC_IO_COMPLETE: - read (hpriv->fds[0], &itransfer, sizeof (itransfer)); - read (hpriv->fds[0], &kresult, sizeof (IOReturn)); - read (hpriv->fds[0], &io_size, sizeof (UInt32)); - - darwin_handle_callback (itransfer, kresult, io_size); - break; - default: - usbi_err (ctx, "unknown message received from device pipe"); - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - - return 0; -} - -static int darwin_clock_gettime(int clk_id, struct timespec *tp) { - mach_timespec_t sys_time; - clock_serv_t clock_ref; - - switch (clk_id) { - case USBI_CLOCK_REALTIME: - /* CLOCK_REALTIME represents time since the epoch */ - clock_ref = clock_realtime; - break; - case USBI_CLOCK_MONOTONIC: - /* use system boot time as reference for the monotonic clock */ - clock_ref = clock_monotonic; - break; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } - - clock_get_time (clock_ref, &sys_time); - - tp->tv_sec = sys_time.tv_sec; - tp->tv_nsec = sys_time.tv_nsec; - - return 0; -} - -const struct usbi_os_backend darwin_backend = { - .name = "Darwin", - .init = darwin_init, - .exit = darwin_exit, - .get_device_list = darwin_get_device_list, - .get_device_descriptor = darwin_get_device_descriptor, - .get_active_config_descriptor = darwin_get_active_config_descriptor, - .get_config_descriptor = darwin_get_config_descriptor, - - .open = darwin_open, - .close = darwin_close, - .get_configuration = darwin_get_configuration, - .set_configuration = darwin_set_configuration, - .claim_interface = darwin_claim_interface, - .release_interface = darwin_release_interface, - - .set_interface_altsetting = darwin_set_interface_altsetting, - .clear_halt = darwin_clear_halt, - .reset_device = darwin_reset_device, - - .kernel_driver_active = darwin_kernel_driver_active, - .detach_kernel_driver = darwin_detach_kernel_driver, - .attach_kernel_driver = darwin_attach_kernel_driver, - - .destroy_device = darwin_destroy_device, - - .submit_transfer = darwin_submit_transfer, - .cancel_transfer = darwin_cancel_transfer, - .clear_transfer_priv = darwin_clear_transfer_priv, - - .handle_events = op_handle_events, - - .clock_gettime = darwin_clock_gettime, - - .device_priv_size = sizeof(struct darwin_device_priv), - .device_handle_priv_size = sizeof(struct darwin_device_handle_priv), - .transfer_priv_size = sizeof(struct darwin_transfer_priv), - .add_iso_packet_size = 0, -}; - diff --git a/third_party/libusb/libusb/os/darwin_usb.h b/third_party/libusb/libusb/os/darwin_usb.h deleted file mode 100644 index 59d0a69..0000000 --- a/third_party/libusb/libusb/os/darwin_usb.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * darwin backend for libusb 1.0 - * Copyright (C) 2008-2009 Nathan Hjelm <hjelmn@users.sourceforge.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#if !defined(LIBUSB_DARWIN_H) -#define LIBUSB_DARWIN_H - -#include "libusbi.h" - -#include <IOKit/IOTypes.h> -#include <IOKit/IOCFBundle.h> -#include <IOKit/usb/IOUSBLib.h> -#include <IOKit/IOCFPlugIn.h> - -/* IOUSBInterfaceInferface */ -#if defined (kIOUSBInterfaceInterfaceID300) - -#define usb_interface_t IOUSBInterfaceInterface300 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300 -#define InterfaceVersion 300 - -#elif defined (kIOUSBInterfaceInterfaceID245) - -#define usb_interface_t IOUSBInterfaceInterface245 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245 -#define InterfaceVersion 245 - -#elif defined (kIOUSBInterfaceInterfaceID220) - -#define usb_interface_t IOUSBInterfaceInterface220 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220 -#define InterfaceVersion 220 - -#elif defined (kIOUSBInterfaceInterfaceID197) - -#define usb_interface_t IOUSBInterfaceInterface197 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197 -#define InterfaceVersion 197 - -#elif defined (kIOUSBInterfaceInterfaceID190) - -#define usb_interface_t IOUSBInterfaceInterface190 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190 -#define InterfaceVersion 190 - -#elif defined (kIOUSBInterfaceInterfaceID182) - -#define usb_interface_t IOUSBInterfaceInterface182 -#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182 -#define InterfaceVersion 182 - -#else - -#error "IOUSBFamily is too old. Please upgrade your OS" - -#endif - -/* IOUSBDeviceInterface */ -#if defined (kIOUSBDeviceInterfaceID320) - -#define usb_device_t IOUSBDeviceInterface320 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID320 -#define DeviceVersion 320 - -#elif defined (kIOUSBDeviceInterfaceID300) - -#define usb_device_t IOUSBDeviceInterface300 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID300 -#define DeviceVersion 300 - -#elif defined (kIOUSBDeviceInterfaceID245) - -#define usb_device_t IOUSBDeviceInterface245 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID245 -#define DeviceVersion 245 - -#elif defined (kIOUSBDeviceInterfaceID197) - -#define usb_device_t IOUSBDeviceInterface197 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID197 -#define DeviceVersion 197 - -#elif defined (kIOUSBDeviceInterfaceID187) - -#define usb_device_t IOUSBDeviceInterface187 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID187 -#define DeviceVersion 187 - -#elif defined (kIOUSBDeviceInterfaceID182) - -#define usb_device_t IOUSBDeviceInterface182 -#define DeviceInterfaceID kIOUSBDeviceInterfaceID182 -#define DeviceVersion 182 - -#else - -#error "IOUSBFamily is too old. Please upgrade your OS" - -#endif - -#if !defined(IO_OBJECT_NULL) -#define IO_OBJECT_NULL ((io_object_t) 0) -#endif - -typedef IOCFPlugInInterface *io_cf_plugin_ref_t; -typedef IONotificationPortRef io_notification_port_t; - -/* private structures */ -struct darwin_device_priv { - IOUSBDeviceDescriptor dev_descriptor; - UInt32 location; - char sys_path[21]; - usb_device_t **device; - int open_count; - UInt8 first_config, active_config; -}; - -struct darwin_device_handle_priv { - int is_open; - CFRunLoopSourceRef cfSource; - int fds[2]; - - struct darwin_interface { - usb_interface_t **interface; - uint8_t num_endpoints; - CFRunLoopSourceRef cfSource; - uint64_t frames[256]; - uint8_t endpoint_addrs[USB_MAXENDPOINTS]; - } interfaces[USB_MAXINTERFACES]; -}; - -struct darwin_transfer_priv { - /* Isoc */ - IOUSBIsocFrame *isoc_framelist; - size_t num_iso_packets; - - /* Control */ -#if !defined (LIBUSB_NO_TIMEOUT_DEVICE) - IOUSBDevRequestTO req; -#else - IOUSBDevRequest req; -#endif - - /* Bulk */ -}; - -enum { - MESSAGE_DEVICE_GONE, - MESSAGE_ASYNC_IO_COMPLETE -}; - - - -#endif diff --git a/third_party/libusb/libusb/os/linux_usbfs.c b/third_party/libusb/libusb/os/linux_usbfs.c deleted file mode 100644 index 2b81189..0000000 --- a/third_party/libusb/libusb/os/linux_usbfs.c +++ /dev/null @@ -1,2313 +0,0 @@ -/* - * Linux usbfs backend for libusb - * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/utsname.h> -#include <unistd.h> - -#include "libusb.h" -#include "libusbi.h" -#include "linux_usbfs.h" - -/* sysfs vs usbfs: - * opening a usbfs node causes the device to be resumed, so we attempt to - * avoid this during enumeration. - * - * sysfs allows us to read the kernel's in-memory copies of device descriptors - * and so forth, avoiding the need to open the device: - * - The binary "descriptors" file was added in 2.6.23. - * - The "busnum" file was added in 2.6.22 - * - The "devnum" file has been present since pre-2.6.18 - * - the "bConfigurationValue" file has been present since pre-2.6.18 - * - * If we have bConfigurationValue, busnum, and devnum, then we can determine - * the active configuration without having to open the usbfs node in RDWR mode. - * We assume this is the case if we see the busnum file (indicates 2.6.22+). - * The busnum file is important as that is the only way we can relate sysfs - * devices to usbfs nodes. - * - * If we also have descriptors, we can obtain the device descriptor and active - * configuration without touching usbfs at all. - * - * The descriptors file originally only contained the active configuration - * descriptor alongside the device descriptor, but all configurations are - * included as of Linux 2.6.26. - */ - -/* endianness for multi-byte fields: - * - * Descriptors exposed by usbfs have the multi-byte fields in the device - * descriptor as host endian. Multi-byte fields in the other descriptors are - * bus-endian. The kernel documentation says otherwise, but it is wrong. - */ - -static const char *usbfs_path = NULL; - -/* Linux 2.6.32 adds support for a bulk continuation URB flag. this basically - * allows us to mark URBs as being part of a specific logical transfer when - * we submit them to the kernel. then, on any error except a cancellation, all - * URBs within that transfer will be cancelled and no more URBs will be - * accepted for the transfer, meaning that no more data can creep in. - * - * The BULK_CONTINUATION flag must be set on all URBs within a bulk transfer - * (in either direction) except the first. - * For IN transfers, we must also set SHORT_NOT_OK on all URBs except the - * last; it means that the kernel should treat a short reply as an error. - * For OUT transfers, SHORT_NOT_OK must not be set. it isn't needed (OUT - * transfers can't be short unless there's already some sort of error), and - * setting this flag is disallowed (a kernel with USB debugging enabled will - * reject such URBs). - */ -static int supports_flag_bulk_continuation = -1; - -/* clock ID for monotonic clock, as not all clock sources are available on all - * systems. appropriate choice made at initialization time. */ -static clockid_t monotonic_clkid = -1; - -/* do we have a busnum to relate devices? this also implies that we can read - * the active configuration through bConfigurationValue */ -static int sysfs_can_relate_devices = 0; - -/* do we have a descriptors file? */ -static int sysfs_has_descriptors = 0; - -struct linux_device_priv { - char *sysfs_dir; - unsigned char *dev_descriptor; - unsigned char *config_descriptor; -}; - -struct linux_device_handle_priv { - int fd; -}; - -enum reap_action { - NORMAL = 0, - /* submission failed after the first URB, so await cancellation/completion - * of all the others */ - SUBMIT_FAILED, - - /* cancelled by user or timeout */ - CANCELLED, - - /* completed multi-URB transfer in non-final URB */ - COMPLETED_EARLY, - - /* one or more urbs encountered a low-level error */ - ERROR, -}; - -struct linux_transfer_priv { - union { - struct usbfs_urb *urbs; - struct usbfs_urb **iso_urbs; - }; - - enum reap_action reap_action; - int num_urbs; - unsigned int num_retired; - enum libusb_transfer_status reap_status; - - /* next iso packet in user-supplied transfer to be populated */ - int iso_packet_offset; -}; - -static void _get_usbfs_path(struct libusb_device *dev, char *path) -{ - snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, dev->bus_number, - dev->device_address); -} - -static struct linux_device_priv *_device_priv(struct libusb_device *dev) -{ - return (struct linux_device_priv *) dev->os_priv; -} - -static struct linux_device_handle_priv *_device_handle_priv( - struct libusb_device_handle *handle) -{ - return (struct linux_device_handle_priv *) handle->os_priv; -} - -static int check_usb_vfs(const char *dirname) -{ - DIR *dir; - struct dirent *entry; - int found = 0; - - dir = opendir(dirname); - if (!dir) - return 0; - - while ((entry = readdir(dir)) != NULL) { - if (entry->d_name[0] == '.') - continue; - - /* We assume if we find any files that it must be the right place */ - found = 1; - break; - } - - closedir(dir); - return found; -} - -static const char *find_usbfs_path(void) -{ - const char *path = "/dev/bus/usb"; - const char *ret = NULL; - - if (check_usb_vfs(path)) { - ret = path; - } else { - path = "/proc/bus/usb"; - if (check_usb_vfs(path)) - ret = path; - } - - usbi_dbg("found usbfs at %s", ret); - return ret; -} - -/* the monotonic clock is not usable on all systems (e.g. embedded ones often - * seem to lack it). fall back to REALTIME if we have to. */ -static clockid_t find_monotonic_clock(void) -{ - struct timespec ts; - int r; - -#ifdef CLOCK_MONOTONIC - /* Linux 2.6.28 adds CLOCK_MONOTONIC_RAW but we don't use it - * because it's not available through timerfd */ - r = clock_gettime(CLOCK_MONOTONIC, &ts); - if (r == 0) - return CLOCK_MONOTONIC; - usbi_dbg("monotonic clock doesn't work, errno %d", errno); -#endif - - return CLOCK_REALTIME; -} - -/* bulk continuation URB flag available from Linux 2.6.32 */ -static int check_flag_bulk_continuation(void) -{ - struct utsname uts; - int atoms, major, minor, sublevel; - - if (uname(&uts) < 0) - return -1; - atoms = sscanf(uts.release, "%d.%d.%d", &major, &minor, &sublevel); - if (atoms < 1) - return -1; - - if (major > 2) - return 1; - if (major < 2) - return 0; - - if (atoms < 2) - return 0; - - /* major == 2 */ - if (minor < 6) - return 0; - if (minor > 6) /* Does not exist, just here for correctness */ - return 1; - - /* 2.6.x */ - if (3 == atoms && sublevel >= 32) - return 1; - - return 0; -} - -/* Return 1 if filename exists inside dirname in sysfs. - SYSFS_DEVICE_PATH is assumed to be the beginning of the path. */ -static int sysfs_has_file(const char *dirname, const char *filename) -{ - struct stat statbuf; - char path[PATH_MAX]; - int r; - - snprintf(path, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, dirname, filename); - r = stat(path, &statbuf); - if (r == 0 && S_ISREG(statbuf.st_mode)) - return 1; - - return 0; -} - -static int op_init(struct libusb_context *ctx) -{ - struct stat statbuf; - int r; - - usbfs_path = find_usbfs_path(); - if (!usbfs_path) { - usbi_err(ctx, "could not find usbfs"); - return LIBUSB_ERROR_OTHER; - } - - if (monotonic_clkid == -1) - monotonic_clkid = find_monotonic_clock(); - - if (supports_flag_bulk_continuation == -1) { - supports_flag_bulk_continuation = check_flag_bulk_continuation(); - if (supports_flag_bulk_continuation == -1) { - usbi_err(ctx, "error checking for bulk continuation support"); - return LIBUSB_ERROR_OTHER; - } - } - - if (supports_flag_bulk_continuation) - usbi_dbg("bulk continuation flag supported"); - - r = stat(SYSFS_DEVICE_PATH, &statbuf); - if (r == 0 && S_ISDIR(statbuf.st_mode)) { - DIR *devices = opendir(SYSFS_DEVICE_PATH); - struct dirent *entry; - - usbi_dbg("found usb devices in sysfs"); - - if (!devices) { - usbi_err(ctx, "opendir devices failed errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - /* Make sure sysfs supports all the required files. If it - * does not, then usbfs will be used instead. Determine - * this by looping through the directories in - * SYSFS_DEVICE_PATH. With the assumption that there will - * always be subdirectories of the name usbN (usb1, usb2, - * etc) representing the root hubs, check the usbN - * subdirectories to see if they have all the needed files. - * This algorithm uses the usbN subdirectories (root hubs) - * because a device disconnection will cause a race - * condition regarding which files are available, sometimes - * causing an incorrect result. The root hubs are used - * because it is assumed that they will always be present. - * See the "sysfs vs usbfs" comment at the top of this file - * for more details. */ - while ((entry = readdir(devices))) { - int has_busnum=0, has_devnum=0, has_descriptors=0; - int has_configuration_value=0; - - /* Only check the usbN directories. */ - if (strncmp(entry->d_name, "usb", 3) != 0) - continue; - - /* Check for the files libusb needs from sysfs. */ - has_busnum = sysfs_has_file(entry->d_name, "busnum"); - has_devnum = sysfs_has_file(entry->d_name, "devnum"); - has_descriptors = sysfs_has_file(entry->d_name, "descriptors"); - has_configuration_value = sysfs_has_file(entry->d_name, "bConfigurationValue"); - - if (has_busnum && has_devnum && has_configuration_value) - sysfs_can_relate_devices = 1; - if (has_descriptors) - sysfs_has_descriptors = 1; - - /* Only need to check until we've found ONE device which - has all the attributes. */ - if (sysfs_has_descriptors && sysfs_can_relate_devices) - break; - } - closedir(devices); - - /* Only use sysfs descriptors if the rest of - sysfs will work for libusb. */ - if (!sysfs_can_relate_devices) - sysfs_has_descriptors = 0; - } else { - usbi_dbg("sysfs usb info not available"); - sysfs_has_descriptors = 0; - sysfs_can_relate_devices = 0; - } - - return 0; -} - -static int usbfs_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer) -{ - struct linux_device_priv *priv = _device_priv(dev); - - /* return cached copy */ - memcpy(buffer, priv->dev_descriptor, DEVICE_DESC_LENGTH); - return 0; -} - -static int _open_sysfs_attr(struct libusb_device *dev, const char *attr) -{ - struct linux_device_priv *priv = _device_priv(dev); - char filename[PATH_MAX]; - int fd; - - snprintf(filename, PATH_MAX, "%s/%s/%s", - SYSFS_DEVICE_PATH, priv->sysfs_dir, attr); - fd = open(filename, O_RDONLY); - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), - "open %s failed ret=%d errno=%d", filename, fd, errno); - return LIBUSB_ERROR_IO; - } - - return fd; -} - -/* Note only suitable for attributes which always read >= 0, < 0 is error */ -static int __read_sysfs_attr(struct libusb_context *ctx, - const char *devname, const char *attr) -{ - char filename[PATH_MAX]; - FILE *f; - int r, value; - - snprintf(filename, PATH_MAX, "%s/%s/%s", SYSFS_DEVICE_PATH, - devname, attr); - f = fopen(filename, "r"); - if (f == NULL) { - if (errno == ENOENT) { - /* File doesn't exist. Assume the device has been - disconnected (see trac ticket #70). */ - return LIBUSB_ERROR_NO_DEVICE; - } - usbi_err(ctx, "open %s failed errno=%d", filename, errno); - return LIBUSB_ERROR_IO; - } - - r = fscanf(f, "%d", &value); - fclose(f); - if (r != 1) { - usbi_err(ctx, "fscanf %s returned %d, errno=%d", attr, r, errno); - return LIBUSB_ERROR_NO_DEVICE; /* For unplug race (trac #70) */ - } - if (value < 0) { - usbi_err(ctx, "%s contains a negative value", filename); - return LIBUSB_ERROR_IO; - } - - return value; -} - -static int sysfs_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer) -{ - int fd; - ssize_t r; - - /* sysfs provides access to an in-memory copy of the device descriptor, - * so we use that rather than keeping our own copy */ - - fd = _open_sysfs_attr(dev, "descriptors"); - if (fd < 0) - return fd; - - r = read(fd, buffer, DEVICE_DESC_LENGTH);; - close(fd); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", fd, errno); - return LIBUSB_ERROR_IO; - } else if (r < DEVICE_DESC_LENGTH) { - usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, DEVICE_DESC_LENGTH); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -static int op_get_device_descriptor(struct libusb_device *dev, - unsigned char *buffer, int *host_endian) -{ - if (sysfs_has_descriptors) { - return sysfs_get_device_descriptor(dev, buffer); - } else { - *host_endian = 1; - return usbfs_get_device_descriptor(dev, buffer); - } -} - -static int usbfs_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len) -{ - struct linux_device_priv *priv = _device_priv(dev); - if (!priv->config_descriptor) - return LIBUSB_ERROR_NOT_FOUND; /* device is unconfigured */ - - /* retrieve cached copy */ - memcpy(buffer, priv->config_descriptor, len); - return 0; -} - -/* read the bConfigurationValue for a device */ -static int sysfs_get_active_config(struct libusb_device *dev, int *config) -{ - char *endptr; - char tmp[4] = {0, 0, 0, 0}; - long num; - int fd; - ssize_t r; - - fd = _open_sysfs_attr(dev, "bConfigurationValue"); - if (fd < 0) - return fd; - - r = read(fd, tmp, sizeof(tmp)); - close(fd); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "read bConfigurationValue failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r == 0) { - usbi_err(DEVICE_CTX(dev), "device unconfigured"); - *config = -1; - return 0; - } - - if (tmp[sizeof(tmp) - 1] != 0) { - usbi_err(DEVICE_CTX(dev), "not null-terminated?"); - return LIBUSB_ERROR_IO; - } else if (tmp[0] == 0) { - usbi_err(DEVICE_CTX(dev), "no configuration value?"); - return LIBUSB_ERROR_IO; - } - - num = strtol(tmp, &endptr, 10); - if (endptr == tmp) { - usbi_err(DEVICE_CTX(dev), "error converting '%s' to integer", tmp); - return LIBUSB_ERROR_IO; - } - - *config = (int) num; - return 0; -} - -/* takes a usbfs/descriptors fd seeked to the start of a configuration, and - * seeks to the next one. */ -static int seek_to_next_config(struct libusb_context *ctx, int fd, - int host_endian) -{ - struct libusb_config_descriptor config; - unsigned char tmp[6]; - off_t off; - ssize_t r; - - /* read first 6 bytes of descriptor */ - r = read(fd, tmp, sizeof(tmp)); - if (r < 0) { - usbi_err(ctx, "read failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r < sizeof(tmp)) { - usbi_err(ctx, "short descriptor read %d/%d", r, sizeof(tmp)); - return LIBUSB_ERROR_IO; - } - - /* seek forward to end of config */ - usbi_parse_descriptor(tmp, "bbwbb", &config, host_endian); - off = lseek(fd, config.wTotalLength - sizeof(tmp), SEEK_CUR); - if (off < 0) { - usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -static int sysfs_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len) -{ - int fd; - ssize_t r; - off_t off; - int to_copy; - int config; - unsigned char tmp[6]; - - r = sysfs_get_active_config(dev, &config); - if (r < 0) - return r; - if (config == -1) - return LIBUSB_ERROR_NOT_FOUND; - - usbi_dbg("active configuration %d", config); - - /* sysfs provides access to an in-memory copy of the device descriptor, - * so we use that rather than keeping our own copy */ - - fd = _open_sysfs_attr(dev, "descriptors"); - if (fd < 0) - return fd; - - /* device might have been unconfigured since we read bConfigurationValue, - * so first check that there is any config descriptor data at all... */ - off = lseek(fd, 0, SEEK_END); - if (off < 1) { - usbi_err(DEVICE_CTX(dev), "end seek failed, ret=%d errno=%d", - off, errno); - close(fd); - return LIBUSB_ERROR_IO; - } else if (off == DEVICE_DESC_LENGTH) { - close(fd); - return LIBUSB_ERROR_NOT_FOUND; - } - - off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET); - if (off < 0) { - usbi_err(DEVICE_CTX(dev), "seek failed, ret=%d errno=%d", off, errno); - close(fd); - return LIBUSB_ERROR_IO; - } - - /* unbounded loop: we expect the descriptor to be present under all - * circumstances */ - while (1) { - r = read(fd, tmp, sizeof(tmp)); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", - fd, errno); - return LIBUSB_ERROR_IO; - } else if (r < sizeof(tmp)) { - usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, sizeof(tmp)); - return LIBUSB_ERROR_IO; - } - - /* check bConfigurationValue */ - if (tmp[5] == config) - break; - - /* try the next descriptor */ - off = lseek(fd, 0 - sizeof(tmp), SEEK_CUR); - if (off < 0) - return LIBUSB_ERROR_IO; - - r = seek_to_next_config(DEVICE_CTX(dev), fd, 0); - if (r < 0) - return r; - } - - to_copy = (len < sizeof(tmp)) ? len : sizeof(tmp); - memcpy(buffer, tmp, to_copy); - if (len > sizeof(tmp)) { - r = read(fd, buffer + sizeof(tmp), len - sizeof(tmp)); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", - fd, errno); - r = LIBUSB_ERROR_IO; - } else if (r == 0) { - usbi_dbg("device is unconfigured"); - r = LIBUSB_ERROR_NOT_FOUND; - } else if (r < len - sizeof(tmp)) { - usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, len); - r = LIBUSB_ERROR_IO; - } - } else { - r = 0; - } - - close(fd); - return r; -} - -static int op_get_active_config_descriptor(struct libusb_device *dev, - unsigned char *buffer, size_t len, int *host_endian) -{ - if (sysfs_has_descriptors) { - return sysfs_get_active_config_descriptor(dev, buffer, len); - } else { - return usbfs_get_active_config_descriptor(dev, buffer, len); - } -} - -/* takes a usbfs fd, attempts to find the requested config and copy a certain - * amount of it into an output buffer. */ -static int get_config_descriptor(struct libusb_context *ctx, int fd, - uint8_t config_index, unsigned char *buffer, size_t len) -{ - off_t off; - ssize_t r; - - off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET); - if (off < 0) { - usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno); - return LIBUSB_ERROR_IO; - } - - /* might need to skip some configuration descriptors to reach the - * requested configuration */ - while (config_index > 0) { - r = seek_to_next_config(ctx, fd, 1); - if (r < 0) - return r; - config_index--; - } - - /* read the rest of the descriptor */ - r = read(fd, buffer, len); - if (r < 0) { - usbi_err(ctx, "read failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } else if (r < len) { - usbi_err(ctx, "short output read %d/%d", r, len); - return LIBUSB_ERROR_IO; - } - - return 0; -} - -static int op_get_config_descriptor(struct libusb_device *dev, - uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - char filename[PATH_MAX]; - int fd; - int r; - - /* always read from usbfs: sysfs only has the active descriptor - * this will involve waking the device up, but oh well! */ - - /* FIXME: the above is no longer true, new kernels have all descriptors - * in the descriptors file. but its kinda hard to detect if the kernel - * is sufficiently new. */ - - _get_usbfs_path(dev, filename); - fd = open(filename, O_RDONLY); - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), - "open '%s' failed, ret=%d errno=%d", filename, fd, errno); - return LIBUSB_ERROR_IO; - } - - r = get_config_descriptor(DEVICE_CTX(dev), fd, config_index, buffer, len); - close(fd); - return r; -} - -/* cache the active config descriptor in memory. a value of -1 means that - * we aren't sure which one is active, so just assume the first one. - * only for usbfs. */ -static int cache_active_config(struct libusb_device *dev, int fd, - int active_config) -{ - struct linux_device_priv *priv = _device_priv(dev); - struct libusb_config_descriptor config; - unsigned char tmp[8]; - unsigned char *buf; - int idx; - int r; - - if (active_config == -1) { - idx = 0; - } else { - r = usbi_get_config_index_by_value(dev, active_config, &idx); - if (r < 0) - return r; - if (idx == -1) - return LIBUSB_ERROR_NOT_FOUND; - } - - r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, tmp, sizeof(tmp)); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), "first read error %d", r); - return r; - } - - usbi_parse_descriptor(tmp, "bbw", &config, 0); - buf = malloc(config.wTotalLength); - if (!buf) - return LIBUSB_ERROR_NO_MEM; - - r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, buf, - config.wTotalLength); - if (r < 0) { - free(buf); - return r; - } - - if (priv->config_descriptor) - free(priv->config_descriptor); - priv->config_descriptor = buf; - return 0; -} - -/* send a control message to retrieve active configuration */ -static int usbfs_get_active_config(struct libusb_device *dev, int fd) -{ - unsigned char active_config = 0; - int r; - - struct usbfs_ctrltransfer ctrl = { - .bmRequestType = LIBUSB_ENDPOINT_IN, - .bRequest = LIBUSB_REQUEST_GET_CONFIGURATION, - .wValue = 0, - .wIndex = 0, - .wLength = 1, - .timeout = 1000, - .data = &active_config - }; - - r = ioctl(fd, IOCTL_USBFS_CONTROL, &ctrl); - if (r < 0) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - /* we hit this error path frequently with buggy devices :( */ - usbi_warn(DEVICE_CTX(dev), - "get_configuration failed ret=%d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - - return active_config; -} - -static int initialize_device(struct libusb_device *dev, uint8_t busnum, - uint8_t devaddr, const char *sysfs_dir) -{ - struct linux_device_priv *priv = _device_priv(dev); - unsigned char *dev_buf; - char path[PATH_MAX]; - int fd, speed; - int active_config = 0; - int device_configured = 1; - ssize_t r; - - dev->bus_number = busnum; - dev->device_address = devaddr; - - if (sysfs_dir) { - priv->sysfs_dir = malloc(strlen(sysfs_dir) + 1); - if (!priv->sysfs_dir) - return LIBUSB_ERROR_NO_MEM; - strcpy(priv->sysfs_dir, sysfs_dir); - - /* Note speed can contain 1.5, in this case __read_sysfs_attr - will stop parsing at the '.' and return 1 */ - speed = __read_sysfs_attr(DEVICE_CTX(dev), sysfs_dir, "speed"); - if (speed >= 0) { - switch (speed) { - case 1: dev->speed = LIBUSB_SPEED_LOW; break; - case 12: dev->speed = LIBUSB_SPEED_FULL; break; - case 480: dev->speed = LIBUSB_SPEED_HIGH; break; - case 5000: dev->speed = LIBUSB_SPEED_SUPER; break; - default: - usbi_warn(DEVICE_CTX(dev), "Unknown device speed: %d Mbps", speed); - } - } - } - - if (sysfs_has_descriptors) - return 0; - - /* cache device descriptor in memory so that we can retrieve it later - * without waking the device up (op_get_device_descriptor) */ - - priv->dev_descriptor = NULL; - priv->config_descriptor = NULL; - - if (sysfs_can_relate_devices) { - int tmp = sysfs_get_active_config(dev, &active_config); - if (tmp < 0) - return tmp; - if (active_config == -1) - device_configured = 0; - } - - _get_usbfs_path(dev, path); - fd = open(path, O_RDWR); - if (fd < 0 && errno == EACCES) { - fd = open(path, O_RDONLY); - /* if we only have read-only access to the device, we cannot - * send a control message to determine the active config. just - * assume the first one is active. */ - active_config = -1; - } - - if (fd < 0) { - usbi_err(DEVICE_CTX(dev), "open failed, ret=%d errno=%d", fd, errno); - return LIBUSB_ERROR_IO; - } - - if (!sysfs_can_relate_devices) { - if (active_config == -1) { - /* if we only have read-only access to the device, we cannot - * send a control message to determine the active config. just - * assume the first one is active. */ - usbi_warn(DEVICE_CTX(dev), "access to %s is read-only; cannot " - "determine active configuration descriptor", path); - } else { - active_config = usbfs_get_active_config(dev, fd); - if (active_config == LIBUSB_ERROR_IO) { - /* buggy devices sometimes fail to report their active config. - * assume unconfigured and continue the probing */ - usbi_warn(DEVICE_CTX(dev), "couldn't query active " - "configuration, assumung unconfigured"); - device_configured = 0; - } else if (active_config < 0) { - close(fd); - return active_config; - } else if (active_config == 0) { - /* some buggy devices have a configuration 0, but we're - * reaching into the corner of a corner case here, so let's - * not support buggy devices in these circumstances. - * stick to the specs: a configuration value of 0 means - * unconfigured. */ - usbi_dbg("active cfg 0? assuming unconfigured device"); - device_configured = 0; - } - } - } - - dev_buf = malloc(DEVICE_DESC_LENGTH); - if (!dev_buf) { - close(fd); - return LIBUSB_ERROR_NO_MEM; - } - - r = read(fd, dev_buf, DEVICE_DESC_LENGTH); - if (r < 0) { - usbi_err(DEVICE_CTX(dev), - "read descriptor failed ret=%d errno=%d", fd, errno); - free(dev_buf); - close(fd); - return LIBUSB_ERROR_IO; - } else if (r < DEVICE_DESC_LENGTH) { - usbi_err(DEVICE_CTX(dev), "short descriptor read (%d)", r); - free(dev_buf); - close(fd); - return LIBUSB_ERROR_IO; - } - - /* bit of a hack: set num_configurations now because cache_active_config() - * calls usbi_get_config_index_by_value() which uses it */ - dev->num_configurations = dev_buf[DEVICE_DESC_LENGTH - 1]; - - if (device_configured) { - r = cache_active_config(dev, fd, active_config); - if (r < 0) { - close(fd); - free(dev_buf); - return r; - } - } - - close(fd); - priv->dev_descriptor = dev_buf; - return 0; -} - -static int enumerate_device(struct libusb_context *ctx, - struct discovered_devs **_discdevs, uint8_t busnum, uint8_t devaddr, - const char *sysfs_dir) -{ - struct discovered_devs *discdevs; - unsigned long session_id; - int need_unref = 0; - struct libusb_device *dev; - int r = 0; - - /* FIXME: session ID is not guaranteed unique as addresses can wrap and - * will be reused. instead we should add a simple sysfs attribute with - * a session ID. */ - session_id = busnum << 8 | devaddr; - usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr, - session_id); - - dev = usbi_get_device_by_session_id(ctx, session_id); - if (dev) { - usbi_dbg("using existing device for %d/%d (session %ld)", - busnum, devaddr, session_id); - } else { - usbi_dbg("allocating new device for %d/%d (session %ld)", - busnum, devaddr, session_id); - dev = usbi_alloc_device(ctx, session_id); - if (!dev) - return LIBUSB_ERROR_NO_MEM; - need_unref = 1; - r = initialize_device(dev, busnum, devaddr, sysfs_dir); - if (r < 0) - goto out; - r = usbi_sanitize_device(dev); - if (r < 0) - goto out; - } - - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) - r = LIBUSB_ERROR_NO_MEM; - else - *_discdevs = discdevs; - -out: - if (need_unref) - libusb_unref_device(dev); - return r; -} - -/* open a bus directory and adds all discovered devices to discdevs. on - * failure (non-zero return) the pre-existing discdevs should be destroyed - * (and devices freed). on success, the new discdevs pointer should be used - * as it may have been moved. */ -static int usbfs_scan_busdir(struct libusb_context *ctx, - struct discovered_devs **_discdevs, uint8_t busnum) -{ - DIR *dir; - char dirpath[PATH_MAX]; - struct dirent *entry; - struct discovered_devs *discdevs = *_discdevs; - int r = LIBUSB_ERROR_IO; - - snprintf(dirpath, PATH_MAX, "%s/%03d", usbfs_path, busnum); - usbi_dbg("%s", dirpath); - dir = opendir(dirpath); - if (!dir) { - usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno); - /* FIXME: should handle valid race conditions like hub unplugged - * during directory iteration - this is not an error */ - return r; - } - - while ((entry = readdir(dir))) { - int devaddr; - - if (entry->d_name[0] == '.') - continue; - - devaddr = atoi(entry->d_name); - if (devaddr == 0) { - usbi_dbg("unknown dir entry %s", entry->d_name); - continue; - } - - if (enumerate_device(ctx, &discdevs, busnum, (uint8_t) devaddr, NULL)) { - usbi_dbg("failed to enumerate dir entry %s", entry->d_name); - continue; - } - - r = 0; - } - - if (!r) - *_discdevs = discdevs; - closedir(dir); - return r; -} - -static int usbfs_get_device_list(struct libusb_context *ctx, - struct discovered_devs **_discdevs) -{ - struct dirent *entry; - DIR *buses = opendir(usbfs_path); - struct discovered_devs *discdevs = *_discdevs; - int r = 0; - - if (!buses) { - usbi_err(ctx, "opendir buses failed errno=%d", errno); - return LIBUSB_ERROR_IO; - } - - while ((entry = readdir(buses))) { - struct discovered_devs *discdevs_new = discdevs; - int busnum; - - if (entry->d_name[0] == '.') - continue; - - busnum = atoi(entry->d_name); - if (busnum == 0) { - usbi_dbg("unknown dir entry %s", entry->d_name); - continue; - } - - r = usbfs_scan_busdir(ctx, &discdevs_new, busnum); - if (r < 0) - goto out; - discdevs = discdevs_new; - } - -out: - closedir(buses); - *_discdevs = discdevs; - return r; - -} - -static int sysfs_scan_device(struct libusb_context *ctx, - struct discovered_devs **_discdevs, const char *devname) -{ - int busnum; - int devaddr; - - usbi_dbg("scan %s", devname); - - busnum = __read_sysfs_attr(ctx, devname, "busnum"); - if (busnum < 0) - return busnum; - - devaddr = __read_sysfs_attr(ctx, devname, "devnum"); - if (devaddr < 0) - return devaddr; - - usbi_dbg("bus=%d dev=%d", busnum, devaddr); - if (busnum > 255 || devaddr > 255) - return LIBUSB_ERROR_INVALID_PARAM; - - return enumerate_device(ctx, _discdevs, busnum & 0xff, devaddr & 0xff, - devname); -} - -static int sysfs_get_device_list(struct libusb_context *ctx, - struct discovered_devs **_discdevs) -{ - struct discovered_devs *discdevs = *_discdevs; - DIR *devices = opendir(SYSFS_DEVICE_PATH); - struct dirent *entry; - int r = LIBUSB_ERROR_IO; - - if (!devices) { - usbi_err(ctx, "opendir devices failed errno=%d", errno); - return r; - } - - while ((entry = readdir(devices))) { - struct discovered_devs *discdevs_new = discdevs; - - if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3)) - || strchr(entry->d_name, ':')) - continue; - - if (sysfs_scan_device(ctx, &discdevs_new, entry->d_name)) { - usbi_dbg("failed to enumerate dir entry %s", entry->d_name); - continue; - } - - r = 0; - discdevs = discdevs_new; - } - - if (!r) - *_discdevs = discdevs; - closedir(devices); - return r; -} - -static int op_get_device_list(struct libusb_context *ctx, - struct discovered_devs **_discdevs) -{ - /* we can retrieve device list and descriptors from sysfs or usbfs. - * sysfs is preferable, because if we use usbfs we end up resuming - * any autosuspended USB devices. however, sysfs is not available - * everywhere, so we need a usbfs fallback too. - * - * as described in the "sysfs vs usbfs" comment at the top of this - * file, sometimes we have sysfs but not enough information to - * relate sysfs devices to usbfs nodes. op_init() determines the - * adequacy of sysfs and sets sysfs_can_relate_devices. - */ - if (sysfs_can_relate_devices != 0) - return sysfs_get_device_list(ctx, _discdevs); - else - return usbfs_get_device_list(ctx, _discdevs); -} - -static int op_open(struct libusb_device_handle *handle) -{ - struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); - char filename[PATH_MAX]; - - _get_usbfs_path(handle->dev, filename); - usbi_dbg("opening %s", filename); - hpriv->fd = open(filename, O_RDWR); - if (hpriv->fd < 0) { - if (errno == EACCES) { - usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: " - "Permission denied.", filename); - usbi_err(HANDLE_CTX(handle), - "libusb requires write access to USB device nodes."); - return LIBUSB_ERROR_ACCESS; - } else if (errno == ENOENT) { - usbi_err(HANDLE_CTX(handle), "libusb couldn't open USB device %s: " - "No such file or directory.", filename); - return LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(HANDLE_CTX(handle), - "open failed, code %d errno %d", hpriv->fd, errno); - return LIBUSB_ERROR_IO; - } - } - - return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); -} - -static void op_close(struct libusb_device_handle *dev_handle) -{ - int fd = _device_handle_priv(dev_handle)->fd; - usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd); - close(fd); -} - -static int op_get_configuration(struct libusb_device_handle *handle, - int *config) -{ - int r; - if (sysfs_can_relate_devices != 1) - return LIBUSB_ERROR_NOT_SUPPORTED; - - r = sysfs_get_active_config(handle->dev, config); - if (r < 0) - return r; - - if (*config == -1) - *config = 0; - - return 0; -} - -static int op_set_configuration(struct libusb_device_handle *handle, int config) -{ - struct linux_device_priv *priv = _device_priv(handle->dev); - int fd = _device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_SETCONFIG, &config); - if (r) { - if (errno == EINVAL) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - if (!sysfs_has_descriptors) { - /* update our cached active config descriptor */ - if (config == -1) { - if (priv->config_descriptor) { - free(priv->config_descriptor); - priv->config_descriptor = NULL; - } - } else { - r = cache_active_config(handle->dev, fd, config); - if (r < 0) - usbi_warn(HANDLE_CTX(handle), - "failed to update cached config descriptor, error %d", r); - } - } - - return 0; -} - -static int op_claim_interface(struct libusb_device_handle *handle, int iface) -{ - int fd = _device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_CLAIMINTF, &iface); - if (r) { - if (errno == ENOENT) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "claim interface failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - return 0; -} - -static int op_release_interface(struct libusb_device_handle *handle, int iface) -{ - int fd = _device_handle_priv(handle)->fd; - int r = ioctl(fd, IOCTL_USBFS_RELEASEINTF, &iface); - if (r) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "release interface failed, error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - return 0; -} - -static int op_set_interface(struct libusb_device_handle *handle, int iface, - int altsetting) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_setinterface setintf; - int r; - - setintf.interface = iface; - setintf.altsetting = altsetting; - r = ioctl(fd, IOCTL_USBFS_SETINTF, &setintf); - if (r) { - if (errno == EINVAL) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "setintf failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_clear_halt(struct libusb_device_handle *handle, - unsigned char endpoint) -{ - int fd = _device_handle_priv(handle)->fd; - unsigned int _endpoint = endpoint; - int r = ioctl(fd, IOCTL_USBFS_CLEAR_HALT, &_endpoint); - if (r) { - if (errno == ENOENT) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "clear_halt failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_reset_device(struct libusb_device_handle *handle) -{ - int fd = _device_handle_priv(handle)->fd; - int i, r, ret = 0; - - /* Doing a device reset will cause the usbfs driver to get unbound - from any interfaces it is bound to. By voluntarily unbinding - the usbfs driver ourself, we stop the kernel from rebinding - the interface after reset (which would end up with the interface - getting bound to the in kernel driver if any). */ - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (handle->claimed_interfaces & (1L << i)) { - op_release_interface(handle, i); - } - } - - usbi_mutex_lock(&handle->lock); - r = ioctl(fd, IOCTL_USBFS_RESET, NULL); - if (r) { - if (errno == ENODEV) { - ret = LIBUSB_ERROR_NOT_FOUND; - goto out; - } - - usbi_err(HANDLE_CTX(handle), - "reset failed error %d errno %d", r, errno); - ret = LIBUSB_ERROR_OTHER; - goto out; - } - - /* And re-claim any interfaces which were claimed before the reset */ - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (handle->claimed_interfaces & (1L << i)) { - r = op_claim_interface(handle, i); - if (r) { - usbi_warn(HANDLE_CTX(handle), - "failed to re-claim interface %d after reset", i); - handle->claimed_interfaces &= ~(1L << i); - } - } - } -out: - usbi_mutex_unlock(&handle->lock); - return ret; -} - -static int op_kernel_driver_active(struct libusb_device_handle *handle, - int interface) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_getdriver getdrv; - int r; - - getdrv.interface = interface; - r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv); - if (r) { - if (errno == ENODATA) - return 0; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "get driver failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 1; -} - -static int op_detach_kernel_driver(struct libusb_device_handle *handle, - int interface) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_ioctl command; - int r; - - command.ifno = interface; - command.ioctl_code = IOCTL_USBFS_DISCONNECT; - command.data = NULL; - - r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); - if (r) { - if (errno == ENODATA) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EINVAL) - return LIBUSB_ERROR_INVALID_PARAM; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), - "detach failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } - - return 0; -} - -static int op_attach_kernel_driver(struct libusb_device_handle *handle, - int interface) -{ - int fd = _device_handle_priv(handle)->fd; - struct usbfs_ioctl command; - int r; - - command.ifno = interface; - command.ioctl_code = IOCTL_USBFS_CONNECT; - command.data = NULL; - - r = ioctl(fd, IOCTL_USBFS_IOCTL, &command); - if (r < 0) { - if (errno == ENODATA) - return LIBUSB_ERROR_NOT_FOUND; - else if (errno == EINVAL) - return LIBUSB_ERROR_INVALID_PARAM; - else if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - else if (errno == EBUSY) - return LIBUSB_ERROR_BUSY; - - usbi_err(HANDLE_CTX(handle), - "attach failed error %d errno %d", r, errno); - return LIBUSB_ERROR_OTHER; - } else if (r == 0) { - return LIBUSB_ERROR_NOT_FOUND; - } - - return 0; -} - -static void op_destroy_device(struct libusb_device *dev) -{ - struct linux_device_priv *priv = _device_priv(dev); - if (!sysfs_has_descriptors) { - if (priv->dev_descriptor) - free(priv->dev_descriptor); - if (priv->config_descriptor) - free(priv->config_descriptor); - } - if (priv->sysfs_dir) - free(priv->sysfs_dir); -} - -/* URBs are discarded in reverse order of submission to avoid races. */ -static int discard_urbs(struct usbi_transfer *itransfer, int first, int last_plus_one) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = - usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - int i, ret = 0; - struct usbfs_urb *urb; - - for (i = last_plus_one - 1; i >= first; i--) { - if (LIBUSB_TRANSFER_TYPE_ISOCHRONOUS == transfer->type) - urb = tpriv->iso_urbs[i]; - else - urb = &tpriv->urbs[i]; - - if (0 == ioctl(dpriv->fd, IOCTL_USBFS_DISCARDURB, urb)) - continue; - - if (EINVAL == errno) { - usbi_dbg("URB not found --> assuming ready to be reaped"); - ret = LIBUSB_ERROR_NOT_FOUND; - } else if (ENODEV == errno) { - usbi_dbg("Device not found for URB --> assuming ready to be reaped"); - ret = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised discard errno %d", errno); - ret = LIBUSB_ERROR_OTHER; - } - } - return ret; -} - -static void free_iso_urbs(struct linux_transfer_priv *tpriv) -{ - int i; - for (i = 0; i < tpriv->num_urbs; i++) { - struct usbfs_urb *urb = tpriv->iso_urbs[i]; - if (!urb) - break; - free(urb); - } - - free(tpriv->iso_urbs); - tpriv->iso_urbs = NULL; -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer, - unsigned char urb_type) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - struct usbfs_urb *urbs; - int is_out = (transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) - == LIBUSB_ENDPOINT_OUT; - int r; - int i; - size_t alloc_size; - - if (tpriv->urbs) - return LIBUSB_ERROR_BUSY; - - /* usbfs places a 16kb limit on bulk URBs. we divide up larger requests - * into smaller units to meet such restriction, then fire off all the - * units at once. it would be simpler if we just fired one unit at a time, - * but there is a big performance gain through doing it this way. */ - int num_urbs = transfer->length / MAX_BULK_BUFFER_LENGTH; - int last_urb_partial = 0; - - if (transfer->length == 0) { - num_urbs = 1; - } else if ((transfer->length % MAX_BULK_BUFFER_LENGTH) > 0) { - last_urb_partial = 1; - num_urbs++; - } - usbi_dbg("need %d urbs for new transfer with length %d", num_urbs, - transfer->length); - alloc_size = num_urbs * sizeof(struct usbfs_urb); - urbs = malloc(alloc_size); - if (!urbs) - return LIBUSB_ERROR_NO_MEM; - memset(urbs, 0, alloc_size); - tpriv->urbs = urbs; - tpriv->num_urbs = num_urbs; - tpriv->num_retired = 0; - tpriv->reap_action = NORMAL; - tpriv->reap_status = LIBUSB_TRANSFER_COMPLETED; - - for (i = 0; i < num_urbs; i++) { - struct usbfs_urb *urb = &urbs[i]; - urb->usercontext = itransfer; - urb->type = urb_type; - urb->endpoint = transfer->endpoint; - urb->buffer = transfer->buffer + (i * MAX_BULK_BUFFER_LENGTH); - if (supports_flag_bulk_continuation && !is_out) - urb->flags = USBFS_URB_SHORT_NOT_OK; - if (i == num_urbs - 1 && last_urb_partial) - urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH; - else if (transfer->length == 0) - urb->buffer_length = 0; - else - urb->buffer_length = MAX_BULK_BUFFER_LENGTH; - - if (i > 0 && supports_flag_bulk_continuation) - urb->flags |= USBFS_URB_BULK_CONTINUATION; - - r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); - if (r < 0) { - if (errno == ENODEV) { - r = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - r = LIBUSB_ERROR_IO; - } - - /* if the first URB submission fails, we can simply free up and - * return failure immediately. */ - if (i == 0) { - usbi_dbg("first URB failed, easy peasy"); - free(urbs); - tpriv->urbs = NULL; - return r; - } - - /* if it's not the first URB that failed, the situation is a bit - * tricky. we may need to discard all previous URBs. there are - * complications: - * - discarding is asynchronous - discarded urbs will be reaped - * later. the user must not have freed the transfer when the - * discarded URBs are reaped, otherwise libusb will be using - * freed memory. - * - the earlier URBs may have completed successfully and we do - * not want to throw away any data. - * - this URB failing may be no error; EREMOTEIO means that - * this transfer simply didn't need all the URBs we submitted - * so, we report that the transfer was submitted successfully and - * in case of error we discard all previous URBs. later when - * the final reap completes we can report error to the user, - * or success if an earlier URB was completed successfully. - */ - tpriv->reap_action = EREMOTEIO == errno ? COMPLETED_EARLY : SUBMIT_FAILED; - - /* The URBs we haven't submitted yet we count as already - * retired. */ - tpriv->num_retired += num_urbs - i; - - /* If we completed short then don't try to discard. */ - if (COMPLETED_EARLY == tpriv->reap_action) - return 0; - - discard_urbs(itransfer, 0, i); - - usbi_dbg("reporting successful submission but waiting for %d " - "discards before reporting error", i); - return 0; - } - } - - return 0; -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - struct usbfs_urb **urbs; - size_t alloc_size; - int num_packets = transfer->num_iso_packets; - int i; - int this_urb_len = 0; - int num_urbs = 1; - int packet_offset = 0; - unsigned int packet_len; - unsigned char *urb_buffer = transfer->buffer; - - if (tpriv->iso_urbs) - return LIBUSB_ERROR_BUSY; - - /* usbfs places a 32kb limit on iso URBs. we divide up larger requests - * into smaller units to meet such restriction, then fire off all the - * units at once. it would be simpler if we just fired one unit at a time, - * but there is a big performance gain through doing it this way. */ - - /* calculate how many URBs we need */ - for (i = 0; i < num_packets; i++) { - int space_remaining = MAX_ISO_BUFFER_LENGTH - this_urb_len; - packet_len = transfer->iso_packet_desc[i].length; - - if (packet_len > space_remaining) { - num_urbs++; - this_urb_len = packet_len; - } else { - this_urb_len += packet_len; - } - } - usbi_dbg("need %d 32k URBs for transfer", num_urbs); - - alloc_size = num_urbs * sizeof(*urbs); - urbs = malloc(alloc_size); - if (!urbs) - return LIBUSB_ERROR_NO_MEM; - memset(urbs, 0, alloc_size); - - tpriv->iso_urbs = urbs; - tpriv->num_urbs = num_urbs; - tpriv->num_retired = 0; - tpriv->reap_action = NORMAL; - tpriv->iso_packet_offset = 0; - - /* allocate + initialize each URB with the correct number of packets */ - for (i = 0; i < num_urbs; i++) { - struct usbfs_urb *urb; - int space_remaining_in_urb = MAX_ISO_BUFFER_LENGTH; - int urb_packet_offset = 0; - unsigned char *urb_buffer_orig = urb_buffer; - int j; - int k; - - /* swallow up all the packets we can fit into this URB */ - while (packet_offset < transfer->num_iso_packets) { - packet_len = transfer->iso_packet_desc[packet_offset].length; - if (packet_len <= space_remaining_in_urb) { - /* throw it in */ - urb_packet_offset++; - packet_offset++; - space_remaining_in_urb -= packet_len; - urb_buffer += packet_len; - } else { - /* it can't fit, save it for the next URB */ - break; - } - } - - alloc_size = sizeof(*urb) - + (urb_packet_offset * sizeof(struct usbfs_iso_packet_desc)); - urb = malloc(alloc_size); - if (!urb) { - free_iso_urbs(tpriv); - return LIBUSB_ERROR_NO_MEM; - } - memset(urb, 0, alloc_size); - urbs[i] = urb; - - /* populate packet lengths */ - for (j = 0, k = packet_offset - urb_packet_offset; - k < packet_offset; k++, j++) { - packet_len = transfer->iso_packet_desc[k].length; - urb->iso_frame_desc[j].length = packet_len; - } - - urb->usercontext = itransfer; - urb->type = USBFS_URB_TYPE_ISO; - /* FIXME: interface for non-ASAP data? */ - urb->flags = USBFS_URB_ISO_ASAP; - urb->endpoint = transfer->endpoint; - urb->number_of_packets = urb_packet_offset; - urb->buffer = urb_buffer_orig; - } - - /* submit URBs */ - for (i = 0; i < num_urbs; i++) { - int r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urbs[i]); - if (r < 0) { - if (errno == ENODEV) { - r = LIBUSB_ERROR_NO_DEVICE; - } else { - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - r = LIBUSB_ERROR_IO; - } - - /* if the first URB submission fails, we can simply free up and - * return failure immediately. */ - if (i == 0) { - usbi_dbg("first URB failed, easy peasy"); - free_iso_urbs(tpriv); - return r; - } - - /* if it's not the first URB that failed, the situation is a bit - * tricky. we must discard all previous URBs. there are - * complications: - * - discarding is asynchronous - discarded urbs will be reaped - * later. the user must not have freed the transfer when the - * discarded URBs are reaped, otherwise libusb will be using - * freed memory. - * - the earlier URBs may have completed successfully and we do - * not want to throw away any data. - * so, in this case we discard all the previous URBs BUT we report - * that the transfer was submitted successfully. then later when - * the final discard completes we can report error to the user. - */ - tpriv->reap_action = SUBMIT_FAILED; - - /* The URBs we haven't submitted yet we count as already - * retired. */ - tpriv->num_retired = num_urbs - i; - discard_urbs(itransfer, 0, i); - - usbi_dbg("reporting successful submission but waiting for %d " - "discards before reporting error", i); - return 0; - } - } - - return 0; -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_device_handle_priv *dpriv = - _device_handle_priv(transfer->dev_handle); - struct usbfs_urb *urb; - int r; - - if (tpriv->urbs) - return LIBUSB_ERROR_BUSY; - - if (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - urb = malloc(sizeof(struct usbfs_urb)); - if (!urb) - return LIBUSB_ERROR_NO_MEM; - memset(urb, 0, sizeof(struct usbfs_urb)); - tpriv->urbs = urb; - tpriv->num_urbs = 1; - tpriv->reap_action = NORMAL; - - urb->usercontext = itransfer; - urb->type = USBFS_URB_TYPE_CONTROL; - urb->endpoint = transfer->endpoint; - urb->buffer = transfer->buffer; - urb->buffer_length = transfer->length; - - r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb); - if (r < 0) { - free(urb); - tpriv->urbs = NULL; - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(TRANSFER_CTX(transfer), - "submiturb failed error %d errno=%d", r, errno); - return LIBUSB_ERROR_IO; - } - return 0; -} - -static int op_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_BULK); - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer, USBFS_URB_TYPE_INTERRUPT); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int op_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_BULK: - if (tpriv->reap_action == ERROR) - break; - /* else, fall through */ - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - tpriv->reap_action = CANCELLED; - break; - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } - - if (!tpriv->urbs) - return LIBUSB_ERROR_NOT_FOUND; - - return discard_urbs(itransfer, 0, tpriv->num_urbs); -} - -static void op_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - - /* urbs can be freed also in submit_transfer so lock mutex first */ - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - usbi_mutex_lock(&itransfer->lock); - if (tpriv->urbs) - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - break; - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - usbi_mutex_lock(&itransfer->lock); - if (tpriv->iso_urbs) - free_iso_urbs(tpriv); - usbi_mutex_unlock(&itransfer->lock); - break; - default: - usbi_err(TRANSFER_CTX(transfer), - "unknown endpoint type %d", transfer->type); - } -} - -static int handle_bulk_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - int urb_idx = urb - tpriv->urbs; - - usbi_mutex_lock(&itransfer->lock); - usbi_dbg("handling completion status %d of bulk urb %d/%d", urb->status, - urb_idx + 1, tpriv->num_urbs); - - tpriv->num_retired++; - - if (tpriv->reap_action != NORMAL) { - /* cancelled, submit_fail, or completed early */ - usbi_dbg("abnormal reap: urb status %d", urb->status); - - /* even though we're in the process of cancelling, it's possible that - * we may receive some data in these URBs that we don't want to lose. - * examples: - * 1. while the kernel is cancelling all the packets that make up an - * URB, a few of them might complete. so we get back a successful - * cancellation *and* some data. - * 2. we receive a short URB which marks the early completion condition, - * so we start cancelling the remaining URBs. however, we're too - * slow and another URB completes (or at least completes partially). - * (this can't happen since we always use BULK_CONTINUATION.) - * - * When this happens, our objectives are not to lose any "surplus" data, - * and also to stick it at the end of the previously-received data - * (closing any holes), so that libusb reports the total amount of - * transferred data and presents it in a contiguous chunk. - */ - if (urb->actual_length > 0) { - unsigned char *target = transfer->buffer + itransfer->transferred; - usbi_dbg("received %d bytes of surplus data", urb->actual_length); - if (urb->buffer != target) { - usbi_dbg("moving surplus data from offset %d to offset %d", - (unsigned char *) urb->buffer - transfer->buffer, - target - transfer->buffer); - memmove(target, urb->buffer, urb->actual_length); - } - itransfer->transferred += urb->actual_length; - } - - if (tpriv->num_retired == tpriv->num_urbs) { - usbi_dbg("abnormal reap: last URB handled, reporting"); - if (tpriv->reap_action != COMPLETED_EARLY && - tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - goto completed; - } - goto out_unlock; - } - - itransfer->transferred += urb->actual_length; - - /* Many of these errors can occur on *any* urb of a multi-urb - * transfer. When they do, we tear down the rest of the transfer. - */ - switch (urb->status) { - case 0: - break; - case -EREMOTEIO: /* short transfer */ - break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: - break; - case -ESHUTDOWN: - usbi_dbg("device removed"); - tpriv->reap_status = LIBUSB_TRANSFER_NO_DEVICE; - goto cancel_remaining; - case -EPIPE: - usbi_dbg("detected endpoint stall"); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_STALL; - goto cancel_remaining; - case -EOVERFLOW: - /* overflow can only ever occur in the last urb */ - usbi_dbg("overflow, actual_length=%d", urb->actual_length); - if (tpriv->reap_status == LIBUSB_TRANSFER_COMPLETED) - tpriv->reap_status = LIBUSB_TRANSFER_OVERFLOW; - goto completed; - case -ETIME: - case -EPROTO: - case -EILSEQ: - usbi_dbg("low level error %d", urb->status); - tpriv->reap_action = ERROR; - goto cancel_remaining; - default: - usbi_warn(ITRANSFER_CTX(itransfer), - "unrecognised urb status %d", urb->status); - tpriv->reap_action = ERROR; - goto cancel_remaining; - } - - /* if we're the last urb or we got less data than requested then we're - * done */ - if (urb_idx == tpriv->num_urbs - 1) { - usbi_dbg("last URB in transfer --> complete!"); - goto completed; - } else if (urb->actual_length < urb->buffer_length) { - usbi_dbg("short transfer %d/%d --> complete!", - urb->actual_length, urb->buffer_length); - if (tpriv->reap_action == NORMAL) - tpriv->reap_action = COMPLETED_EARLY; - } else - goto out_unlock; - -cancel_remaining: - if (ERROR == tpriv->reap_action && LIBUSB_TRANSFER_COMPLETED == tpriv->reap_status) - tpriv->reap_status = LIBUSB_TRANSFER_ERROR; - - if (tpriv->num_retired == tpriv->num_urbs) /* nothing to cancel */ - goto completed; - - /* cancel remaining urbs and wait for their completion before - * reporting results */ - discard_urbs(itransfer, urb_idx + 1, tpriv->num_urbs); - -out_unlock: - usbi_mutex_unlock(&itransfer->lock); - return 0; - -completed: - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return CANCELLED == tpriv->reap_action ? - usbi_handle_transfer_cancellation(itransfer) : - usbi_handle_transfer_completion(itransfer, tpriv->reap_status); -} - -static int handle_iso_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct libusb_transfer *transfer = - USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int num_urbs = tpriv->num_urbs; - int urb_idx = 0; - int i; - enum libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED; - - usbi_mutex_lock(&itransfer->lock); - for (i = 0; i < num_urbs; i++) { - if (urb == tpriv->iso_urbs[i]) { - urb_idx = i + 1; - break; - } - } - if (urb_idx == 0) { - usbi_err(TRANSFER_CTX(transfer), "could not locate urb!"); - usbi_mutex_unlock(&itransfer->lock); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("handling completion status %d of iso urb %d/%d", urb->status, - urb_idx, num_urbs); - - /* copy isochronous results back in */ - - for (i = 0; i < urb->number_of_packets; i++) { - struct usbfs_iso_packet_desc *urb_desc = &urb->iso_frame_desc[i]; - struct libusb_iso_packet_descriptor *lib_desc = - &transfer->iso_packet_desc[tpriv->iso_packet_offset++]; - lib_desc->status = urb_desc->status; - lib_desc->actual_length = urb_desc->actual_length; - } - - tpriv->num_retired++; - - if (tpriv->reap_action != NORMAL) { /* cancelled or submit_fail */ - usbi_dbg("CANCEL: urb status %d", urb->status); - - if (status == LIBUSB_TRANSFER_COMPLETED) - status = LIBUSB_TRANSFER_ERROR; - - if (tpriv->num_retired == num_urbs) { - usbi_dbg("CANCEL: last URB handled, reporting"); - free_iso_urbs(tpriv); - if (tpriv->reap_action == CANCELLED) { - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_cancellation(itransfer); - } else { - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, - LIBUSB_TRANSFER_ERROR); - } - } - goto out; - } - - switch (urb->status) { - case 0: - break; - case -ENOENT: /* cancelled */ - break; - case -ESHUTDOWN: - usbi_dbg("device removed"); - status = LIBUSB_TRANSFER_NO_DEVICE; - break; - case -ETIME: - case -EPROTO: - case -EILSEQ: - usbi_dbg("low-level USB error %d", urb->status); - break; - default: - usbi_warn(TRANSFER_CTX(transfer), - "unrecognised urb status %d", urb->status); - break; - } - - /* if we're the last urb or we got less data than requested then we're - * done */ - if (urb_idx == num_urbs) { - usbi_dbg("last URB in transfer --> complete!"); - free_iso_urbs(tpriv); - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, status); - } - -out: - usbi_mutex_unlock(&itransfer->lock); - return 0; -} - -static int handle_control_completion(struct usbi_transfer *itransfer, - struct usbfs_urb *urb) -{ - struct linux_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer); - int status; - - usbi_mutex_lock(&itransfer->lock); - usbi_dbg("handling completion status %d", urb->status); - - itransfer->transferred += urb->actual_length; - - if (tpriv->reap_action == CANCELLED) { - if (urb->status != 0 && urb->status != -ENOENT) - usbi_warn(ITRANSFER_CTX(itransfer), - "cancel: unrecognised urb status %d", urb->status); - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_cancellation(itransfer); - } - - switch (urb->status) { - case 0: - status = LIBUSB_TRANSFER_COMPLETED; - break; - case -ENOENT: /* cancelled */ - status = LIBUSB_TRANSFER_CANCELLED; - break; - case -ESHUTDOWN: - usbi_dbg("device removed"); - status = LIBUSB_TRANSFER_NO_DEVICE; - break; - case -EPIPE: - usbi_dbg("unsupported control request"); - status = LIBUSB_TRANSFER_STALL; - break; - case -ETIME: - case -EPROTO: - case -EILSEQ: - usbi_dbg("low-level bus error occurred"); - status = LIBUSB_TRANSFER_ERROR; - break; - default: - usbi_warn(ITRANSFER_CTX(itransfer), - "unrecognised urb status %d", urb->status); - status = LIBUSB_TRANSFER_ERROR; - break; - } - - free(tpriv->urbs); - tpriv->urbs = NULL; - usbi_mutex_unlock(&itransfer->lock); - return usbi_handle_transfer_completion(itransfer, status); -} - -static int reap_for_handle(struct libusb_device_handle *handle) -{ - struct linux_device_handle_priv *hpriv = _device_handle_priv(handle); - int r; - struct usbfs_urb *urb; - struct usbi_transfer *itransfer; - struct libusb_transfer *transfer; - - r = ioctl(hpriv->fd, IOCTL_USBFS_REAPURBNDELAY, &urb); - if (r == -1 && errno == EAGAIN) - return 1; - if (r < 0) { - if (errno == ENODEV) - return LIBUSB_ERROR_NO_DEVICE; - - usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d", - r, errno); - return LIBUSB_ERROR_IO; - } - - itransfer = urb->usercontext; - transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - usbi_dbg("urb type=%d status=%d transferred=%d", urb->type, urb->status, - urb->actual_length); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return handle_iso_completion(itransfer, urb); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return handle_bulk_completion(itransfer, urb); - case LIBUSB_TRANSFER_TYPE_CONTROL: - return handle_control_completion(itransfer, urb); - default: - usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x", - transfer->type); - return LIBUSB_ERROR_OTHER; - } -} - -static int op_handle_events(struct libusb_context *ctx, - struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) -{ - int r; - int i = 0; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - struct pollfd *pollfd = &fds[i]; - struct libusb_device_handle *handle; - struct linux_device_handle_priv *hpriv = NULL; - - if (!pollfd->revents) - continue; - - num_ready--; - list_for_each_entry(handle, &ctx->open_devs, list, struct libusb_device_handle) { - hpriv = _device_handle_priv(handle); - if (hpriv->fd == pollfd->fd) - break; - } - - if (pollfd->revents & POLLERR) { - usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); - usbi_handle_disconnect(handle); - continue; - } - - r = reap_for_handle(handle); - if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE) - continue; - else if (r < 0) - goto out; - } - - r = 0; -out: - usbi_mutex_unlock(&ctx->open_devs_lock); - return r; -} - -static int op_clock_gettime(int clk_id, struct timespec *tp) -{ - switch (clk_id) { - case USBI_CLOCK_MONOTONIC: - return clock_gettime(monotonic_clkid, tp); - case USBI_CLOCK_REALTIME: - return clock_gettime(CLOCK_REALTIME, tp); - default: - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -#ifdef USBI_TIMERFD_AVAILABLE -static clockid_t op_get_timerfd_clockid(void) -{ - return monotonic_clkid; - -} -#endif - -const struct usbi_os_backend linux_usbfs_backend = { - .name = "Linux usbfs", - .init = op_init, - .exit = NULL, - .get_device_list = op_get_device_list, - .get_device_descriptor = op_get_device_descriptor, - .get_active_config_descriptor = op_get_active_config_descriptor, - .get_config_descriptor = op_get_config_descriptor, - - .open = op_open, - .close = op_close, - .get_configuration = op_get_configuration, - .set_configuration = op_set_configuration, - .claim_interface = op_claim_interface, - .release_interface = op_release_interface, - - .set_interface_altsetting = op_set_interface, - .clear_halt = op_clear_halt, - .reset_device = op_reset_device, - - .kernel_driver_active = op_kernel_driver_active, - .detach_kernel_driver = op_detach_kernel_driver, - .attach_kernel_driver = op_attach_kernel_driver, - - .destroy_device = op_destroy_device, - - .submit_transfer = op_submit_transfer, - .cancel_transfer = op_cancel_transfer, - .clear_transfer_priv = op_clear_transfer_priv, - - .handle_events = op_handle_events, - - .clock_gettime = op_clock_gettime, - -#ifdef USBI_TIMERFD_AVAILABLE - .get_timerfd_clockid = op_get_timerfd_clockid, -#endif - - .device_priv_size = sizeof(struct linux_device_priv), - .device_handle_priv_size = sizeof(struct linux_device_handle_priv), - .transfer_priv_size = sizeof(struct linux_transfer_priv), - .add_iso_packet_size = 0, -}; - diff --git a/third_party/libusb/libusb/os/linux_usbfs.h b/third_party/libusb/libusb/os/linux_usbfs.h deleted file mode 100644 index 93e7f31..0000000 --- a/third_party/libusb/libusb/os/linux_usbfs.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * usbfs header structures - * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> - * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_USBFS_H -#define LIBUSB_USBFS_H - -#define SYSFS_DEVICE_PATH "/sys/bus/usb/devices" - -struct usbfs_ctrltransfer { - /* keep in sync with usbdevice_fs.h:usbdevfs_ctrltransfer */ - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - - uint32_t timeout; /* in milliseconds */ - - /* pointer to data */ - void *data; -}; - -struct usbfs_bulktransfer { - /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ - unsigned int ep; - unsigned int len; - unsigned int timeout; /* in milliseconds */ - - /* pointer to data */ - void *data; -}; - -struct usbfs_setinterface { - /* keep in sync with usbdevice_fs.h:usbdevfs_setinterface */ - unsigned int interface; - unsigned int altsetting; -}; - -#define USBFS_MAXDRIVERNAME 255 - -struct usbfs_getdriver { - unsigned int interface; - char driver[USBFS_MAXDRIVERNAME + 1]; -}; - -#define USBFS_URB_SHORT_NOT_OK 0x01 -#define USBFS_URB_ISO_ASAP 0x02 -#define USBFS_URB_BULK_CONTINUATION 0x04 -#define USBFS_URB_QUEUE_BULK 0x10 - -enum usbfs_urb_type { - USBFS_URB_TYPE_ISO = 0, - USBFS_URB_TYPE_INTERRUPT = 1, - USBFS_URB_TYPE_CONTROL = 2, - USBFS_URB_TYPE_BULK = 3, -}; - -struct usbfs_iso_packet_desc { - unsigned int length; - unsigned int actual_length; - unsigned int status; -}; - -#define MAX_ISO_BUFFER_LENGTH 32768 -#define MAX_BULK_BUFFER_LENGTH 16384 -#define MAX_CTRL_BUFFER_LENGTH 4096 - -struct usbfs_urb { - unsigned char type; - unsigned char endpoint; - int status; - unsigned int flags; - void *buffer; - int buffer_length; - int actual_length; - int start_frame; - int number_of_packets; - int error_count; - unsigned int signr; - void *usercontext; - struct usbfs_iso_packet_desc iso_frame_desc[0]; -}; - -struct usbfs_connectinfo { - unsigned int devnum; - unsigned char slow; -}; - -struct usbfs_ioctl { - int ifno; /* interface 0..N ; negative numbers reserved */ - int ioctl_code; /* MUST encode size + direction of data so the - * macros in <asm/ioctl.h> give correct values */ - void *data; /* param buffer (in, or out) */ -}; - -struct usbfs_hub_portinfo { - unsigned char numports; - unsigned char port[127]; /* port to device num mapping */ -}; - -#define IOCTL_USBFS_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) -#define IOCTL_USBFS_BULK _IOWR('U', 2, struct usbfs_bulktransfer) -#define IOCTL_USBFS_RESETEP _IOR('U', 3, unsigned int) -#define IOCTL_USBFS_SETINTF _IOR('U', 4, struct usbfs_setinterface) -#define IOCTL_USBFS_SETCONFIG _IOR('U', 5, unsigned int) -#define IOCTL_USBFS_GETDRIVER _IOW('U', 8, struct usbfs_getdriver) -#define IOCTL_USBFS_SUBMITURB _IOR('U', 10, struct usbfs_urb) -#define IOCTL_USBFS_DISCARDURB _IO('U', 11) -#define IOCTL_USBFS_REAPURB _IOW('U', 12, void *) -#define IOCTL_USBFS_REAPURBNDELAY _IOW('U', 13, void *) -#define IOCTL_USBFS_CLAIMINTF _IOR('U', 15, unsigned int) -#define IOCTL_USBFS_RELEASEINTF _IOR('U', 16, unsigned int) -#define IOCTL_USBFS_CONNECTINFO _IOW('U', 17, struct usbfs_connectinfo) -#define IOCTL_USBFS_IOCTL _IOWR('U', 18, struct usbfs_ioctl) -#define IOCTL_USBFS_HUB_PORTINFO _IOR('U', 19, struct usbfs_hub_portinfo) -#define IOCTL_USBFS_RESET _IO('U', 20) -#define IOCTL_USBFS_CLEAR_HALT _IOR('U', 21, unsigned int) -#define IOCTL_USBFS_DISCONNECT _IO('U', 22) -#define IOCTL_USBFS_CONNECT _IO('U', 23) - -#endif diff --git a/third_party/libusb/libusb/os/poll_posix.h b/third_party/libusb/libusb/os/poll_posix.h deleted file mode 100644 index 0e5e7f5b..0000000 --- a/third_party/libusb/libusb/os/poll_posix.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef LIBUSB_POLL_POSIX_H -#define LIBUSB_POLL_POSIX_H - -#define usbi_write write -#define usbi_read read -#define usbi_close close -#define usbi_pipe pipe -#define usbi_poll poll - -#endif /* LIBUSB_POLL_POSIX_H */ diff --git a/third_party/libusb/libusb/os/poll_windows.c b/third_party/libusb/libusb/os/poll_windows.c deleted file mode 100644 index c997c81..0000000 --- a/third_party/libusb/libusb/os/poll_windows.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * poll_windows: poll compatibility wrapper for Windows - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -/* - * poll() and pipe() Windows compatibility layer for libusb 1.0 - * - * The way this layer works is by using OVERLAPPED with async I/O transfers, as - * OVERLAPPED have an associated event which is flagged for I/O completion. - * - * For USB pollable async I/O, you would typically: - * - obtain a Windows HANDLE to a file or device that has been opened in - * OVERLAPPED mode - * - call usbi_create_fd with this handle to obtain a custom fd. - * Note that if you need simultaneous R/W access, you need to call create_fd - * twice, once in _O_RDONLY and once in _O_WRONLY mode to obtain 2 separate - * pollable fds - * - leave the core functions call the poll routine and flag POLLIN/POLLOUT - * - * The pipe pollable synchronous I/O works using the overlapped event associated - * with a fake pipe. The read/write functions are only meant to be used in that - * context. - */ -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <io.h> - -#include <libusbi.h> - -// Uncomment to debug the polling layer -//#define DEBUG_POLL_WINDOWS -#if defined(DEBUG_POLL_WINDOWS) -#define poll_dbg usbi_dbg -#else -// MSVC6 cannot use a variadic argument and non MSVC -// compilers produce warnings if parenthesis are ommitted. -#if defined(_MSC_VER) -#define poll_dbg -#else -#define poll_dbg(...) -#endif -#endif - -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -#if defined(__CYGWIN__) -// cygwin produces a warning unless these prototypes are defined -extern int _open(char* name, int flags); -extern int _close(int fd); -extern int _snprintf(char *buffer, size_t count, const char *format, ...); -#define NUL_DEVICE "/dev/null" -#else -#define NUL_DEVICE "NUL" -#endif - -#define CHECK_INIT_POLLING do {if(!is_polling_set) init_polling();} while(0) - -// public fd data -const struct winfd INVALID_WINFD = {-1, INVALID_HANDLE_VALUE, NULL, RW_NONE}; -struct winfd poll_fd[MAX_FDS]; -// internal fd data -struct { - CRITICAL_SECTION mutex; // lock for fds - // Additional variables for XP CancelIoEx partial emulation - HANDLE original_handle; - DWORD thread_id; -} _poll_fd[MAX_FDS]; - -// globals -BOOLEAN is_polling_set = FALSE; -#if defined(DYNAMIC_FDS) -HANDLE fd_update = INVALID_HANDLE_VALUE; // event to notify poll of fd update -HANDLE new_fd[MAX_FDS]; // overlapped event handles for fds created since last poll -unsigned nb_new_fds = 0; // nb new fds created since last poll -usbi_mutex_t new_fd_mutex; // mutex required for the above -#endif -LONG pipe_number = 0; -static volatile LONG compat_spinlock = 0; - -// CancelIoEx, available on Vista and later only, provides the ability to cancel -// a single transfer (OVERLAPPED) when used. As it may not be part of any of the -// platform headers, we hook into the Kernel32 system DLL directly to seek it. -static BOOL (__stdcall *pCancelIoEx)(HANDLE, LPOVERLAPPED) = NULL; -#define CancelIoEx_Available (pCancelIoEx != NULL) -static __inline BOOL cancel_io(int _index) -{ - if ((_index < 0) || (_index >= MAX_FDS)) { - return FALSE; - } - - if ( (poll_fd[_index].fd < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL) ) { - return TRUE; - } - if (CancelIoEx_Available) { - return (*pCancelIoEx)(poll_fd[_index].handle, poll_fd[_index].overlapped); - } - if (_poll_fd[_index].thread_id == GetCurrentThreadId()) { - return CancelIo(poll_fd[_index].handle); - } - usbi_warn(NULL, "Unable to cancel I/O that was started from another thread"); - return FALSE; -} - -// Init -void init_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (!is_polling_set) { - pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED)) - GetProcAddress(GetModuleHandleA("KERNEL32"), "CancelIoEx"); - usbi_dbg("Will use CancelIo%s for I/O cancellation", - CancelIoEx_Available?"Ex":""); - for (i=0; i<MAX_FDS; i++) { - poll_fd[i] = INVALID_WINFD; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[i].thread_id = 0; - InitializeCriticalSection(&_poll_fd[i].mutex); - } -#if defined(DYNAMIC_FDS) - // We need to create an update event so that poll is warned when there - // are new/deleted fds during a timeout wait operation - fd_update = CreateEvent(NULL, TRUE, FALSE, NULL); - if (fd_update == NULL) { - usbi_err(NULL, "unable to create update event"); - } - usbi_mutex_init(&new_fd_mutex, NULL); - nb_new_fds = 0; -#endif - is_polling_set = TRUE; - } - compat_spinlock = 0; -} - -// Internal function to retrieve the table index (and lock the fd mutex) -int _fd_to_index_and_lock(int fd) -{ - int i; - - if (fd <= 0) - return -1; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have changed before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - return i; - } - } - return -1; -} - -OVERLAPPED *create_overlapped(void) -{ - OVERLAPPED *overlapped = calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return NULL; - } - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(overlapped->hEvent == NULL) { - free (overlapped); - return NULL; - } - return overlapped; -} - -void free_overlapped(OVERLAPPED *overlapped) -{ - if (overlapped == NULL) - return; - - if ( (overlapped->hEvent != 0) - && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) { - CloseHandle(overlapped->hEvent); - } - free(overlapped); -} - -void reset_overlapped(OVERLAPPED *overlapped) -{ - HANDLE event_handle; - if (overlapped == NULL) - return; - - event_handle = overlapped->hEvent; - if (event_handle != NULL) { - ResetEvent(event_handle); - } - memset(overlapped, 0, sizeof(OVERLAPPED)); - overlapped->hEvent = event_handle; -} - -void exit_polling(void) -{ - int i; - - while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) { - SleepEx(0, TRUE); - } - if (is_polling_set) { - is_polling_set = FALSE; - - for (i=0; i<MAX_FDS; i++) { - // Cancel any async I/O (handle can be invalid) - cancel_io(i); - // If anything was pending on that I/O, it should be - // terminating, and we should be able to access the fd - // mutex lock before too long - EnterCriticalSection(&_poll_fd[i].mutex); - if ( (poll_fd[i].fd > 0) && (poll_fd[i].handle != INVALID_HANDLE_VALUE) && (poll_fd[i].handle != 0) - && (GetFileType(poll_fd[i].handle) == FILE_TYPE_UNKNOWN) ) { - _close(poll_fd[i].fd); - } - free_overlapped(poll_fd[i].overlapped); - if (!CancelIoEx_Available) { - // Close duplicate handle - if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[i].handle); - } - } - poll_fd[i] = INVALID_WINFD; -#if defined(DYNAMIC_FDS) - usbi_mutex_destroy(&new_fd_mutex); - CloseHandle(fd_update); - fd_update = INVALID_HANDLE_VALUE; -#endif - LeaveCriticalSection(&_poll_fd[i].mutex); - DeleteCriticalSection(&_poll_fd[i].mutex); - } - } - compat_spinlock = 0; -} - -/* - * Create a fake pipe. - * As libusb only uses pipes for signaling, all we need from a pipe is an - * event. To that extent, we create a single wfd and overlapped as a means - * to access that event. - */ -int usbi_pipe(int filedes[2]) -{ - int i; - OVERLAPPED* overlapped; - - CHECK_INIT_POLLING; - - overlapped = calloc(1, sizeof(OVERLAPPED)); - if (overlapped == NULL) { - return -1; - } - // The overlapped must have status pending for signaling to work in poll - overlapped->Internal = STATUS_PENDING; - overlapped->InternalHigh = 0; - - // Read end of the "pipe" - filedes[0] = _open(NUL_DEVICE, _O_WRONLY); - if (filedes[0] < 0) { - usbi_err(NULL, "could not create pipe: errno %d", errno); - goto out1; - } - // We can use the same handle for both ends - filedes[1] = filedes[0]; - poll_dbg("pipe filedes = %d", filedes[0]); - - // Note: manual reset must be true (second param) as the reset occurs in read - overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if(!overlapped->hEvent) { - goto out2; - } - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been allocated before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - - poll_fd[i].fd = filedes[0]; - poll_fd[i].handle = DUMMY_HANDLE; - poll_fd[i].overlapped = overlapped; - // There's no polling on the write end, so we just use READ for our needs - poll_fd[i].rw = RW_READ; - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - LeaveCriticalSection(&_poll_fd[i].mutex); - return 0; - } - } - - CloseHandle(overlapped->hEvent); -out2: - _close(filedes[0]); -out1: - free(overlapped); - return -1; -} - -/* - * Create both an fd and an OVERLAPPED from an open Windows handle, so that - * it can be used with our polling function - * The handle MUST support overlapped transfers (usually requires CreateFile - * with FILE_FLAG_OVERLAPPED) - * Return a pollable file descriptor struct, or INVALID_WINFD on error - * - * Note that the fd returned by this function is a per-transfer fd, rather - * than a per-session fd and cannot be used for anything else but our - * custom functions (the fd itself points to the NUL: device) - * if you plan to do R/W on the same handle, you MUST create 2 fds: one for - * read and one for write. Using a single R/W fd is unsupported and will - * produce unexpected results - */ -struct winfd usbi_create_fd(HANDLE handle, int access_mode) -{ - int i, fd; - struct winfd wfd = INVALID_WINFD; - OVERLAPPED* overlapped = NULL; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) { - return INVALID_WINFD; - } - - if ((access_mode != _O_RDONLY) && (access_mode != _O_WRONLY)) { - usbi_warn(NULL, "only one of _O_RDONLY or _O_WRONLY are supported.\n" - "If you want to poll for R/W simultaneously, create multiple fds from the same handle."); - return INVALID_WINFD; - } - if (access_mode == _O_RDONLY) { - wfd.rw = RW_READ; - } else { - wfd.rw = RW_WRITE; - } - - // Ensure that we get a non system conflicting unique fd, using - // the same fd attribution system as the pipe ends - fd = _open(NUL_DEVICE, _O_WRONLY); - if (fd < 0) { - return INVALID_WINFD; - } - - overlapped = create_overlapped(); - if(overlapped == NULL) { - _close(fd); - return INVALID_WINFD; - } - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd < 0) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been removed before we got to critical - if (poll_fd[i].fd >= 0) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - wfd.fd = fd; - // Attempt to emulate some of the CancelIoEx behaviour on platforms - // that don't have it - if (!CancelIoEx_Available) { - _poll_fd[i].thread_id = GetCurrentThreadId(); - if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), - &wfd.handle, 0, TRUE, DUPLICATE_SAME_ACCESS)) { - usbi_dbg("could not duplicate handle for CancelIo - using original one"); - wfd.handle = handle; - // Make sure we won't close the original handle on fd deletion then - _poll_fd[i].original_handle = INVALID_HANDLE_VALUE; - } else { - _poll_fd[i].original_handle = handle; - } - } else { - wfd.handle = handle; - } - wfd.overlapped = overlapped; - memcpy(&poll_fd[i], &wfd, sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); -#if defined(DYNAMIC_FDS) - usbi_mutex_lock(&new_fd_mutex); - new_fd[nb_new_fds++] = overlapped->hEvent; - usbi_mutex_unlock(&new_fd_mutex); - // Notify poll that fds have been updated - SetEvent(fd_update); -#endif - return wfd; - } - } - free_overlapped(overlapped); - _close(fd); - return INVALID_WINFD; -} - -void _free_index(int _index) -{ - // Cancel any async IO (Don't care about the validity of our handles for this) - cancel_io(_index); - // close fake handle for devices - if ( (poll_fd[_index].handle != INVALID_HANDLE_VALUE) && (poll_fd[_index].handle != 0) - && (GetFileType(poll_fd[_index].handle) == FILE_TYPE_UNKNOWN) ) { - _close(poll_fd[_index].fd); - } - // close the duplicate handle (if we have an actual duplicate) - if (!CancelIoEx_Available) { - if (_poll_fd[_index].original_handle != INVALID_HANDLE_VALUE) { - CloseHandle(poll_fd[_index].handle); - } - _poll_fd[_index].original_handle = INVALID_HANDLE_VALUE; - _poll_fd[_index].thread_id = 0; - } - free_overlapped(poll_fd[_index].overlapped); - poll_fd[_index] = INVALID_WINFD; -} - -/* - * Release a pollable file descriptor. - * - * Note that the associated Windows handle is not closed by this call - */ -void usbi_free_fd(int fd) -{ - int _index; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(fd); - if (_index < 0) { - return; - } - _free_index(_index); - LeaveCriticalSection(&_poll_fd[_index].mutex); -} - -/* - * The functions below perform various conversions between fd, handle and OVERLAPPED - */ -struct winfd fd_to_winfd(int fd) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (fd <= 0) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].fd == fd) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].fd != fd) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd handle_to_winfd(HANDLE handle) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].handle == handle) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].handle != handle) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped) -{ - int i; - struct winfd wfd; - - CHECK_INIT_POLLING; - - if (overlapped == NULL) - return INVALID_WINFD; - - for (i=0; i<MAX_FDS; i++) { - if (poll_fd[i].overlapped == overlapped) { - EnterCriticalSection(&_poll_fd[i].mutex); - // fd might have been deleted before we got to critical - if (poll_fd[i].overlapped != overlapped) { - LeaveCriticalSection(&_poll_fd[i].mutex); - continue; - } - memcpy(&wfd, &poll_fd[i], sizeof(struct winfd)); - LeaveCriticalSection(&_poll_fd[i].mutex); - return wfd; - } - } - return INVALID_WINFD; -} - -/* - * POSIX poll equivalent, using Windows OVERLAPPED - * Currently, this function only accepts one of POLLIN or POLLOUT per fd - * (but you can create multiple fds from the same handle for read and write) - */ -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout) -{ - unsigned i; - int _index, object_index, triggered; - HANDLE *handles_to_wait_on; - int *handle_to_index; - DWORD nb_handles_to_wait_on = 0; - DWORD ret; - -#if defined(DYNAMIC_FDS) - DWORD nb_extra_handles = 0; - unsigned j; - - // To address the possibility of missing new fds between the time the new - // pollable fd set is assembled, and the ResetEvent() call below, an - // additional new_fd[] HANDLE table is used for any new fd that was created - // since the last call to poll (see below) - ResetEvent(fd_update); - - // At this stage, any new fd creation will be detected through the fd_update - // event notification, and any previous creation that we may have missed - // will be picked up through the existing new_fd[] table. -#endif - - CHECK_INIT_POLLING; - - triggered = 0; - handles_to_wait_on = malloc((nfds+1)*sizeof(HANDLE)); // +1 for fd_update - handle_to_index = malloc(nfds*sizeof(int)); - if ((handles_to_wait_on == NULL) || (handle_to_index == NULL)) { - errno = ENOMEM; - triggered = -1; - goto poll_exit; - } - - for (i = 0; i < nfds; ++i) { - fds[i].revents = 0; - - // Only one of POLLIN or POLLOUT can be selected with this version of poll (not both) - if ((fds[i].events & ~POLLIN) && (!(fds[i].events & POLLOUT))) { - fds[i].revents |= POLLERR; - errno = EACCES; - usbi_warn(NULL, "unsupported set of events"); - triggered = -1; - goto poll_exit; - } - - _index = _fd_to_index_and_lock(fds[i].fd); - poll_dbg("fd[%d]=%d: (overlapped=%p) got events %04X", i, poll_fd[_index].fd, poll_fd[_index].overlapped, fds[i].events); - - if ( (_index < 0) || (poll_fd[_index].handle == INVALID_HANDLE_VALUE) - || (poll_fd[_index].handle == 0) || (poll_fd[_index].overlapped == NULL)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - usbi_warn(NULL, "invalid fd"); - triggered = -1; - goto poll_exit; - } - - // IN or OUT must match our fd direction - if ((fds[i].events & POLLIN) && (poll_fd[_index].rw != RW_READ)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLIN on fd without READ access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - if ((fds[i].events & POLLOUT) && (poll_fd[_index].rw != RW_WRITE)) { - fds[i].revents |= POLLNVAL | POLLERR; - errno = EBADF; - usbi_warn(NULL, "attempted POLLOUT on fd without WRITE access"); - LeaveCriticalSection(&_poll_fd[_index].mutex); - triggered = -1; - goto poll_exit; - } - - // The following macro only works if overlapped I/O was reported pending - if ( (HasOverlappedIoCompleted(poll_fd[_index].overlapped)) - || (HasOverlappedIoCompletedSync(poll_fd[_index].overlapped)) ) { - poll_dbg(" completed"); - // checks above should ensure this works: - fds[i].revents = fds[i].events; - triggered++; - } else { - handles_to_wait_on[nb_handles_to_wait_on] = poll_fd[_index].overlapped->hEvent; - handle_to_index[nb_handles_to_wait_on] = i; -#if defined(DYNAMIC_FDS) - // If this fd from the poll set is also part of the new_fd event handle table, remove it - usbi_mutex_lock(&new_fd_mutex); - for (j=0; j<nb_new_fds; j++) { - if (handles_to_wait_on[nb_handles_to_wait_on] == new_fd[j]) { - new_fd[j] = INVALID_HANDLE_VALUE; - break; - } - } - usbi_mutex_unlock(&new_fd_mutex); -#endif - nb_handles_to_wait_on++; - } - LeaveCriticalSection(&_poll_fd[_index].mutex); - } -#if defined(DYNAMIC_FDS) - // At this stage, new_fd[] should only contain events from fds that - // have been added since the last call to poll, but are not (yet) part - // of the pollable fd set. Typically, these would be from fds that have - // been created between the construction of the fd set and the calling - // of poll. - // Event if we won't be able to return usable poll data on these events, - // make sure we monitor them to return an EINTR code - usbi_mutex_lock(&new_fd_mutex); // We could probably do without - for (i=0; i<nb_new_fds; i++) { - if (new_fd[i] != INVALID_HANDLE_VALUE) { - handles_to_wait_on[nb_handles_to_wait_on++] = new_fd[i]; - nb_extra_handles++; - } - } - usbi_mutex_unlock(&new_fd_mutex); - poll_dbg("dynamic_fds: added %d extra handles", nb_extra_handles); -#endif - - // If nothing was triggered, wait on all fds that require it - if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) { -#if defined(DYNAMIC_FDS) - // Register for fd update notifications - handles_to_wait_on[nb_handles_to_wait_on++] = fd_update; - nb_extra_handles++; -#endif - if (timeout < 0) { - poll_dbg("starting infinite wait for %d handles...", (int)nb_handles_to_wait_on); - } else { - poll_dbg("starting %d ms wait for %d handles...", timeout, (int)nb_handles_to_wait_on); - } - ret = WaitForMultipleObjects(nb_handles_to_wait_on, handles_to_wait_on, - FALSE, (timeout<0)?INFINITE:(DWORD)timeout); - object_index = ret-WAIT_OBJECT_0; - if ((object_index >= 0) && ((DWORD)object_index < nb_handles_to_wait_on)) { -#if defined(DYNAMIC_FDS) - if ((DWORD)object_index >= (nb_handles_to_wait_on-nb_extra_handles)) { - // Detected fd update => flag a poll interruption - if ((DWORD)object_index == (nb_handles_to_wait_on-1)) - poll_dbg(" dynamic_fds: fd_update event"); - else - poll_dbg(" dynamic_fds: new fd I/O event"); - errno = EINTR; - triggered = -1; - goto poll_exit; - } -#endif - poll_dbg(" completed after wait"); - i = handle_to_index[object_index]; - _index = _fd_to_index_and_lock(fds[i].fd); - fds[i].revents = fds[i].events; - triggered++; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - } else if (ret == WAIT_TIMEOUT) { - poll_dbg(" timed out"); - triggered = 0; // 0 = timeout - } else { - errno = EIO; - triggered = -1; // error - } - } - -poll_exit: - if (handles_to_wait_on != NULL) { - free(handles_to_wait_on); - } - if (handle_to_index != NULL) { - free(handle_to_index); - } -#if defined(DYNAMIC_FDS) - usbi_mutex_lock(&new_fd_mutex); - nb_new_fds = 0; - usbi_mutex_unlock(&new_fd_mutex); -#endif - return triggered; -} - -/* - * close a fake pipe fd - */ -int usbi_close(int fd) -{ - int _index; - int r = -1; - - CHECK_INIT_POLLING; - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - } else { - if (poll_fd[_index].overlapped != NULL) { - // Must be a different event for each end of the pipe - CloseHandle(poll_fd[_index].overlapped->hEvent); - free(poll_fd[_index].overlapped); - } - r = _close(poll_fd[_index].fd); - if (r != 0) { - errno = EIO; - } - poll_fd[_index] = INVALID_WINFD; - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - return r; -} - -/* - * synchronous write for fake "pipe" signaling - */ -ssize_t usbi_write(int fd, const void *buf, size_t count) -{ - int _index; - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if ( (_index < 0) || (poll_fd[_index].overlapped == NULL) ) { - errno = EBADF; - if (_index >= 0) { - LeaveCriticalSection(&_poll_fd[_index].mutex); - } - return -1; - } - - poll_dbg("set pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); - SetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_WAIT_0; - // If two threads write on the pipe at the same time, we need to - // process two separate reads => use the overlapped as a counter - poll_fd[_index].overlapped->InternalHigh++; - - LeaveCriticalSection(&_poll_fd[_index].mutex); - return sizeof(unsigned char); -} - -/* - * synchronous read for fake "pipe" signaling - */ -ssize_t usbi_read(int fd, void *buf, size_t count) -{ - int _index; - ssize_t r = -1; - - CHECK_INIT_POLLING; - - if (count != sizeof(unsigned char)) { - usbi_err(NULL, "this function should only used for signaling"); - return -1; - } - - _index = _fd_to_index_and_lock(fd); - - if (_index < 0) { - errno = EBADF; - return -1; - } - - if (WaitForSingleObject(poll_fd[_index].overlapped->hEvent, INFINITE) != WAIT_OBJECT_0) { - usbi_warn(NULL, "waiting for event failed: %d", (int)GetLastError()); - errno = EIO; - goto out; - } - - poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, GetCurrentThreadId()); - poll_fd[_index].overlapped->InternalHigh--; - // Don't reset unless we don't have any more events to process - if (poll_fd[_index].overlapped->InternalHigh <= 0) { - ResetEvent(poll_fd[_index].overlapped->hEvent); - poll_fd[_index].overlapped->Internal = STATUS_PENDING; - } - - r = sizeof(unsigned char); - -out: - LeaveCriticalSection(&_poll_fd[_index].mutex); - return r; -} diff --git a/third_party/libusb/libusb/os/poll_windows.h b/third_party/libusb/libusb/os/poll_windows.h deleted file mode 100644 index 27986b8..0000000 --- a/third_party/libusb/libusb/os/poll_windows.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Windows compat: POSIX compatibility wrapper - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of poll implementation from libusb-win32, by Stephan Meyer et al. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef LIBUSB_POLL_WINDOWS_H -#define LIBUSB_POLL_WINDOWS_H -#pragma once - -#if defined(_MSC_VER) -// disable /W4 MSVC warnings that are benign -#pragma warning(disable:4127) // conditional expression is constant -#endif - -// Uncomment to have poll return with EINTR as soon as a new transfer (fd) is added -// This should result in a LIBUSB_ERROR_INTERRUPTED being returned by libusb calls, -// which should give the app an opportunity to resubmit a new fd set. -//#define DYNAMIC_FDS - -// Handle synchronous completion through the overlapped structure -#if !defined(STATUS_REPARSE) // reuse the REPARSE status code -#define STATUS_REPARSE ((LONG)0x00000104L) -#endif -#define STATUS_COMPLETED_SYNCHRONOUSLY STATUS_REPARSE -#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY) - -#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2) - -enum windows_version { - WINDOWS_UNSUPPORTED, - WINDOWS_XP, - WINDOWS_2003, // also includes XP 64 - WINDOWS_VISTA_AND_LATER, -}; -extern enum windows_version windows_version; - -#define MAX_FDS 256 - -#define POLLIN 0x0001 /* There is data to read */ -#define POLLPRI 0x0002 /* There is urgent data to read */ -#define POLLOUT 0x0004 /* Writing now will not block */ -#define POLLERR 0x0008 /* Error condition */ -#define POLLHUP 0x0010 /* Hung up */ -#define POLLNVAL 0x0020 /* Invalid request: fd not open */ - -// access modes -enum rw_type { - RW_NONE, - RW_READ, - RW_WRITE, -}; - -// fd struct that can be used for polling on Windows -struct winfd { - int fd; // what's exposed to libusb core - HANDLE handle; // what we need to attach overlapped to the I/O op, so we can poll it - OVERLAPPED* overlapped; // what will report our I/O status - enum rw_type rw; // I/O transfer direction: read *XOR* write (NOT BOTH) -}; -extern const struct winfd INVALID_WINFD; - -int usbi_pipe(int pipefd[2]); -int usbi_poll(struct pollfd *fds, unsigned int nfds, int timeout); -ssize_t usbi_write(int fd, const void *buf, size_t count); -ssize_t usbi_read(int fd, void *buf, size_t count); -int usbi_close(int fd); - -void init_polling(void); -void exit_polling(void); -struct winfd usbi_create_fd(HANDLE handle, int access_mode); -void usbi_free_fd(int fd); -struct winfd fd_to_winfd(int fd); -struct winfd handle_to_winfd(HANDLE handle); -struct winfd overlapped_to_winfd(OVERLAPPED* overlapped); - -/* - * Timeval operations - */ -#if defined(DDKBUILD) -#include <winsock.h> // defines timeval functions on DDK -#endif - -#if !defined(TIMESPEC_TO_TIMEVAL) -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ - (tv)->tv_sec = (long)(ts)->tv_sec; \ - (tv)->tv_usec = (long)(ts)->tv_nsec / 1000; \ -} -#endif -#if !defined(timersub) -#define timersub(a, b, result) \ -do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ -} while (0) -#endif - -#endif /* LIBUSB_POLL_WINDOWS_H */ diff --git a/third_party/libusb/libusb/os/threads_posix.c b/third_party/libusb/libusb/os/threads_posix.c deleted file mode 100644 index 435b873..0000000 --- a/third_party/libusb/libusb/os/threads_posix.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * libusb synchronization using POSIX Threads - * - * Copyright (C) 2011 Vitali Lovich <vlovich@aliph.com> - * Copyright (C) 2011 Peter Stuge <peter@stuge.se> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef _XOPEN_SOURCE -# if _XOPEN_SOURCE < 500 -# undef _XOPEN_SOURCE -# define _XOPEN_SOURCE 500 -# endif -#else -#define _XOPEN_SOURCE 500 -#endif /* _XOPEN_SOURCE */ - -#include <pthread.h> - -int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr) -{ - int err; - pthread_mutexattr_t stack_attr; - if (!attr) { - attr = &stack_attr; - err = pthread_mutexattr_init(&stack_attr); - if (err != 0) - return err; - } - - err = pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE); - if (err != 0) - goto finish; - - err = pthread_mutex_init(mutex, attr); - -finish: - if (attr == &stack_attr) - pthread_mutexattr_destroy(&stack_attr); - - return err; -} diff --git a/third_party/libusb/libusb/os/threads_posix.h b/third_party/libusb/libusb/os/threads_posix.h deleted file mode 100644 index 9752208..0000000 --- a/third_party/libusb/libusb/os/threads_posix.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * libusb synchronization using POSIX Threads - * - * Copyright (C) 2010 Peter Stuge <peter@stuge.se> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_THREADS_POSIX_H -#define LIBUSB_THREADS_POSIX_H - -#include <pthread.h> - -#define usbi_mutex_static_t pthread_mutex_t -#define USBI_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define usbi_mutex_static_lock pthread_mutex_lock -#define usbi_mutex_static_unlock pthread_mutex_unlock - -#define usbi_mutex_t pthread_mutex_t -#define usbi_mutex_init pthread_mutex_init -#define usbi_mutex_lock pthread_mutex_lock -#define usbi_mutex_unlock pthread_mutex_unlock -#define usbi_mutex_trylock pthread_mutex_trylock -#define usbi_mutex_destroy pthread_mutex_destroy - -#define usbi_cond_t pthread_cond_t -#define usbi_cond_init pthread_cond_init -#define usbi_cond_wait pthread_cond_wait -#define usbi_cond_timedwait pthread_cond_timedwait -#define usbi_cond_broadcast pthread_cond_broadcast -#define usbi_cond_destroy pthread_cond_destroy -#define usbi_cond_signal pthread_cond_signal - -extern int usbi_mutex_init_recursive(pthread_mutex_t *mutex, pthread_mutexattr_t *attr); - -#endif /* LIBUSB_THREADS_POSIX_H */ diff --git a/third_party/libusb/libusb/os/threads_windows.c b/third_party/libusb/libusb/os/threads_windows.c deleted file mode 100644 index 8a29920..0000000 --- a/third_party/libusb/libusb/os/threads_windows.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * libusb synchronization on Microsoft Windows - * - * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <objbase.h> -#include <errno.h> -#include <stdarg.h> - -#include "libusbi.h" - - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr) { - if(! mutex) return ((errno=EINVAL)); - *mutex = CreateMutex(NULL, FALSE, NULL); - if(!*mutex) return ((errno=ENOMEM)); - return 0; -} -int usbi_mutex_destroy(usbi_mutex_t *mutex) { - // It is not clear if CloseHandle failure is due to failure to unlock. - // If so, this should be errno=EBUSY. - if(!mutex || !CloseHandle(*mutex)) return ((errno=EINVAL)); - *mutex = NULL; - return 0; -} -int usbi_mutex_trylock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, 0); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - if(result == WAIT_TIMEOUT) - return ((errno=EBUSY)); - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_lock(usbi_mutex_t *mutex) { - DWORD result; - if(!mutex) return ((errno=EINVAL)); - result = WaitForSingleObject(*mutex, INFINITE); - if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED) - return 0; // acquired (ToDo: check that abandoned is ok) - return ((errno=EINVAL)); // don't know how this would happen - // so don't know proper errno -} -int usbi_mutex_unlock(usbi_mutex_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - if(!ReleaseMutex(*mutex)) return ((errno=EPERM )); - return 0; -} - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - while (InterlockedExchange((LONG *)mutex, 1) == 1) { - SleepEx(0, TRUE); - } - return 0; -} -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex) { - if(!mutex) return ((errno=EINVAL)); - *mutex = 0; - return 0; -} - - - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr) { - if(!cond) return ((errno=EINVAL)); - list_init(&cond->waiters ); - list_init(&cond->not_waiting); - return 0; -} -int usbi_cond_destroy(usbi_cond_t *cond) { - // This assumes no one is using this anymore. The check MAY NOT BE safe. - struct usbi_cond_perthread *pos, *prev_pos = NULL; - if(!cond) return ((errno=EINVAL)); - if(!list_empty(&cond->waiters)) return ((errno=EBUSY )); // (!see above!) - list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - free(prev_pos); - list_del(&pos->list); - prev_pos = pos; - } - free(prev_pos); - prev_pos = pos = NULL; - - return 0; -} - -int usbi_cond_broadcast(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - int fail = 0; - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - list_for_each_entry(pos, &cond->waiters, list, struct usbi_cond_perthread) { - if(!SetEvent(pos->event)) - fail = 1; - } - // The wait function will remove its respective item from the list. - return fail ? ((errno=EINVAL)) : 0; -} -int usbi_cond_signal(usbi_cond_t *cond) { - // Assumes mutex is locked; this is not in keeping with POSIX spec, but - // libusb does this anyway, so we simplify by not adding more sync - // primitives to the CV definition! - struct usbi_cond_perthread *pos; - if(!cond) return ((errno=EINVAL)); - if(list_empty(&cond->waiters)) return 0; // no one to wakeup. - pos = list_entry(&cond->waiters.next, struct usbi_cond_perthread, list); - // The wait function will remove its respective item from the list. - return SetEvent(pos->event) ? 0 : ((errno=EINVAL)); -} -static int __inline usbi_cond_intwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - DWORD timeout_ms) { - struct usbi_cond_perthread *pos; - int found = 0, r; - DWORD r2,tid = GetCurrentThreadId(); - if(!cond || !mutex) return ((errno=EINVAL)); - list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) { - if(tid == pos->tid) { - found = 1; - break; - } - } - if(!found) { - pos = malloc(sizeof(struct usbi_cond_perthread)); - if(!pos) return ((errno=ENOMEM)); // This errno is not POSIX-allowed. - pos->tid = tid; - pos->event = CreateEvent(NULL, FALSE, FALSE, NULL); // auto-reset. - if(!pos->event) { - free(pos); - return ((errno=ENOMEM)); - } - list_add(&pos->list, &cond->not_waiting); - } - - list_del(&pos->list); // remove from not_waiting list. - list_add(&pos->list, &cond->waiters); - - r = usbi_mutex_unlock(mutex); - if(r) return r; - r2 = WaitForSingleObject(pos->event, timeout_ms); - r = usbi_mutex_lock(mutex); - if(r) return r; - - list_del(&pos->list); - list_add(&pos->list, &cond->not_waiting); - - if(r2 == WAIT_TIMEOUT) return ((errno=ETIMEDOUT)); - - return 0; -} -// N.B.: usbi_cond_*wait() can also return ENOMEM, even though pthread_cond_*wait cannot! -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex) { - return usbi_cond_intwait(cond, mutex, INFINITE); -} -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime) { - FILETIME filetime; - ULARGE_INTEGER rtime; - struct timeval targ_time, cur_time, delta_time; - struct timespec cur_time_ns; - DWORD millis; - extern const uint64_t epoch_time; - - GetSystemTimeAsFileTime(&filetime); - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - cur_time_ns.tv_sec = (long)(rtime.QuadPart / 10000000); - cur_time_ns.tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - TIMESPEC_TO_TIMEVAL(&cur_time, &cur_time_ns); - - TIMESPEC_TO_TIMEVAL(&targ_time, abstime); - timersub(&targ_time, &cur_time, &delta_time); - if(delta_time.tv_sec < 0) // abstime already passed? - millis = 0; - else { - millis = delta_time.tv_usec/1000; - millis += delta_time.tv_sec *1000; - if (delta_time.tv_usec % 1000) // round up to next millisecond - millis++; - } - - return usbi_cond_intwait(cond, mutex, millis); -} - diff --git a/third_party/libusb/libusb/os/threads_windows.h b/third_party/libusb/libusb/os/threads_windows.h deleted file mode 100644 index 7bb144a..0000000 --- a/third_party/libusb/libusb/os/threads_windows.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * libusb synchronization on Microsoft Windows - * - * Copyright (C) 2010 Michael Plante <michael.plante@gmail.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LIBUSB_THREADS_WINDOWS_H -#define LIBUSB_THREADS_WINDOWS_H - -#define usbi_mutex_static_t volatile LONG -#define USBI_MUTEX_INITIALIZER 0 - -#define usbi_mutex_t HANDLE - -struct usbi_cond_perthread { - struct list_head list; - DWORD tid; - HANDLE event; -}; -struct usbi_cond_t_ { - // Every time a thread touches the CV, it winds up in one of these lists. - // It stays there until the CV is destroyed, even if the thread - // terminates. - struct list_head waiters; - struct list_head not_waiting; -}; -typedef struct usbi_cond_t_ usbi_cond_t; - -// We *were* getting timespec from pthread.h: -#if (!defined(HAVE_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED)) -#define HAVE_STRUCT_TIMESPEC 1 -#define _TIMESPEC_DEFINED 1 -struct timespec { - long tv_sec; - long tv_nsec; -}; -#endif /* HAVE_STRUCT_TIMESPEC | _TIMESPEC_DEFINED */ - -// We *were* getting ETIMEDOUT from pthread.h: -#ifndef ETIMEDOUT -# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ -#endif - -#define usbi_mutexattr_t void -#define usbi_condattr_t void - -// all Windows mutexes are recursive -#define usbi_mutex_init_recursive(mutex, attr) usbi_mutex_init((mutex), (attr)) - -int usbi_mutex_static_lock(usbi_mutex_static_t *mutex); -int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex); - - -int usbi_mutex_init(usbi_mutex_t *mutex, - const usbi_mutexattr_t *attr); -int usbi_mutex_lock(usbi_mutex_t *mutex); -int usbi_mutex_unlock(usbi_mutex_t *mutex); -int usbi_mutex_trylock(usbi_mutex_t *mutex); -int usbi_mutex_destroy(usbi_mutex_t *mutex); - -int usbi_cond_init(usbi_cond_t *cond, - const usbi_condattr_t *attr); -int usbi_cond_destroy(usbi_cond_t *cond); -int usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex); -int usbi_cond_timedwait(usbi_cond_t *cond, - usbi_mutex_t *mutex, - const struct timespec *abstime); -int usbi_cond_broadcast(usbi_cond_t *cond); -int usbi_cond_signal(usbi_cond_t *cond); - -#endif /* LIBUSB_THREADS_WINDOWS_H */ - diff --git a/third_party/libusb/libusb/os/windows_usb.c b/third_party/libusb/libusb/os/windows_usb.c deleted file mode 100644 index 68216db..0000000 --- a/third_party/libusb/libusb/os/windows_usb.c +++ /dev/null @@ -1,3038 +0,0 @@ -/* - * windows backend for libusb 1.0 - * Copyright (c) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer - * Hash table functions adapted from glibc, by Ulrich Drepper et al. - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -// COMPILATION OPTIONS: -// - Should libusb automatically claim (and release) the interfaces it requires? -#define AUTO_CLAIM -// - Forces instant overlapped completion on timeouts: can prevents extensive -// wait in poll, after a timeout, but might affect subsequent API calls. -// ***USE AT YOUR OWN RISKS*** -//#define FORCE_INSTANT_TIMEOUTS - -#include <config.h> -#include <windows.h> -#include <setupapi.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <process.h> -#include <stdio.h> -#include <inttypes.h> -#include <objbase.h> -#include <winioctl.h> - -#include <libusbi.h> -#include "poll_windows.h" -#include "windows_usb.h" - -// The following prevents "banned API" errors when using the MS's WDK OACR/Prefast -#if defined(_PREFAST_) -#pragma warning(disable:28719) -#endif - -// The 2 macros below are used in conjunction with safe loops. -#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; } -#define LOOP_BREAK(err) { r=err; continue; } - -extern void usbi_fd_notification(struct libusb_context *ctx); - -// Helper prototypes -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian); -static int windows_clock_gettime(int clk_id, struct timespec *tp); -unsigned __stdcall windows_clock_gettime_threaded(void* param); -// WinUSB API prototypes -static int winusb_init(struct libusb_context *ctx); -static int winusb_exit(void); -static int winusb_open(struct libusb_device_handle *dev_handle); -static void winusb_close(struct libusb_device_handle *dev_handle); -static int winusb_configure_endpoints(struct libusb_device_handle *dev_handle, int iface); -static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int winusb_submit_control_transfer(struct usbi_transfer *itransfer); -static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer); -static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int winusb_abort_transfers(struct usbi_transfer *itransfer); -static int winusb_abort_control(struct usbi_transfer *itransfer); -static int winusb_reset_device(struct libusb_device_handle *dev_handle); -static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); -// Composite API prototypes -static int composite_init(struct libusb_context *ctx); -static int composite_exit(void); -static int composite_open(struct libusb_device_handle *dev_handle); -static void composite_close(struct libusb_device_handle *dev_handle); -static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface); -static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting); -static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface); -static int composite_submit_control_transfer(struct usbi_transfer *itransfer); -static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer); -static int composite_submit_iso_transfer(struct usbi_transfer *itransfer); -static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint); -static int composite_abort_transfers(struct usbi_transfer *itransfer); -static int composite_abort_control(struct usbi_transfer *itransfer); -static int composite_reset_device(struct libusb_device_handle *dev_handle); -static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size); - - -// Global variables -uint64_t hires_frequency, hires_ticks_to_ps; -const uint64_t epoch_time = UINT64_C(116444736000000000); // 1970.01.01 00:00:000 in MS Filetime -enum windows_version windows_version = WINDOWS_UNSUPPORTED; -// Concurrency -static int concurrent_usage = -1; -#if defined(AUTO_CLAIM) -usbi_mutex_t autoclaim_lock; -#endif -// Timer thread -// NB: index 0 is for monotonic and 1 is for the thread exit event -HANDLE timer_thread = NULL; -HANDLE timer_mutex = NULL; -struct timespec timer_tp; -volatile LONG request_count[2] = {0, 1}; // last one must be > 0 -HANDLE timer_request[2] = { NULL, NULL }; -HANDLE timer_response = NULL; -// API globals -bool api_winusb_available = false; -#define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_ACCESS; } while (0) - -static inline BOOLEAN guid_eq(const GUID *guid1, const GUID *guid2) { - if ((guid1 != NULL) && (guid2 != NULL)) { - return (memcmp(guid1, guid2, sizeof(GUID)) == 0); - } - return false; -} - -#if defined(ENABLE_DEBUG_LOGGING) -static char* guid_to_string(const GUID* guid) -{ - static char guid_string[MAX_GUID_STRING_LENGTH]; - - if (guid == NULL) return NULL; - sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - (unsigned int)guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); - return guid_string; -} -#endif - -/* - * Converts a windows error to human readable string - * uses retval as errorcode, or, if 0, use GetLastError() - */ -#if defined(ENABLE_LOGGING) -static char *windows_error_str(uint32_t retval) -{ -static char err_string[ERR_BUFFER_SIZE]; - - DWORD size; - size_t i; - uint32_t error_code, format_error; - - error_code = retval?retval:GetLastError(); - - safe_sprintf(err_string, ERR_BUFFER_SIZE, "[%d] ", error_code); - - size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error_code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[safe_strlen(err_string)], - ERR_BUFFER_SIZE - (DWORD)safe_strlen(err_string), NULL); - if (size == 0) { - format_error = GetLastError(); - if (format_error) - safe_sprintf(err_string, ERR_BUFFER_SIZE, - "Windows error code %u (FormatMessage error code %u)", error_code, format_error); - else - safe_sprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", error_code); - } else { - // Remove CR/LF terminators - for (i=safe_strlen(err_string)-1; ((err_string[i]==0x0A) || (err_string[i]==0x0D)); i--) { - err_string[i] = 0; - } - } - return err_string; -} -#endif - -/* - * Sanitize Microsoft's paths: convert to uppercase, add prefix and fix backslashes. - * Return an allocated sanitized string or NULL on error. - */ -static char* sanitize_path(const char* path) -{ - const char root_prefix[] = "\\\\.\\"; - size_t j, size, root_size; - char* ret_path = NULL; - size_t add_root = 0; - - if (path == NULL) - return NULL; - - size = safe_strlen(path)+1; - root_size = sizeof(root_prefix)-1; - - // Microsoft indiscriminatly uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes. - if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\')) || - ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) { - add_root = root_size; - size += add_root; - } - - if ((ret_path = (char*)calloc(size, 1)) == NULL) - return NULL; - - safe_strcpy(&ret_path[add_root], size-add_root, path); - - // Ensure consistancy with root prefix - for (j=0; j<root_size; j++) - ret_path[j] = root_prefix[j]; - - // Same goes for '\' and '#' after the root prefix. Ensure '#' is used - for(j=root_size; j<size; j++) { - ret_path[j] = (char)toupper((int)ret_path[j]); // Fix case too - if (ret_path[j] == '\\') - ret_path[j] = '#'; - } - - return ret_path; -} - -/* - * Cfgmgr32, OLE32 and SetupAPI DLL functions - */ -static int init_dlls(void) -{ - DLL_LOAD(Cfgmgr32.dll, CM_Get_Parent, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Child, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Sibling, TRUE); - DLL_LOAD(Cfgmgr32.dll, CM_Get_Device_IDA, TRUE); - // Prefixed to avoid conflict with header files - DLL_LOAD_PREFIXED(OLE32.dll, p, CLSIDFromString, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetClassDevsA, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInfo, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiEnumDeviceInterfaces, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceInterfaceDetailA, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiDestroyDeviceInfoList, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiOpenDevRegKey, TRUE); - DLL_LOAD_PREFIXED(SetupAPI.dll, p, SetupDiGetDeviceRegistryPropertyA, TRUE); - DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegQueryValueExW, TRUE); - DLL_LOAD_PREFIXED(AdvAPI32.dll, p, RegCloseKey, TRUE); - return LIBUSB_SUCCESS; -} - -/* - * enumerate interfaces for the whole USB class - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * usb_class: the generic USB class for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -static bool get_devinfo_data(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, char* usb_class, unsigned _index) -{ - if (_index <= 0) { - *dev_info = pSetupDiGetClassDevsA(NULL, usb_class, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); - if (*dev_info == INVALID_HANDLE_VALUE) { - return false; - } - } - - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return false; - } - return true; -} - -/* - * enumerate interfaces for a specific GUID - * - * Parameters: - * dev_info: a pointer to a dev_info list - * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed) - * guid: the GUID for which to retrieve interface details - * index: zero based index of the interface in the device info list - * - * Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA - * structure returned and call this function repeatedly using the same guid (with an - * incremented index starting at zero) until all interfaces have been returned. - */ -static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID* guid, unsigned _index) -{ - SP_DEVICE_INTERFACE_DATA dev_interface_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; - DWORD size; - - if (_index <= 0) { - *dev_info = pSetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); - } - - if (dev_info_data != NULL) { - dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA); - if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain device info data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - } - - dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, guid, _index, &dev_interface_data)) { - if (GetLastError() != ERROR_NO_MORE_ITEMS) { - usbi_err(ctx, "Could not obtain interface data for index %u: %s", - _index, windows_error_str(0)); - } - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; - } - - // Read interface data (dummy + actual) to access the device path - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) { - // The dummy call should fail with ERROR_INSUFFICIENT_BUFFER - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - usbi_err(ctx, "could not access interface data (dummy) for index %u: %s", - _index, windows_error_str(0)); - goto err_exit; - } - } else { - usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong."); - goto err_exit; - } - - if ((dev_interface_details = malloc(size)) == NULL) { - usbi_err(ctx, "could not allocate interface data for index %u.", _index); - goto err_exit; - } - - dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); - if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, - dev_interface_details, size, &size, NULL)) { - usbi_err(ctx, "could not access interface data (actual) for index %u: %s", - _index, windows_error_str(0)); - } - - return dev_interface_details; - -err_exit: - pSetupDiDestroyDeviceInfoList(*dev_info); - *dev_info = INVALID_HANDLE_VALUE; - return NULL; -} - -/* Hash table functions - modified From glibc 2.3.2: - [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 - [Knuth] The Art of Computer Programming, part 3 (6.4) */ -typedef struct htab_entry { - unsigned long used; - char* str; -} htab_entry; -htab_entry* htab_table = NULL; -usbi_mutex_t htab_write_mutex = NULL; -unsigned long htab_size, htab_filled; - -/* For the used double hash method the table size has to be a prime. To - correct the user given table size we need a prime test. This trivial - algorithm is adequate because the code is called only during init and - the number is likely to be small */ -static int isprime(unsigned long number) -{ - // no even number will be passed - unsigned int divider = 3; - - while((divider * divider < number) && (number % divider != 0)) - divider += 2; - - return (number % divider != 0); -} - -/* Before using the hash table we must allocate memory for it. - We allocate one element more as the found prime number says. - This is done for more effective indexing as explained in the - comment for the hash function. */ -static int htab_create(struct libusb_context *ctx, unsigned long nel) -{ - if (htab_table != NULL) { - usbi_err(ctx, "hash table already allocated"); - } - - // Create a mutex - usbi_mutex_init(&htab_write_mutex, NULL); - - // Change nel to the first prime number not smaller as nel. - nel |= 1; - while(!isprime(nel)) - nel += 2; - - htab_size = nel; - usbi_dbg("using %d entries hash table", nel); - htab_filled = 0; - - // allocate memory and zero out. - htab_table = (htab_entry*)calloc(htab_size + 1, sizeof(htab_entry)); - if (htab_table == NULL) { - usbi_err(ctx, "could not allocate space for hash table"); - return 0; - } - - return 1; -} - -/* After using the hash table it has to be destroyed. */ -static void htab_destroy(void) -{ - size_t i; - if (htab_table == NULL) { - return; - } - - for (i=0; i<htab_size; i++) { - if (htab_table[i].used) { - safe_free(htab_table[i].str); - } - } - usbi_mutex_destroy(&htab_write_mutex); - safe_free(htab_table); -} - -/* This is the search function. It uses double hashing with open addressing. - We use an trick to speed up the lookup. The table is created with one - more element available. This enables us to use the index zero special. - This index will never be used because we store the first hash index in - the field used where zero means not used. Every other value means used. - The used field can be used as a first fast comparison for equality of - the stored and the parameter value. This helps to prevent unnecessary - expensive calls of strcmp. */ -static unsigned long htab_hash(char* str) -{ - unsigned long hval, hval2; - unsigned long idx; - unsigned long r = 5381; - int c; - char* sz = str; - - // Compute main hash value (algorithm suggested by Nokia) - while ((c = *sz++)) - r = ((r << 5) + r) + c; - if (r == 0) - ++r; - - // compute table hash: simply take the modulus - hval = r % htab_size; - if (hval == 0) - ++hval; - - // Try the first index - idx = hval; - - if (htab_table[idx].used) { - if ( (htab_table[idx].used == hval) - && (safe_strcmp(str, htab_table[idx].str) == 0) ) { - // existing hash - return idx; - } - usbi_dbg("hash collision ('%s' vs '%s')", str, htab_table[idx].str); - - // Second hash function, as suggested in [Knuth] - hval2 = 1 + hval % (htab_size - 2); - - do { - // Because size is prime this guarantees to step through all available indexes - if (idx <= hval2) { - idx = htab_size + idx - hval2; - } else { - idx -= hval2; - } - - // If we visited all entries leave the loop unsuccessfully - if (idx == hval) { - break; - } - - // If entry is found use it. - if ( (htab_table[idx].used == hval) - && (safe_strcmp(str, htab_table[idx].str) == 0) ) { - return idx; - } - } - while (htab_table[idx].used); - } - - // Not found => New entry - - // If the table is full return an error - if (htab_filled >= htab_size) { - usbi_err(NULL, "hash table is full (%d entries)", htab_size); - return 0; - } - - // Concurrent threads might be storing the same entry at the same time - // (eg. "simultaneous" enums from different threads) => use a mutex - usbi_mutex_lock(&htab_write_mutex); - // Just free any previously allocated string (which should be the same as - // new one). The possibility of concurrent threads storing a collision - // string (same hash, different string) at the same time is extremely low - safe_free(htab_table[idx].str); - htab_table[idx].used = hval; - htab_table[idx].str = malloc(safe_strlen(str)+1); - if (htab_table[idx].str == NULL) { - usbi_err(NULL, "could not duplicate string for hash table"); - usbi_mutex_unlock(&htab_write_mutex); - return 0; - } - memcpy(htab_table[idx].str, str, safe_strlen(str)+1); - ++htab_filled; - usbi_mutex_unlock(&htab_write_mutex); - - return idx; -} - -/* - * Returns the session ID of a device's nth level ancestor - * If there's no device at the nth level, return 0 - */ -static unsigned long get_ancestor_session_id(DWORD devinst, unsigned level) -{ - DWORD parent_devinst; - unsigned long session_id = 0; - char* sanitized_path = NULL; - char path[MAX_PATH_LENGTH]; - unsigned i; - - if (level < 1) return 0; - for (i = 0; i<level; i++) { - if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS) { - return 0; - } - devinst = parent_devinst; - } - if (CM_Get_Device_IDA(devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) { - return 0; - } - // TODO (post hotplug): try without sanitizing - sanitized_path = sanitize_path(path); - if (sanitized_path == NULL) { - return 0; - } - session_id = htab_hash(sanitized_path); - safe_free(sanitized_path); - return session_id; -} - -/* - * Populate the endpoints addresses of the device_priv interface helper structs - */ -static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int i, r; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct libusb_config_descriptor *conf_desc; - const struct libusb_interface_descriptor *if_desc; - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - r = libusb_get_config_descriptor(dev_handle->dev, 0, &conf_desc); - if (r != LIBUSB_SUCCESS) { - usbi_warn(ctx, "could not read config descriptor: error %d", r); - return r; - } - - if_desc = &conf_desc->interface[iface].altsetting[altsetting]; - safe_free(priv->usb_interface[iface].endpoint); - - if (if_desc->bNumEndpoints == 0) { - usbi_dbg("no endpoints found for interface %d", iface); - return LIBUSB_SUCCESS; - } - - priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints); - if (priv->usb_interface[iface].endpoint == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - - priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints; - for (i=0; i<if_desc->bNumEndpoints; i++) { - priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress; - usbi_dbg("(re)assigned endpoint %02X to interface %d", priv->usb_interface[iface].endpoint[i], iface); - } - libusb_free_config_descriptor(conf_desc); - - // Extra init is required for WinUSB endpoints - if (priv->apib->id == USB_API_WINUSB) { - return winusb_configure_endpoints(dev_handle, iface); - } - - return LIBUSB_SUCCESS; -} - -// Lookup for a match in the list of API driver names -static bool is_api_driver(char* driver, uint8_t api) -{ - uint8_t i; - const char sep_str[2] = {LIST_SEPARATOR, 0}; - char *tok, *tmp_str; - size_t len = safe_strlen(driver); - - if (len == 0) return false; - tmp_str = calloc(len+1, 1); - if (tmp_str == NULL) return false; - memcpy(tmp_str, driver, len+1); - tok = strtok(tmp_str, sep_str); - while (tok != NULL) { - for (i=0; i<usb_api_backend[api].nb_driver_names; i++) { - if (safe_strcmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) { - free(tmp_str); - return true; - } - } - tok = strtok(NULL, sep_str); - } - free (tmp_str); - return false; -} - -/* - * auto-claiming and auto-release helper functions - */ -#if defined(AUTO_CLAIM) -static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type) -{ - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv( - transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface = *interface_number; - int r = LIBUSB_SUCCESS; - - usbi_mutex_lock(&autoclaim_lock); - if (current_interface < 0) // No serviceable interface was found - { - for (current_interface=0; current_interface<USB_MAXINTERFACES; current_interface++) { - // Must claim an interface of the same API type - if ( (priv->usb_interface[current_interface].apib->id == api_type) - && (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS) ) { - usbi_dbg("auto-claimed interface %d for control request", current_interface); - if (handle_priv->autoclaim_count[current_interface] != 0) { - usbi_warn(ctx, "program assertion failed - autoclaim_count was nonzero"); - } - handle_priv->autoclaim_count[current_interface]++; - break; - } - } - if (current_interface == USB_MAXINTERFACES) { - usbi_err(ctx, "could not auto-claim any interface"); - r = LIBUSB_ERROR_NOT_FOUND; - } - } else { - // If we have a valid interface that was autoclaimed, we must increment - // its autoclaim count so that we can prevent an early release. - if (handle_priv->autoclaim_count[current_interface] != 0) { - handle_priv->autoclaim_count[current_interface]++; - } - } - usbi_mutex_unlock(&autoclaim_lock); - - *interface_number = current_interface; - return r; - -} - -static void auto_release(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - libusb_device_handle *dev_handle = transfer->dev_handle; - struct windows_device_handle_priv* handle_priv = _device_handle_priv(dev_handle); - int r; - - usbi_mutex_lock(&autoclaim_lock); - if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) { - handle_priv->autoclaim_count[transfer_priv->interface_number]--; - if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) { - r = libusb_release_interface(dev_handle, transfer_priv->interface_number); - if (r == LIBUSB_SUCCESS) { - usbi_dbg("auto-released interface %d", transfer_priv->interface_number); - } else { - usbi_dbg("failed to auto-release interface %d (error=%d)", - transfer_priv->interface_number, r); - } - } - } - usbi_mutex_unlock(&autoclaim_lock); -} -#endif - - -/* - * init: libusb backend init function - * - * This function enumerates the HCDs (Host Controller Drivers) and populates our private HCD list - * In our implementation, we equate Windows' "HCD" to LibUSB's "bus". Note that bus is zero indexed. - * HCDs are not expected to change after init (might not hold true for hot pluggable USB PCI card?) - */ -static int windows_init(struct libusb_context *ctx) -{ - int i, r = LIBUSB_ERROR_OTHER; - OSVERSIONINFO os_version; - HANDLE semaphore; - char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - usbi_err(ctx, "could not create semaphore: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_MEM; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore's release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - usbi_err(ctx, "failure to access semaphore: %s", windows_error_str(0)); - CloseHandle(semaphore); - return LIBUSB_ERROR_NO_MEM; - } - - // NB: concurrent usage supposes that init calls are equally balanced with - // exit calls. If init is called more than exit, we will not exit properly - if ( ++concurrent_usage == 0 ) { // First init? - // Detect OS version - memset(&os_version, 0, sizeof(OSVERSIONINFO)); - os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - windows_version = WINDOWS_UNSUPPORTED; - if ((GetVersionEx(&os_version) != 0) && (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)) { - if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 1)) { - windows_version = WINDOWS_XP; - } else if ((os_version.dwMajorVersion == 5) && (os_version.dwMinorVersion == 2)) { - windows_version = WINDOWS_2003; // also includes XP 64 - } else if (os_version.dwMajorVersion >= 6) { - windows_version = WINDOWS_VISTA_AND_LATER; - } - } - if (windows_version == WINDOWS_UNSUPPORTED) { - usbi_err(ctx, "This version of Windows is NOT supported"); - r = LIBUSB_ERROR_NOT_SUPPORTED; - goto init_exit; - } - -#if defined(AUTO_CLAIM) - // We need a lock for proper auto-release - usbi_mutex_init(&autoclaim_lock, NULL); -#endif - - // Initialize pollable file descriptors - init_polling(); - - // Load DLL imports - if (init_dlls() != LIBUSB_SUCCESS) { - usbi_err(ctx, "could not resolve DLL functions"); - return LIBUSB_ERROR_NOT_FOUND; - } - - // Initialize the low level APIs (we don't care about errors at this stage) - for (i=0; i<USB_API_MAX; i++) { - usb_api_backend[i].init(ctx); - } - - // Because QueryPerformanceCounter might report different values when - // running on different cores, we create a separate thread for the timer - // calls, which we glue to the first core always to prevent timing discrepancies. - r = LIBUSB_ERROR_NO_MEM; - for (i = 0; i < 2; i++) { - timer_request[i] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (timer_request[i] == NULL) { - usbi_err(ctx, "could not create timer request event %d - aborting", i); - goto init_exit; - } - } - timer_response = CreateSemaphore(NULL, 0, MAX_TIMER_SEMAPHORES, NULL); - if (timer_response == NULL) { - usbi_err(ctx, "could not create timer response semaphore - aborting"); - goto init_exit; - } - timer_mutex = CreateMutex(NULL, FALSE, NULL); - if (timer_mutex == NULL) { - usbi_err(ctx, "could not create timer mutex - aborting"); - goto init_exit; - } - timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, NULL, 0, NULL); - if (timer_thread == NULL) { - usbi_err(ctx, "Unable to create timer thread - aborting"); - goto init_exit; - } - SetThreadAffinityMask(timer_thread, 0); - - // Create a hash table to store session ids. Second parameter is better if prime - htab_create(ctx, HTAB_SIZE); - } - // At this stage, either we went through full init successfully, or didn't need to - r = LIBUSB_SUCCESS; - -init_exit: // Holds semaphore here. - if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed? - if (timer_thread) { - SetEvent(timer_request[1]); // actually the signal to quit the thread. - if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) { - usbi_warn(ctx, "could not wait for timer thread to quit"); - TerminateThread(timer_thread, 1); // shouldn't happen, but we're destroying - // all objects it might have held anyway. - } - CloseHandle(timer_thread); - timer_thread = NULL; - } - for (i = 0; i < 2; i++) { - if (timer_request[i]) { - CloseHandle(timer_request[i]); - timer_request[i] = NULL; - } - } - if (timer_response) { - CloseHandle(timer_response); - timer_response = NULL; - } - if (timer_mutex) { - CloseHandle(timer_mutex); - timer_mutex = NULL; - } - htab_destroy(); - } - - if (r != LIBUSB_SUCCESS) - --concurrent_usage; // Not expected to call libusb_exit if we failed. - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); - return r; -} - -/* - * HCD (root) hubs need to have their device descriptor manually populated - * - * Note that, like Microsoft does in the device manager, we populate the - * Vendor and Device ID for HCD hubs with the ones from the PCI HCD device. - */ -static int force_hcd_device_descriptor(struct libusb_device *dev) -{ - struct windows_device_priv *parent_priv, *priv = _device_priv(dev); - struct libusb_context *ctx = DEVICE_CTX(dev); - int vid, pid; - - dev->num_configurations = 1; - priv->dev_descriptor.bLength = sizeof(USB_DEVICE_DESCRIPTOR); - priv->dev_descriptor.bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE; - priv->dev_descriptor.bNumConfigurations = 1; - priv->active_config = 1; - - if (priv->parent_dev == NULL) { - usbi_err(ctx, "program assertion failed - HCD hub has no parent"); - return LIBUSB_ERROR_NO_DEVICE; - } - parent_priv = _device_priv(priv->parent_dev); - if (sscanf(parent_priv->path, "\\\\.\\PCI#VEN_%04x&DEV_%04x%*s", &vid, &pid) == 2) { - priv->dev_descriptor.idVendor = (uint16_t)vid; - priv->dev_descriptor.idProduct = (uint16_t)pid; - } else { - usbi_warn(ctx, "could not infer VID/PID of HCD hub from '%s'", parent_priv->path); - priv->dev_descriptor.idVendor = 0x1d6b; // Linux Foundation root hub - priv->dev_descriptor.idProduct = 1; - } - return LIBUSB_SUCCESS; -} - -/* - * fetch and cache all the config descriptors through I/O - */ -static int cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle, char* device_id) -{ - DWORD size, ret_size; - struct libusb_context *ctx = DEVICE_CTX(dev); - struct windows_device_priv *priv = _device_priv(dev); - int r; - uint8_t i; - - USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request - PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request - PUSB_CONFIGURATION_DESCRIPTOR cd_data = NULL; - - if (dev->num_configurations == 0) - return LIBUSB_ERROR_INVALID_PARAM; - - priv->config_descriptor = malloc(dev->num_configurations * sizeof(PUSB_CONFIGURATION_DESCRIPTOR)); - if (priv->config_descriptor == NULL) - return LIBUSB_ERROR_NO_MEM; - for (i=0; i<dev->num_configurations; i++) - priv->config_descriptor[i] = NULL; - - for (i=0, r=LIBUSB_SUCCESS; ; i++) - { - // safe loop: release all dynamic resources - safe_free(cd_buf_actual); - - // safe loop: end of loop condition - if ((i >= dev->num_configurations) || (r != LIBUSB_SUCCESS)) - break; - - size = sizeof(USB_CONFIGURATION_DESCRIPTOR_SHORT); - memset(&cd_buf_short, 0, size); - - cd_buf_short.req.ConnectionIndex = (ULONG)priv->port; - cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_short.req.SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_short.req.SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_short.req.SetupPacket.wIndex = i; - cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - // Dummy call to get the required data size - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size, - &cd_buf_short, size, &ret_size, NULL)) { - usbi_err(ctx, "could not access configuration descriptor (dummy) for '%s': %s", device_id, windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if ((ret_size != size) || (cd_buf_short.data.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) { - usbi_err(ctx, "unexpected configuration descriptor size (dummy) for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.data.wTotalLength; - if ((cd_buf_actual = (PUSB_DESCRIPTOR_REQUEST)malloc(size)) == NULL) { - usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - memset(cd_buf_actual, 0, size); - - // Actual call - cd_buf_actual->ConnectionIndex = (ULONG)priv->port; - cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN; - cd_buf_actual->SetupPacket.bRequest = USB_REQUEST_GET_DESCRIPTOR; - cd_buf_actual->SetupPacket.wValue = (USB_CONFIGURATION_DESCRIPTOR_TYPE << 8) | i; - cd_buf_actual->SetupPacket.wIndex = i; - cd_buf_actual->SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST)); - - if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size, - cd_buf_actual, size, &ret_size, NULL)) { - usbi_err(ctx, "could not access configuration descriptor (actual) for '%s': %s", device_id, windows_error_str(0)); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR*)cd_buf_actual+sizeof(USB_DESCRIPTOR_REQUEST)); - - if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.data.wTotalLength)) { - usbi_err(ctx, "unexpected configuration descriptor size (actual) for '%s'.", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - if (cd_data->bDescriptorType != USB_CONFIGURATION_DESCRIPTOR_TYPE) { - usbi_err(ctx, "not a configuration descriptor for '%s'", device_id); - LOOP_BREAK(LIBUSB_ERROR_IO); - } - - usbi_dbg("cached config descriptor %d (bConfigurationValue=%d, %d bytes)", - i, cd_data->bConfigurationValue, cd_data->wTotalLength); - - // Cache the descriptor - priv->config_descriptor[i] = malloc(cd_data->wTotalLength); - if (priv->config_descriptor[i] == NULL) - return LIBUSB_ERROR_NO_MEM; - - memcpy(priv->config_descriptor[i], cd_data, cd_data->wTotalLength); - } - return LIBUSB_SUCCESS; -} - -/* - * Populate a libusb device structure - */ -static int init_device(struct libusb_device* dev, struct libusb_device* parent_dev, - uint8_t port_number, char* device_id, DWORD devinst) -{ - HANDLE handle; - DWORD size; - USB_NODE_CONNECTION_INFORMATION_EX conn_info; - struct windows_device_priv *priv, *parent_priv; - struct libusb_context *ctx = DEVICE_CTX(dev); - struct libusb_device* tmp_dev; - unsigned i; - - if ((dev == NULL) || (parent_dev == NULL)) { - return LIBUSB_ERROR_NOT_FOUND; - } - priv = _device_priv(dev); - parent_priv = _device_priv(parent_dev); - if (parent_priv->apib->id != USB_API_HUB) { - usbi_warn(ctx, "parent for device '%s' is not a hub", device_id); - return LIBUSB_ERROR_NOT_FOUND; - } - - // It is possible for the parent hub not to have been initialized yet - // If that's the case, lookup the ancestors to set the bus number - if (parent_dev->bus_number == 0) { - for (i=2; ; i++) { - tmp_dev = usbi_get_device_by_session_id(ctx, get_ancestor_session_id(devinst, i)); - if (tmp_dev == NULL) break; - if (tmp_dev->bus_number != 0) { - usbi_dbg("got bus number from ancestor #%d", i); - parent_dev->bus_number = tmp_dev->bus_number; - break; - } - } - } - if (parent_dev->bus_number == 0) { - usbi_err(ctx, "program assertion failed: unable to find ancestor bus number for '%s'", device_id); - return LIBUSB_ERROR_NOT_FOUND; - } - dev->bus_number = parent_dev->bus_number; - priv->port = port_number; - priv->depth = parent_priv->depth + 1; - priv->parent_dev = parent_dev; - - // If the device address is already set, we can stop here - if (dev->device_address != 0) { - return LIBUSB_SUCCESS; - } - memset(&conn_info, 0, sizeof(conn_info)); - if (priv->depth != 0) { // Not a HCD hub - handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - if (handle == INVALID_HANDLE_VALUE) { - usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - size = sizeof(conn_info); - conn_info.ConnectionIndex = (ULONG)port_number; - if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, size, - &conn_info, size, &size, NULL)) { - usbi_warn(ctx, "could not get node connection information for device '%s': %s", - device_id, windows_error_str(0)); - safe_closehandle(handle); - return LIBUSB_ERROR_NO_DEVICE; - } - if (conn_info.ConnectionStatus == NoDeviceConnected) { - usbi_err(ctx, "device '%s' is no longer connected!", device_id); - safe_closehandle(handle); - return LIBUSB_ERROR_NO_DEVICE; - } - memcpy(&priv->dev_descriptor, &(conn_info.DeviceDescriptor), sizeof(USB_DEVICE_DESCRIPTOR)); - dev->num_configurations = priv->dev_descriptor.bNumConfigurations; - priv->active_config = conn_info.CurrentConfigurationValue; - usbi_dbg("found %d configurations (active conf: %d)", dev->num_configurations, priv->active_config); - // If we can't read the config descriptors, just set the number of confs to zero - if (cache_config_descriptors(dev, handle, device_id) != LIBUSB_SUCCESS) { - dev->num_configurations = 0; - priv->dev_descriptor.bNumConfigurations = 0; - } - safe_closehandle(handle); - - if (conn_info.DeviceAddress > UINT8_MAX) { - usbi_err(ctx, "program assertion failed: device address overflow"); - } - dev->device_address = (uint8_t)conn_info.DeviceAddress; - switch (conn_info.Speed) { - case 0: dev->speed = LIBUSB_SPEED_LOW; break; - case 1: dev->speed = LIBUSB_SPEED_FULL; break; - case 2: dev->speed = LIBUSB_SPEED_HIGH; break; - default: - usbi_warn(ctx, "Got unknown device speed %d", conn_info.Speed); - break; - } - } else { - dev->device_address = UINT8_MAX; // Hubs from HCD have a devaddr of 255 - force_hcd_device_descriptor(dev); - } - - usbi_dbg("(bus: %d, addr: %d, depth: %d, port: %d): '%s'", - dev->bus_number, dev->device_address, priv->depth, priv->port, device_id); - - return LIBUSB_SUCCESS; -} - -// Returns the api type, or 0 if not found/unsupported -static uint8_t get_api_type(struct libusb_context *ctx, - HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data) -{ - // Precedence for filter drivers vs driver is in the order of this array - struct driver_lookup lookup[3] = { - {"\0\0", SPDRP_SERVICE, "driver"}, - {"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"}, - {"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"} - }; - DWORD size, reg_type; - unsigned k, l; - uint8_t api; - - // Check the service & filter names to know the API we should use - for (k=0; k<3; k++) { - if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop, - ®_type, (BYTE*)lookup[k].list, MAX_KEY_LENGTH, &size)) { - // Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ - if (lookup[k].reg_prop == SPDRP_SERVICE) { - // our buffers are MAX_KEY_LENGTH+1 so we can overflow if needed - lookup[k].list[safe_strlen(lookup[k].list)+1] = 0; - } - // MULTI_SZ is a pain to work with. Turn it into something much more manageable - // NB: none of the driver names we check against contain LIST_SEPARATOR, - // (currently ';'), so even if an unsuported one does, it's not an issue - for (l=0; (lookup[k].list[l] != 0) || (lookup[k].list[l+1] != 0); l++) { - if (lookup[k].list[l] == 0) { - lookup[k].list[l] = LIST_SEPARATOR; - } - } - upperize(lookup[k].list); - usbi_dbg("%s(s): %s", lookup[k].designation, lookup[k].list); - } else { - if (GetLastError() != ERROR_INVALID_DATA) { - usbi_dbg("could not access %s: %s", lookup[k].designation, windows_error_str(0)); - } - lookup[k].list[0] = 0; - } - } - - for (api=1; api<USB_API_MAX; api++) { - for (k=0; k<3; k++) { - if (is_api_driver(lookup[k].list, api)) { - usbi_dbg("matched %s name against %s", lookup[k].designation, usb_api_backend[api].designation); - break; - } - } - if (k >= 3) continue; - return api; - } - return 0; -} - -static int set_composite_interface(struct libusb_context* ctx, struct libusb_device* dev, - char* dev_interface_path, char* device_id, uint8_t api) -{ - unsigned i; - struct windows_device_priv *priv = _device_priv(dev); - int interface_number; - - if (priv->apib->id != USB_API_COMPOSITE) { - usbi_err(ctx, "program assertion failed: '%s' is not composite", device_id); - return LIBUSB_ERROR_NO_DEVICE; - } - - // Because MI_## are not necessarily in sequential order (some composite - // devices will have only MI_00 & MI_03 for instance), we retrieve the actual - // interface number from the path's MI value - interface_number = 0; - for (i=0; device_id[i] != 0; ) { - if ( (device_id[i++] == 'M') && (device_id[i++] == 'I') - && (device_id[i++] == '_') ) { - interface_number = (device_id[i++] - '0')*10; - interface_number += device_id[i] - '0'; - break; - } - } - - if (device_id[i] == 0) { - usbi_warn(ctx, "failure to read interface number for %s. Using default value %d", - device_id, interface_number); - } - - if (priv->usb_interface[interface_number].path != NULL) { - usbi_warn(ctx, "interface[%d] already set - ignoring: %s", interface_number, device_id); - return LIBUSB_ERROR_ACCESS; - } - - usbi_dbg("interface[%d] = %s", interface_number, dev_interface_path); - priv->usb_interface[interface_number].path = dev_interface_path; - priv->usb_interface[interface_number].apib = &usb_api_backend[api]; - priv->composite_api_flags |= 1<<api; - - return LIBUSB_SUCCESS; -} - -/* - * get_device_list: libusb backend device enumeration function - */ -static int windows_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs) -{ - struct discovered_devs *discdevs = *_discdevs; - HDEVINFO dev_info = { 0 }; - char* usb_class[2] = {"USB", "NUSB3"}; - SP_DEVINFO_DATA dev_info_data; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL; -#define MAX_ENUM_GUIDS 64 - const GUID* guid[MAX_ENUM_GUIDS]; -#define HCD_PASS 0 -#define HUB_PASS 1 -#define GEN_PASS 2 -#define DEV_PASS 3 - int r = LIBUSB_SUCCESS; - int class_index = 0; - unsigned int nb_guids, pass, i, j, ancestor; - char path[MAX_PATH_LENGTH]; - char strbuf[MAX_PATH_LENGTH]; - struct libusb_device *dev, *parent_dev; - struct windows_device_priv *priv, *parent_priv; - char* dev_interface_path = NULL; - char* dev_id_path = NULL; - unsigned long session_id; - DWORD size, reg_type, port_nr, install_state; - BOOL b = FALSE; - HKEY key; - WCHAR guid_string_w[MAX_GUID_STRING_LENGTH]; - GUID* if_guid; - LONG s; - uint8_t api; - // Keep a list of newly allocated devs to unref - libusb_device** unref_list; - unsigned int unref_size = 64; - unsigned int unref_cur = 0; - - // PASS 1 : (re)enumerate HCDs (allows for HCD hotplug) - // PASS 2 : (re)enumerate HUBS - // PASS 3 : (re)enumerate generic USB devices (including driverless) - // and list additional USB device interface GUIDs to explore - // PASS 4 : (re)enumerate master USB devices that have a device interface - // PASS 5+: (re)enumerate device interfaced GUIDs and set the device interfaces. - - // Init the GUID table - guid[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER; - guid[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB; - guid[GEN_PASS] = NULL; - guid[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE; - nb_guids = DEV_PASS+1; - - unref_list = malloc(unref_size*sizeof(libusb_device*)); - if (unref_list == NULL) { - return LIBUSB_ERROR_NO_MEM; - } - - for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) { -//#define ENUM_DEBUG -#ifdef ENUM_DEBUG - switch(pass) { - case HCD_PASS: - usbi_dbg("PROCESSING HCDs %s", guid_to_string(guid[pass])); - break; - case HUB_PASS: - usbi_dbg("PROCESSING HUBs %s", guid_to_string(guid[pass])); - break; - case DEV_PASS: - usbi_dbg("PROCESSING DEVs %s", guid_to_string(guid[pass])); - break; - case GEN_PASS: - usbi_dbg("PROCESSING GENs"); - break; - default: - usbi_dbg("PROCESSING EXTs %s", guid_to_string(guid[pass])); - break; - } -#endif - for (i = 0; ; i++) { - // safe loop: free up any (unprotected) dynamic resource - // NB: this is always executed before breaking the loop - safe_free(dev_interface_details); - safe_free(dev_interface_path); - safe_free(dev_id_path); - session_id = 0; - priv = parent_priv = NULL; - dev = parent_dev = NULL; - - // Safe loop: end of loop conditions - if (r != LIBUSB_SUCCESS) { - break; - } - if ((pass == HCD_PASS) && (i == UINT8_MAX)) { - usbi_warn(ctx, "program assertion failed - found more than %d buses, skipping the rest.", UINT8_MAX); - break; - } - if (pass != GEN_PASS) { - // Except for GEN, all passes deal with device interfaces - dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid[pass], i); - if (dev_interface_details == NULL) { - break; - } else { - dev_interface_path = sanitize_path(dev_interface_details->DevicePath); - if (dev_interface_path == NULL) { - usbi_warn(ctx, "could not sanitize device interface path for '%s'", dev_interface_details->DevicePath); - continue; - } - } - } else { - // Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are - // being listed under the "NUSB3" PnP Symbolic Name rather than "USB" - while ( (class_index < 2) && - (!(b = get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i))) ) { - class_index++; - i = 0; - } - if (!b) break; - } - - // Read the Device ID path. This is what we'll use as UID - // Note that if the device is plugged in a different port or hub, the Device ID changes - if (CM_Get_Device_IDA(dev_info_data.DevInst, path, sizeof(path), 0) != CR_SUCCESS) { - usbi_warn(ctx, "could not read the device id path for devinst %X, skipping", - dev_info_data.DevInst); - continue; - } - dev_id_path = sanitize_path(path); - if (dev_id_path == NULL) { - usbi_warn(ctx, "could not sanitize device id path for devinst %X, skipping", - dev_info_data.DevInst); - continue; - } -#ifdef ENUM_DEBUG - usbi_dbg("PRO: %s", dev_id_path); -#endif - - // The SPDRP_ADDRESS for USB devices is the device port number on the hub - port_nr = 0; - if ((pass >= HUB_PASS) && (pass <= GEN_PASS)) { - if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ADDRESS, - ®_type, (BYTE*)&port_nr, 4, &size)) - || (size != 4) ) { - usbi_warn(ctx, "could not retrieve port number for device '%s', skipping: %s", - dev_id_path, windows_error_str(0)); - continue; - } - } - - // Set API to use or get additional data from generic pass - api = USB_API_UNSUPPORTED; - switch (pass) { - case HCD_PASS: - break; - case GEN_PASS: - // We use the GEN pass to detect driverless devices... - size = sizeof(strbuf); - if (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_DRIVER, - ®_type, (BYTE*)strbuf, size, &size)) { - usbi_info(ctx, "The following device has no driver: '%s'", dev_id_path); - usbi_info(ctx, "libusb will not be able to access it."); - } - // ...and to add the additional device interface GUIDs - key = pSetupDiOpenDevRegKey(dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); - if (key != INVALID_HANDLE_VALUE) { - size = sizeof(guid_string_w); - s = pRegQueryValueExW(key, L"DeviceInterfaceGUIDs", NULL, ®_type, - (BYTE*)guid_string_w, &size); - pRegCloseKey(key); - if (s == ERROR_SUCCESS) { - if (nb_guids >= MAX_ENUM_GUIDS) { - // If this assert is ever reported, grow a GUID table dynamically - usbi_err(ctx, "program assertion failed: too many GUIDs"); - LOOP_BREAK(LIBUSB_ERROR_OVERFLOW); - } - if_guid = calloc(1, sizeof(GUID)); - pCLSIDFromString(guid_string_w, if_guid); - guid[nb_guids++] = if_guid; - usbi_dbg("extra GUID: %s", guid_to_string(if_guid)); - } - } - break; - default: - // Get the API type (after checking that the driver installation is OK) - if ( (!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE, - ®_type, (BYTE*)&install_state, 4, &size)) - || (size != 4) ){ - usbi_warn(ctx, "could not detect installation state of driver for '%s': %s", - dev_id_path, windows_error_str(0)); - } else if (install_state != 0) { - usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %d) - skipping", - dev_id_path, install_state); - continue; - } - api = get_api_type(ctx, &dev_info, &dev_info_data); - break; - } - - // Find parent device (for the passes that need it) - switch (pass) { - case HCD_PASS: - case DEV_PASS: - case HUB_PASS: - break; - default: - // Go through the ancestors until we see a face we recognize - parent_dev = NULL; - for (ancestor = 1; parent_dev == NULL; ancestor++) { - session_id = get_ancestor_session_id(dev_info_data.DevInst, ancestor); - if (session_id == 0) { - break; - } - parent_dev = usbi_get_device_by_session_id(ctx, session_id); - } - if (parent_dev == NULL) { - usbi_dbg("unlisted ancestor for '%s' (newly connected, etc.) - ignoring", dev_id_path); - continue; - } - parent_priv = _device_priv(parent_dev); - // virtual USB devices are also listed during GEN - don't process these yet - if ( (pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB) ) { - continue; - } - break; - } - - // Create new or match existing device, using the (hashed) device_id as session id - if (pass <= DEV_PASS) { // For subsequent passes, we'll lookup the parent - // These are the passes that create "new" devices - session_id = htab_hash(dev_id_path); - dev = usbi_get_device_by_session_id(ctx, session_id); - if (dev == NULL) { - if (pass == DEV_PASS) { - // This can occur if the OS only reports a newly plugged device after we started enum - usbi_warn(ctx, "'%s' was only detected in late pass (newly connected device?)" - " - ignoring", dev_id_path); - continue; - } - usbi_dbg("allocating new device for session [%X]", session_id); - if ((dev = usbi_alloc_device(ctx, session_id)) == NULL) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - windows_device_priv_init(dev); - // Keep track of devices that need unref - unref_list[unref_cur++] = dev; - if (unref_cur > unref_size) { - unref_size += 64; - unref_list = realloc(unref_list, unref_size*sizeof(libusb_device*)); - if (unref_list == NULL) { - usbi_err(ctx, "could not realloc list for unref - aborting."); - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - } - } else { - usbi_dbg("found existing device for session [%X] (%d.%d)", - session_id, dev->bus_number, dev->device_address); - } - priv = _device_priv(dev); - } - - // Setup device - switch (pass) { - case HCD_PASS: - dev->bus_number = (uint8_t)(i + 1); // bus 0 is reserved for disconnected - dev->device_address = 0; - dev->num_configurations = 0; - priv->apib = &usb_api_backend[USB_API_HUB]; - priv->depth = UINT8_MAX; // Overflow to 0 for HCD Hubs - priv->path = dev_interface_path; dev_interface_path = NULL; - break; - case HUB_PASS: - case DEV_PASS: - // If the device has already been setup, don't do it again - if (priv->path != NULL) - break; - // Take care of API initialization - priv->path = dev_interface_path; dev_interface_path = NULL; - priv->apib = &usb_api_backend[api]; - switch(api) { - case USB_API_COMPOSITE: - case USB_API_HUB: - break; - default: - // For other devices, the first interface is the same as the device - priv->usb_interface[0].path = malloc(safe_strlen(priv->path)+1); - if (priv->usb_interface[0].path != NULL) { - safe_strcpy(priv->usb_interface[0].path, safe_strlen(priv->path)+1, priv->path); - } - // The following is needed if we want API calls to work for both simple - // and composite devices. - for(j=0; j<USB_MAXINTERFACES; j++) { - priv->usb_interface[j].apib = &usb_api_backend[api]; - } - break; - } - break; - case GEN_PASS: - r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_id_path, dev_info_data.DevInst); - if (r == LIBUSB_SUCCESS) { - // Append device to the list of discovered devices - discdevs = discovered_devs_append(*_discdevs, dev); - if (!discdevs) { - LOOP_BREAK(LIBUSB_ERROR_NO_MEM); - } - *_discdevs = discdevs; - } else if (r == LIBUSB_ERROR_NO_DEVICE) { - // This can occur if the device was disconnected but Windows hasn't - // refreshed its enumeration yet - in that case, we ignore the device - r = LIBUSB_SUCCESS; - } - break; - default: // later passes - if (parent_priv->apib->id == USB_API_COMPOSITE) { - usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data); - switch (set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api)) { - case LIBUSB_SUCCESS: - dev_interface_path = NULL; - break; - case LIBUSB_ERROR_ACCESS: - // interface has already been set => make sure dev_interface_path is freed then - break; - default: - LOOP_BREAK(r); - break; - } - } - break; - } - } - } - - // Free any additional GUIDs - for (pass = DEV_PASS+1; pass < nb_guids; pass++) { - safe_free(guid[pass]); - } - - // Unref newly allocated devs - for (i=0; i<unref_cur; i++) { - safe_unref_device(unref_list[i]); - } - safe_free(unref_list); - - return r; -} - -/* - * exit: libusb backend deinitialization function - */ -static void windows_exit(void) -{ - int i; - HANDLE semaphore; - char sem_name[11+1+8]; // strlen(libusb_init)+'\0'+(32-bit hex PID) - - sprintf(sem_name, "libusb_init%08X", (unsigned int)GetCurrentProcessId()&0xFFFFFFFF); - semaphore = CreateSemaphoreA(NULL, 1, 1, sem_name); - if (semaphore == NULL) { - return; - } - - // A successful wait brings our semaphore count to 0 (unsignaled) - // => any concurent wait stalls until the semaphore release - if (WaitForSingleObject(semaphore, INFINITE) != WAIT_OBJECT_0) { - CloseHandle(semaphore); - return; - } - - // Only works if exits and inits are balanced exactly - if (--concurrent_usage < 0) { // Last exit - for (i=0; i<USB_API_MAX; i++) { - usb_api_backend[i].exit(); - } - exit_polling(); - - if (timer_thread) { - SetEvent(timer_request[1]); // actually the signal to quit the thread. - if (WAIT_OBJECT_0 != WaitForSingleObject(timer_thread, INFINITE)) { - usbi_dbg("could not wait for timer thread to quit"); - TerminateThread(timer_thread, 1); - } - CloseHandle(timer_thread); - timer_thread = NULL; - } - for (i = 0; i < 2; i++) { - if (timer_request[i]) { - CloseHandle(timer_request[i]); - timer_request[i] = NULL; - } - } - if (timer_response) { - CloseHandle(timer_response); - timer_response = NULL; - } - if (timer_mutex) { - CloseHandle(timer_mutex); - timer_mutex = NULL; - } - htab_destroy(); - } - - ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1 - CloseHandle(semaphore); -} - -static int windows_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - - memcpy(buffer, &(priv->dev_descriptor), DEVICE_DESC_LENGTH); - *host_endian = 0; - - return LIBUSB_SUCCESS; -} - -static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - PUSB_CONFIGURATION_DESCRIPTOR config_header; - size_t size; - - // config index is zero based - if (config_index >= dev->num_configurations) - return LIBUSB_ERROR_INVALID_PARAM; - - if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL)) - return LIBUSB_ERROR_NOT_FOUND; - - config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[config_index]; - - size = min(config_header->wTotalLength, len); - memcpy(buffer, priv->config_descriptor[config_index], size); - - return LIBUSB_SUCCESS; -} - -/* - * return the cached copy of the active config descriptor - */ -static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) -{ - struct windows_device_priv *priv = _device_priv(dev); - - if (priv->active_config == 0) - return LIBUSB_ERROR_NOT_FOUND; - - // config index is zero based - return windows_get_config_descriptor(dev, (uint8_t)(priv->active_config-1), buffer, len, host_endian); -} - -static int windows_open(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - - if (priv->apib == NULL) { - usbi_err(ctx, "program assertion failed - device is not initialized"); - return LIBUSB_ERROR_NO_DEVICE; - } - - return priv->apib->open(dev_handle); -} - -static void windows_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - priv->apib->close(dev_handle); -} - -static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - if (priv->active_config == 0) { - *config = 0; - return LIBUSB_ERROR_NOT_FOUND; - } - - *config = priv->active_config; - return LIBUSB_SUCCESS; -} - -/* - * from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver - * does not currently expose a service that allows higher-level drivers to set - * the configuration." - */ -static int windows_set_configuration(struct libusb_device_handle *dev_handle, int config) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int r = LIBUSB_SUCCESS; - - if (config >= USB_MAXCONFIG) - return LIBUSB_ERROR_INVALID_PARAM; - - r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE, - LIBUSB_REQUEST_SET_CONFIGURATION, (uint16_t)config, - 0, NULL, 0, 1000); - - if (r == LIBUSB_SUCCESS) { - priv->active_config = (uint8_t)config; - } - return r; -} - -static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - if (iface >= USB_MAXINTERFACES) - return LIBUSB_ERROR_INVALID_PARAM; - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints= 0; - - r = priv->apib->claim_interface(dev_handle, iface); - - if (r == LIBUSB_SUCCESS) { - r = windows_assign_endpoints(dev_handle, iface, 0); - } - - return r; -} - -static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - int r = LIBUSB_SUCCESS; - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - safe_free(priv->usb_interface[iface].endpoint); - priv->usb_interface[iface].nb_endpoints= 0; - - r = priv->apib->set_interface_altsetting(dev_handle, iface, altsetting); - - if (r == LIBUSB_SUCCESS) { - r = windows_assign_endpoints(dev_handle, iface, altsetting); - } - - return r; -} - -static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - - return priv->apib->release_interface(dev_handle, iface); -} - -static int windows_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->apib->clear_halt(dev_handle, endpoint); -} - -static int windows_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->apib->reset_device(dev_handle); -} - -// The 3 functions below are unlikely to ever get supported on Windows -static int windows_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static int windows_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface) -{ - return LIBUSB_ERROR_NOT_SUPPORTED; -} - -static void windows_destroy_device(struct libusb_device *dev) -{ - windows_device_priv_release(dev); -} - -static void windows_clear_transfer_priv(struct usbi_transfer *itransfer) -{ - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - - usbi_free_fd(transfer_priv->pollable_fd.fd); -#if defined(AUTO_CLAIM) - // When auto claim is in use, attempt to release the auto-claimed interface - auto_release(itransfer); -#endif -} - -static int submit_bulk_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_bulk_transfer(itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)((transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT)); -#if !defined(DYNAMIC_FDS) - usbi_fd_notification(ctx); -#endif - - return LIBUSB_SUCCESS; -} - -static int submit_iso_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_iso_transfer(itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, - (short)((transfer->endpoint & LIBUSB_ENDPOINT_IN)?POLLIN:POLLOUT)); -#if !defined(DYNAMIC_FDS) - usbi_fd_notification(ctx); -#endif - - return LIBUSB_SUCCESS; -} - -static int submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int r; - - r = priv->apib->submit_control_transfer(itransfer); - if (r != LIBUSB_SUCCESS) { - return r; - } - - usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN); -#if !defined(DYNAMIC_FDS) - usbi_fd_notification(ctx); -#endif - - return LIBUSB_SUCCESS; - -} - -static int windows_submit_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return submit_control_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return submit_bulk_transfer(itransfer); - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return submit_iso_transfer(itransfer); - default: - usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static int windows_abort_control(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_control(itransfer); -} - -static int windows_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->apib->abort_transfers(itransfer); -} - -static int windows_cancel_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); -#if defined(FORCE_INSTANT_TIMEOUTS) - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - - // Forces instant overlapped completion on timeouts - use at your own risks - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) { - transfer_priv->pollable_fd.overlapped->Internal &= ~STATUS_PENDING; - } -#endif - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return windows_abort_control(itransfer); - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - return windows_abort_transfers(itransfer); - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - return LIBUSB_ERROR_INVALID_PARAM; - } -} - -static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int status; - - usbi_dbg("handling I/O completion with errcode %d", io_result); - - switch(io_result) { - case NO_ERROR: - status = priv->apib->copy_transfer_data(itransfer, io_size); - break; - case ERROR_GEN_FAILURE: - usbi_dbg("detected endpoint stall"); - status = LIBUSB_TRANSFER_STALL; - break; - case ERROR_SEM_TIMEOUT: - usbi_dbg("detected semaphore timeout"); - status = LIBUSB_TRANSFER_TIMED_OUT; - break; - case ERROR_OPERATION_ABORTED: - if (itransfer->flags & USBI_TRANSFER_TIMED_OUT) { - usbi_dbg("detected timeout"); - status = LIBUSB_TRANSFER_TIMED_OUT; - } else { - usbi_dbg("detected operation aborted"); - status = LIBUSB_TRANSFER_CANCELLED; - } - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(0)); - status = LIBUSB_TRANSFER_ERROR; - break; - } - windows_clear_transfer_priv(itransfer); // Cancel polling - usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status); -} - -static void windows_handle_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - - switch (transfer->type) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - case LIBUSB_TRANSFER_TYPE_BULK: - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - windows_transfer_callback (itransfer, io_result, io_size); - break; - default: - usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type); - } -} - -static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready) -{ - struct windows_transfer_priv* transfer_priv = NULL; - POLL_NFDS_TYPE i = 0; - bool found = false; - struct usbi_transfer *transfer; - DWORD io_size, io_result; - - usbi_mutex_lock(&ctx->open_devs_lock); - for (i = 0; i < nfds && num_ready > 0; i++) { - - usbi_dbg("checking fd %d with revents = %04x", fds[i].fd, fds[i].revents); - - if (!fds[i].revents) { - continue; - } - - num_ready--; - - // Because a Windows OVERLAPPED is used for poll emulation, - // a pollable fd is created and stored with each transfer - usbi_mutex_lock(&ctx->flying_transfers_lock); - list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) { - transfer_priv = usbi_transfer_get_os_priv(transfer); - if (transfer_priv->pollable_fd.fd == fds[i].fd) { - found = true; - break; - } - } - usbi_mutex_unlock(&ctx->flying_transfers_lock); - - if (found) { - // Handle async requests that completed synchronously first - if (HasOverlappedIoCompletedSync(transfer_priv->pollable_fd.overlapped)) { - io_result = NO_ERROR; - io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh; - // Regular async overlapped - } else if (GetOverlappedResult(transfer_priv->pollable_fd.handle, - transfer_priv->pollable_fd.overlapped, &io_size, false)) { - io_result = NO_ERROR; - } else { - io_result = GetLastError(); - } - usbi_remove_pollfd(ctx, transfer_priv->pollable_fd.fd); - // let handle_callback free the event using the transfer wfd - // If you don't use the transfer wfd, you run a risk of trying to free a - // newly allocated wfd that took the place of the one from the transfer. - windows_handle_callback(transfer, io_result, io_size); - } else { - usbi_err(ctx, "could not find a matching transfer for fd %x", fds[i]); - return LIBUSB_ERROR_NOT_FOUND; - } - } - - usbi_mutex_unlock(&ctx->open_devs_lock); - return LIBUSB_SUCCESS; -} - -/* - * Monotonic and real time functions - */ -unsigned __stdcall windows_clock_gettime_threaded(void* param) -{ - LARGE_INTEGER hires_counter, li_frequency; - LONG nb_responses; - int timer_index; - - // Init - find out if we have access to a monotonic (hires) timer - if (!QueryPerformanceFrequency(&li_frequency)) { - usbi_dbg("no hires timer available on this platform"); - hires_frequency = 0; - hires_ticks_to_ps = UINT64_C(0); - } else { - hires_frequency = li_frequency.QuadPart; - // The hires frequency can go as high as 4 GHz, so we'll use a conversion - // to picoseconds to compute the tv_nsecs part in clock_gettime - hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; - usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); - } - - // Main loop - wait for requests - while (1) { - timer_index = WaitForMultipleObjects(2, timer_request, FALSE, INFINITE) - WAIT_OBJECT_0; - if ( (timer_index != 0) && (timer_index != 1) ) { - usbi_dbg("failure to wait on requests: %s", windows_error_str(0)); - continue; - } - if (request_count[timer_index] == 0) { - // Request already handled - ResetEvent(timer_request[timer_index]); - // There's still a possiblity that a thread sends a request between the - // time we test request_count[] == 0 and we reset the event, in which case - // the request would be ignored. The simple solution to that is to test - // request_count again and process requests if non zero. - if (request_count[timer_index] == 0) - continue; - } - switch (timer_index) { - case 0: - WaitForSingleObject(timer_mutex, INFINITE); - // Requests to this thread are for hires always - if (QueryPerformanceCounter(&hires_counter) != 0) { - timer_tp.tv_sec = (long)(hires_counter.QuadPart / hires_frequency); - timer_tp.tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency)/1000) * hires_ticks_to_ps); - } else { - // Fallback to real-time if we can't get monotonic value - // Note that real-time clock does not wait on the mutex or this thread. - windows_clock_gettime(USBI_CLOCK_REALTIME, &timer_tp); - } - ReleaseMutex(timer_mutex); - - nb_responses = InterlockedExchange((LONG*)&request_count[0], 0); - if ( (nb_responses) - && (ReleaseSemaphore(timer_response, nb_responses, NULL) == 0) ) { - usbi_dbg("unable to release timer semaphore %d: %s", windows_error_str(0)); - } - continue; - case 1: // time to quit - usbi_dbg("timer thread quitting"); - return 0; - } - } - usbi_dbg("ERROR: broken timer thread"); - return 1; -} - -static int windows_clock_gettime(int clk_id, struct timespec *tp) -{ - FILETIME filetime; - ULARGE_INTEGER rtime; - DWORD r; - switch(clk_id) { - case USBI_CLOCK_MONOTONIC: - if (hires_frequency != 0) { - while (1) { - InterlockedIncrement((LONG*)&request_count[0]); - SetEvent(timer_request[0]); - r = WaitForSingleObject(timer_response, TIMER_REQUEST_RETRY_MS); - switch(r) { - case WAIT_OBJECT_0: - WaitForSingleObject(timer_mutex, INFINITE); - *tp = timer_tp; - ReleaseMutex(timer_mutex); - return LIBUSB_SUCCESS; - case WAIT_TIMEOUT: - usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?"); - break; // Retry until successful - default: - usbi_dbg("WaitForSingleObject failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_OTHER; - } - } - } - // Fall through and return real-time if monotonic was not detected @ timer init - case USBI_CLOCK_REALTIME: - // We follow http://msdn.microsoft.com/en-us/library/ms724928%28VS.85%29.aspx - // with a predef epoch_time to have an epoch that starts at 1970.01.01 00:00 - // Note however that our resolution is bounded by the Windows system time - // functions and is at best of the order of 1 ms (or, usually, worse) - GetSystemTimeAsFileTime(&filetime); - rtime.LowPart = filetime.dwLowDateTime; - rtime.HighPart = filetime.dwHighDateTime; - rtime.QuadPart -= epoch_time; - tp->tv_sec = (long)(rtime.QuadPart / 10000000); - tp->tv_nsec = (long)((rtime.QuadPart % 10000000)*100); - return LIBUSB_SUCCESS; - default: - return LIBUSB_ERROR_INVALID_PARAM; - } -} - - -// NB: MSVC6 does not support named initializers. -const struct usbi_os_backend windows_backend = { - "Windows", - windows_init, - windows_exit, - - windows_get_device_list, - windows_open, - windows_close, - - windows_get_device_descriptor, - windows_get_active_config_descriptor, - windows_get_config_descriptor, - - windows_get_configuration, - windows_set_configuration, - windows_claim_interface, - windows_release_interface, - - windows_set_interface_altsetting, - windows_clear_halt, - windows_reset_device, - - windows_kernel_driver_active, - windows_detach_kernel_driver, - windows_attach_kernel_driver, - - windows_destroy_device, - - windows_submit_transfer, - windows_cancel_transfer, - windows_clear_transfer_priv, - - windows_handle_events, - - windows_clock_gettime, -#if defined(USBI_TIMERFD_AVAILABLE) - NULL, -#endif - sizeof(struct windows_device_priv), - sizeof(struct windows_device_handle_priv), - sizeof(struct windows_transfer_priv), - 0, -}; - - -/* - * USB API backends - */ -static int unsupported_init(struct libusb_context *ctx) { - return LIBUSB_SUCCESS; -} -static int unsupported_exit(void) { - return LIBUSB_SUCCESS; -} -static int unsupported_open(struct libusb_device_handle *dev_handle) { - PRINT_UNSUPPORTED_API(open); -} -static void unsupported_close(struct libusb_device_handle *dev_handle) { - usbi_dbg("unsupported API call for 'close'"); -} -static int unsupported_claim_interface(struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(claim_interface); -} -static int unsupported_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) { - PRINT_UNSUPPORTED_API(set_interface_altsetting); -} -static int unsupported_release_interface(struct libusb_device_handle *dev_handle, int iface) { - PRINT_UNSUPPORTED_API(release_interface); -} -static int unsupported_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) { - PRINT_UNSUPPORTED_API(clear_halt); -} -static int unsupported_reset_device(struct libusb_device_handle *dev_handle) { - PRINT_UNSUPPORTED_API(reset_device); -} -static int unsupported_submit_bulk_transfer(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_bulk_transfer); -} -static int unsupported_submit_iso_transfer(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_iso_transfer); -} -static int unsupported_submit_control_transfer(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(submit_control_transfer); -} -static int unsupported_abort_control(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(abort_control); -} -static int unsupported_abort_transfers(struct usbi_transfer *itransfer) { - PRINT_UNSUPPORTED_API(abort_transfers); -} -static int unsupported_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) { - PRINT_UNSUPPORTED_API(copy_transfer_data); -} - -// These names must be uppercase -const char* hub_driver_names[] = {"USBHUB", "USBHUB3", "NUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3"}; -const char* composite_driver_names[] = {"USBCCGP"}; -const char* winusb_driver_names[] = {"WINUSB"}; -const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = { - { - USB_API_UNSUPPORTED, - "Unsupported API", - &CLASS_GUID_UNSUPPORTED, - NULL, - 0, - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, { - USB_API_HUB, - "HUB API", - &CLASS_GUID_UNSUPPORTED, - hub_driver_names, - sizeof(hub_driver_names)/sizeof(hub_driver_names[0]), - unsupported_init, - unsupported_exit, - unsupported_open, - unsupported_close, - unsupported_claim_interface, - unsupported_set_interface_altsetting, - unsupported_release_interface, - unsupported_clear_halt, - unsupported_reset_device, - unsupported_submit_bulk_transfer, - unsupported_submit_iso_transfer, - unsupported_submit_control_transfer, - unsupported_abort_control, - unsupported_abort_transfers, - unsupported_copy_transfer_data, - }, { - USB_API_COMPOSITE, - "Composite API", - &CLASS_GUID_COMPOSITE, - composite_driver_names, - sizeof(composite_driver_names)/sizeof(composite_driver_names[0]), - composite_init, - composite_exit, - composite_open, - composite_close, - composite_claim_interface, - composite_set_interface_altsetting, - composite_release_interface, - composite_clear_halt, - composite_reset_device, - composite_submit_bulk_transfer, - composite_submit_iso_transfer, - composite_submit_control_transfer, - composite_abort_control, - composite_abort_transfers, - composite_copy_transfer_data, - }, { - USB_API_WINUSB, - "WinUSB API", - &CLASS_GUID_LIBUSB_WINUSB, - winusb_driver_names, - sizeof(winusb_driver_names)/sizeof(winusb_driver_names[0]), - winusb_init, - winusb_exit, - winusb_open, - winusb_close, - winusb_claim_interface, - winusb_set_interface_altsetting, - winusb_release_interface, - winusb_clear_halt, - winusb_reset_device, - winusb_submit_bulk_transfer, - unsupported_submit_iso_transfer, - winusb_submit_control_transfer, - winusb_abort_control, - winusb_abort_transfers, - winusb_copy_transfer_data, - }, -}; - - -/* - * WinUSB API functions - */ -static int winusb_init(struct libusb_context *ctx) -{ - DLL_LOAD(winusb.dll, WinUsb_Initialize, TRUE); - DLL_LOAD(winusb.dll, WinUsb_Free, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetDescriptor, TRUE); - DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings, TRUE); - DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation, TRUE); - DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting, TRUE); - DLL_LOAD(winusb.dll, WinUsb_QueryPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy, TRUE); - DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy, TRUE); - DLL_LOAD(winusb.dll, WinUsb_ReadPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_WritePipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_ControlTransfer, TRUE); - DLL_LOAD(winusb.dll, WinUsb_ResetPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_AbortPipe, TRUE); - DLL_LOAD(winusb.dll, WinUsb_FlushPipe, TRUE); - - api_winusb_available = true; - return LIBUSB_SUCCESS; -} - -static int winusb_exit(void) -{ - return LIBUSB_SUCCESS; -} - -// NB: open and close must ensure that they only handle interface of -// the right API type, as these functions can be called wholesale from -// composite_open(), with interfaces belonging to different APIs -static int winusb_open(struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - - HANDLE file_handle; - int i; - - CHECK_WINUSB_AVAILABLE; - - // WinUSB requires a seperate handle for each interface - for (i = 0; i < USB_MAXINTERFACES; i++) { - if ( (priv->usb_interface[i].path != NULL) - && (priv->usb_interface[i].apib->id == USB_API_WINUSB) ) { - file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); - if (file_handle == INVALID_HANDLE_VALUE) { - usbi_err(ctx, "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0)); - switch(GetLastError()) { - case ERROR_FILE_NOT_FOUND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ACCESS_DENIED: - return LIBUSB_ERROR_ACCESS; - default: - return LIBUSB_ERROR_IO; - } - } - handle_priv->interface_handle[i].dev_handle = file_handle; - } - } - - return LIBUSB_SUCCESS; -} - -static void winusb_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE file_handle; - int i; - - if (!api_winusb_available) - return; - - for (i = 0; i < USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].apib->id == USB_API_WINUSB) { - file_handle = handle_priv->interface_handle[i].dev_handle; - if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) { - CloseHandle(file_handle); - } - } - } -} - -static int winusb_configure_endpoints(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle; - UCHAR policy; - ULONG timeout = 0; - uint8_t endpoint_address; - int i; - - CHECK_WINUSB_AVAILABLE; - - // With handle and enpoints set (in parent), we can setup the default pipe properties - // see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx - for (i=-1; i<priv->usb_interface[iface].nb_endpoints; i++) { - endpoint_address =(i==-1)?0:priv->usb_interface[iface].endpoint[i]; - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout)) { - usbi_dbg("failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address); - } - if (i == -1) continue; // Other policies don't apply to control endpoint - policy = false; - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address); - } - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address); - } - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to disable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address); - } - policy = true; - if (!WinUsb_SetPipePolicy(winusb_handle, endpoint_address, - AUTO_CLEAR_STALL, sizeof(UCHAR), &policy)) { - usbi_dbg("failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address); - } - } - - return LIBUSB_SUCCESS; -} - -static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE); - HANDLE file_handle, winusb_handle; - - CHECK_WINUSB_AVAILABLE; - - // If the device is composite, but using the default Windows composite parent driver (usbccgp) - // or if it's the first WinUSB interface, we get a handle through WinUsb_Initialize(). - if ((is_using_usbccgp) || (iface == 0)) { - // composite device (independent interfaces) or interface 0 - file_handle = handle_priv->interface_handle[iface].dev_handle; - if ((file_handle == 0) || (file_handle == INVALID_HANDLE_VALUE)) { - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUsb_Initialize(file_handle, &winusb_handle)) { - usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0)); - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - - switch(GetLastError()) { - case ERROR_BAD_COMMAND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - default: - usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - handle_priv->interface_handle[iface].api_handle = winusb_handle; - } else { - // For all other interfaces, use WinUsb_GetAssociatedInterface() - winusb_handle = handle_priv->interface_handle[0].api_handle; - // It is a requirement for multiple interface devices using WinUSB that you - // must first claim the first interface before you claim any other - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { -#if defined(AUTO_CLAIM) - file_handle = handle_priv->interface_handle[0].dev_handle; - if (WinUsb_Initialize(file_handle, &winusb_handle)) { - handle_priv->interface_handle[0].api_handle = winusb_handle; - usbi_warn(ctx, "auto-claimed interface 0 (required to claim %d with WinUSB)", iface); - } else { - usbi_warn(ctx, "failed to auto-claim interface 0 (required to claim %d with WinUSB)", iface); - return LIBUSB_ERROR_ACCESS; - } -#else - usbi_warn(ctx, "you must claim interface 0 before you can claim %d with WinUSB", iface); - return LIBUSB_ERROR_ACCESS; -#endif - } - if (!WinUsb_GetAssociatedInterface(winusb_handle, (UCHAR)(iface-1), - &handle_priv->interface_handle[iface].api_handle)) { - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - switch(GetLastError()) { - case ERROR_NO_MORE_ITEMS: // invalid iface - return LIBUSB_ERROR_NOT_FOUND; - case ERROR_BAD_COMMAND: // The device was disconnected - return LIBUSB_ERROR_NO_DEVICE; - case ERROR_ALREADY_EXISTS: // already claimed - return LIBUSB_ERROR_BUSY; - default: - usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0)); - return LIBUSB_ERROR_ACCESS; - } - } - } - usbi_dbg("claimed interface %d", iface); - handle_priv->active_interface = iface; - - return LIBUSB_SUCCESS; -} - -static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HANDLE winusb_handle; - - CHECK_WINUSB_AVAILABLE; - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - return LIBUSB_ERROR_NOT_FOUND; - } - - WinUsb_Free(winusb_handle); - handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE; - - return LIBUSB_SUCCESS; -} - -/* - * Return the first valid interface (of the same API type), for control transfers - */ -static int winusb_get_valid_interface(struct libusb_device_handle *dev_handle) -{ - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - int i; - - for (i=0; i<USB_MAXINTERFACES; i++) { - if ( (handle_priv->interface_handle[i].dev_handle != 0) - && (handle_priv->interface_handle[i].dev_handle != INVALID_HANDLE_VALUE) - && (handle_priv->interface_handle[i].api_handle != 0) - && (handle_priv->interface_handle[i].api_handle != INVALID_HANDLE_VALUE) ) { - return i; - } - } - return -1; -} - -/* - * Lookup interface by endpoint address. -1 if not found - */ -static int interface_by_endpoint(struct windows_device_priv *priv, - struct windows_device_handle_priv *handle_priv, uint8_t endpoint_address) -{ - int i, j; - for (i=0; i<USB_MAXINTERFACES; i++) { - if (handle_priv->interface_handle[i].api_handle == INVALID_HANDLE_VALUE) - continue; - if (handle_priv->interface_handle[i].api_handle == 0) - continue; - if (priv->usb_interface[i].endpoint == NULL) - continue; - for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { - if (priv->usb_interface[i].endpoint[j] == endpoint_address) { - return i; - } - } - } - return -1; -} - -static int winusb_submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv( - transfer->dev_handle); - WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer; - ULONG size; - HANDLE winusb_handle; - int current_interface; - struct winfd wfd; - - CHECK_WINUSB_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE; - - if (size > MAX_CTRL_BUFFER_LENGTH) - return LIBUSB_ERROR_INVALID_PARAM; - - current_interface = winusb_get_valid_interface(transfer->dev_handle); - if (current_interface < 0) { -#if defined(AUTO_CLAIM) - if (auto_claim(transfer, ¤t_interface, USB_API_WINUSB) != LIBUSB_SUCCESS) { - return LIBUSB_ERROR_NOT_FOUND; - } -#else - usbi_warn(ctx, "no interface available for control transfer"); - return LIBUSB_ERROR_NOT_FOUND; -#endif - } - - usbi_dbg("will use interface %d", current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - wfd = usbi_create_fd(winusb_handle, _O_RDONLY); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - // Sending of set configuration control requests from WinUSB creates issues - if ( ((setup->request_type & (0x03 << 5)) == LIBUSB_REQUEST_TYPE_STANDARD) - && (setup->request == LIBUSB_REQUEST_SET_CONFIGURATION) ) { - if (setup->value != priv->active_config) { - usbi_warn(ctx, "cannot set configuration other than the default one"); - usbi_free_fd(wfd.fd); - return LIBUSB_ERROR_INVALID_PARAM; - } - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = 0; - } else { - if (!WinUsb_ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) { - if(GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "WinUsb_ControlTransfer failed: %s", windows_error_str(0)); - usbi_free_fd(wfd.fd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)size; - } - } - - // Use priv_transfer to store data needed for async polling - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - HANDLE winusb_handle; - - CHECK_WINUSB_AVAILABLE; - - if (altsetting > 255) { - return LIBUSB_ERROR_INVALID_PARAM; - } - - winusb_handle = handle_priv->interface_handle[iface].api_handle; - if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) { - usbi_err(ctx, "interface must be claimed first"); - return LIBUSB_ERROR_NOT_FOUND; - } - - if (!WinUsb_SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) { - usbi_err(ctx, "WinUsb_SetCurrentAlternateSetting failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_IO; - } - - return LIBUSB_SUCCESS; -} - -static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_transfer_priv *transfer_priv = (struct windows_transfer_priv*)usbi_transfer_get_os_priv(itransfer); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - HANDLE winusb_handle; - bool direction_in, ret; - int current_interface; - struct winfd wfd; - - CHECK_WINUSB_AVAILABLE; - - transfer_priv->pollable_fd = INVALID_WINFD; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN; - - wfd = usbi_create_fd(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY); - // Always use the handle returned from usbi_create_fd (wfd.handle) - if (wfd.fd < 0) { - return LIBUSB_ERROR_NO_MEM; - } - - if (direction_in) { - usbi_dbg("reading %d bytes", transfer->length); - ret = WinUsb_ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } else { - usbi_dbg("writing %d bytes", transfer->length); - ret = WinUsb_WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped); - } - if (!ret) { - if(GetLastError() != ERROR_IO_PENDING) { - usbi_err(ctx, "WinUsb_Pipe Transfer failed: %s", windows_error_str(0)); - usbi_free_fd(wfd.fd); - return LIBUSB_ERROR_IO; - } - } else { - wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY; - wfd.overlapped->InternalHigh = (DWORD)transfer->length; - } - - transfer_priv->pollable_fd = wfd; - transfer_priv->interface_number = (uint8_t)current_interface; - - return LIBUSB_SUCCESS; -} - -static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSB_AVAILABLE; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface); - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUsb_ResetPipe(winusb_handle, endpoint)) { - usbi_err(ctx, "WinUsb_ResetPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from http://www.winvistatips.com/winusb-bugchecks-t335323.html (confirmed - * through testing as well): - * "You can not call WinUsb_AbortPipe on control pipe. You can possibly cancel - * the control transfer using CancelIo" - */ -static int winusb_abort_control(struct usbi_transfer *itransfer) -{ - // Cancelling of the I/O is done in the parent - return LIBUSB_SUCCESS; -} - -static int winusb_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - HANDLE winusb_handle; - int current_interface; - - CHECK_WINUSB_AVAILABLE; - - current_interface = transfer_priv->interface_number; - if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) { - usbi_err(ctx, "program assertion failed: invalid interface_number"); - return LIBUSB_ERROR_NOT_FOUND; - } - usbi_dbg("will use interface %d", current_interface); - - winusb_handle = handle_priv->interface_handle[current_interface].api_handle; - - if (!WinUsb_AbortPipe(winusb_handle, transfer->endpoint)) { - usbi_err(ctx, "WinUsb_AbortPipe failed: %s", windows_error_str(0)); - return LIBUSB_ERROR_NO_DEVICE; - } - - return LIBUSB_SUCCESS; -} - -/* - * from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper - * (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx): - * "WinUSB does not support host-initiated reset port and cycle port operations" and - * IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the - * IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is - * cycle the pipes (and even then, the control pipe can not be reset using WinUSB) - */ -// TODO (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?) -static int winusb_reset_device(struct libusb_device_handle *dev_handle) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - struct winfd wfd; - HANDLE winusb_handle; - int i, j; - - CHECK_WINUSB_AVAILABLE; - - // Reset any available pipe (except control) - for (i=0; i<USB_MAXINTERFACES; i++) { - winusb_handle = handle_priv->interface_handle[i].api_handle; - for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0;) - { - // Cancel any pollable I/O - usbi_remove_pollfd(ctx, wfd.fd); - usbi_free_fd(wfd.fd); - wfd = handle_to_winfd(winusb_handle); - } - - if ( (winusb_handle != 0) && (winusb_handle != INVALID_HANDLE_VALUE)) { - for (j=0; j<priv->usb_interface[i].nb_endpoints; j++) { - usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]); - if (!WinUsb_AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) { - usbi_err(ctx, "WinUsb_AbortPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - // FlushPipe seems to fail on OUT pipes - if ( (priv->usb_interface[i].endpoint[j] & LIBUSB_ENDPOINT_IN) - && (!WinUsb_FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) ) { - usbi_err(ctx, "WinUsb_FlushPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - if (!WinUsb_ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j])) { - usbi_err(ctx, "WinUsb_ResetPipe (pipe address %02X) failed: %s", - priv->usb_interface[i].endpoint[j], windows_error_str(0)); - } - } - } - } - - return LIBUSB_SUCCESS; -} - -static int winusb_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) -{ - itransfer->transferred += io_size; - return LIBUSB_TRANSFER_COMPLETED; -} - - -/* - * Composite API functions - */ -static int composite_init(struct libusb_context *ctx) -{ - return LIBUSB_SUCCESS; -} - -static int composite_exit(void) -{ - return LIBUSB_SUCCESS; -} - -static int composite_open(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - unsigned api; - int r; - uint8_t flag = 1<<USB_API_WINUSB; - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if (priv->composite_api_flags & flag) { - r = usb_api_backend[api].open(dev_handle); - if (r != LIBUSB_SUCCESS) { - return r; - } - } - flag <<= 1; - } - return LIBUSB_SUCCESS; -} - -static void composite_close(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - unsigned api; - uint8_t flag = 1<<USB_API_WINUSB; - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if (priv->composite_api_flags & flag) { - usb_api_backend[api].close(dev_handle); - } - flag <<= 1; - } -} - -static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib->claim_interface(dev_handle, iface); -} - -static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib->set_interface_altsetting(dev_handle, iface, altsetting); -} - -static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - return priv->usb_interface[iface].apib->release_interface(dev_handle, iface); -} - -static int composite_submit_control_transfer(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int i; - - for (i=0; i<USB_MAXINTERFACES; i++) { - if (priv->usb_interface[i].path != NULL) { - usbi_dbg("using interface %d", i); - return priv->usb_interface[i].apib->submit_control_transfer(itransfer); - } - } - - usbi_err(ctx, "no libusb supported interfaces to complete request"); - return LIBUSB_ERROR_NOT_FOUND; -} - -static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib->submit_bulk_transfer(itransfer); -} - -static int composite_submit_iso_transfer(struct usbi_transfer *itransfer) { - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib->submit_iso_transfer(itransfer); -} - -static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) -{ - struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev); - struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle); - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - int current_interface; - - current_interface = interface_by_endpoint(priv, handle_priv, endpoint); - if (current_interface < 0) { - usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear"); - return LIBUSB_ERROR_NOT_FOUND; - } - - return priv->usb_interface[current_interface].apib->clear_halt(dev_handle, endpoint); -} - -static int composite_abort_control(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib->abort_control(itransfer); -} - -static int composite_abort_transfers(struct usbi_transfer *itransfer) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib->abort_transfers(itransfer); -} - -static int composite_reset_device(struct libusb_device_handle *dev_handle) -{ - struct windows_device_priv *priv = _device_priv(dev_handle->dev); - unsigned api; - int r; - uint8_t flag = 1<<USB_API_WINUSB; - - for (api=USB_API_WINUSB; api<USB_API_MAX; api++) { - if (priv->composite_api_flags & flag) { - r = usb_api_backend[api].reset_device(dev_handle); - if (r != LIBUSB_SUCCESS) { - return r; - } - } - flag <<= 1; - } - return LIBUSB_SUCCESS; -} - -static int composite_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size) -{ - struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); - struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer); - struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev); - - return priv->usb_interface[transfer_priv->interface_number].apib->copy_transfer_data(itransfer, io_size); -} diff --git a/third_party/libusb/libusb/os/windows_usb.h b/third_party/libusb/libusb/os/windows_usb.h deleted file mode 100644 index b629d18..0000000 --- a/third_party/libusb/libusb/os/windows_usb.h +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Windows backend for libusb 1.0 - * Copyright (C) 2009-2010 Pete Batard <pbatard@gmail.com> - * With contributions from Michael Plante, Orin Eman et al. - * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer - * Major code testing contribution by Xiaofan Chen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -#if defined(_MSC_VER) -// disable /W4 MSVC warnings that are benign -#pragma warning(disable:4127) // conditional expression is constant -#pragma warning(disable:4100) // unreferenced formal parameter -#pragma warning(disable:4214) // bit field types other than int -#pragma warning(disable:4201) // nameless struct/union -#endif - -// Windows API default is uppercase - ugh! -#if !defined(bool) -#define bool BOOL -#endif -#if !defined(true) -#define true TRUE -#endif -#if !defined(false) -#define false FALSE -#endif - -// Missing from MSVC6 setupapi.h -#if !defined(SPDRP_ADDRESS) -#define SPDRP_ADDRESS 28 -#endif -#if !defined(SPDRP_INSTALL_STATE) -#define SPDRP_INSTALL_STATE 34 -#endif - -#if defined(__CYGWIN__ ) -// cygwin produces a warning unless these prototypes are defined -extern int _snprintf(char *buffer, size_t count, const char *format, ...); -extern char *_strdup(const char *strSource); -// _beginthreadex is MSVCRT => unavailable for cygwin. Fallback to using CreateThread -#define _beginthreadex(a, b, c, d, e, f) CreateThread(a, b, (LPTHREAD_START_ROUTINE)c, d, e, f) -#endif -#define safe_free(p) do {if (p != NULL) {free((void*)p); p = NULL;}} while(0) -#define safe_closehandle(h) do {if (h != INVALID_HANDLE_VALUE) {CloseHandle(h); h = INVALID_HANDLE_VALUE;}} while(0) -#define safe_min(a, b) min((size_t)(a), (size_t)(b)) -#define safe_strcp(dst, dst_max, src, count) do {memcpy(dst, src, safe_min(count, dst_max)); \ - ((char*)dst)[safe_min(count, dst_max)-1] = 0;} while(0) -#define safe_strcpy(dst, dst_max, src) safe_strcp(dst, dst_max, src, safe_strlen(src)+1) -#define safe_strncat(dst, dst_max, src, count) strncat(dst, src, safe_min(count, dst_max - safe_strlen(dst) - 1)) -#define safe_strcat(dst, dst_max, src) safe_strncat(dst, dst_max, src, safe_strlen(src)+1) -#define safe_strcmp(str1, str2) strcmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2)) -#define safe_strncmp(str1, str2, count) strncmp(((str1==NULL)?"<NULL>":str1), ((str2==NULL)?"<NULL>":str2), count) -#define safe_strlen(str) ((str==NULL)?0:strlen(str)) -#define safe_sprintf _snprintf -#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0) -#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL) -static inline void upperize(char* str) { - size_t i; - if (str == NULL) return; - for (i=0; i<safe_strlen(str); i++) - str[i] = (char)toupper((int)str[i]); -} - -#define MAX_CTRL_BUFFER_LENGTH 4096 -#define MAX_USB_DEVICES 256 -#define MAX_USB_STRING_LENGTH 128 -#define MAX_GUID_STRING_LENGTH 40 -#define MAX_PATH_LENGTH 128 -#define MAX_KEY_LENGTH 256 -#define MAX_TIMER_SEMAPHORES 128 -#define TIMER_REQUEST_RETRY_MS 100 -#define ERR_BUFFER_SIZE 256 -#define LIST_SEPARATOR ';' -#define HTAB_SIZE 1021 - -// http://msdn.microsoft.com/en-us/library/ff545978.aspx -// http://msdn.microsoft.com/en-us/library/ff545972.aspx -// http://msdn.microsoft.com/en-us/library/ff545982.aspx -#if !defined(GUID_DEVINTERFACE_USB_HOST_CONTROLLER) -const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} }; -#endif -#if !defined(GUID_DEVINTERFACE_USB_DEVICE) -const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} }; -#endif -#if !defined(GUID_DEVINTERFACE_USB_HUB) -const GUID GUID_DEVINTERFACE_USB_HUB = { 0xF18A0E88, 0xC30C, 0x11D0, {0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8} }; -#endif -const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; - - -/* - * Multiple USB API backend support - */ -#define USB_API_UNSUPPORTED 0 -#define USB_API_HUB 1 -#define USB_API_COMPOSITE 2 -#define USB_API_WINUSB 3 -#define USB_API_MAX 4 - -#define CLASS_GUID_UNSUPPORTED GUID_NULL -const GUID CLASS_GUID_LIBUSB_WINUSB = { 0x78A1C341, 0x4539, 0x11D3, {0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71} }; -const GUID CLASS_GUID_COMPOSITE = { 0x36FC9E60, 0xC465, 0x11cF, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} }; - -struct windows_usb_api_backend { - const uint8_t id; - const char* designation; - const GUID *class_guid; // The Class GUID (for fallback in case the driver name cannot be read) - const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp" - const uint8_t nb_driver_names; - int (*init)(struct libusb_context *ctx); - int (*exit)(void); - int (*open)(struct libusb_device_handle *dev_handle); - void (*close)(struct libusb_device_handle *dev_handle); - int (*claim_interface)(struct libusb_device_handle *dev_handle, int iface); - int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, int iface, int altsetting); - int (*release_interface)(struct libusb_device_handle *dev_handle, int iface); - int (*clear_halt)(struct libusb_device_handle *dev_handle, unsigned char endpoint); - int (*reset_device)(struct libusb_device_handle *dev_handle); - int (*submit_bulk_transfer)(struct usbi_transfer *itransfer); - int (*submit_iso_transfer)(struct usbi_transfer *itransfer); - int (*submit_control_transfer)(struct usbi_transfer *itransfer); - int (*abort_control)(struct usbi_transfer *itransfer); - int (*abort_transfers)(struct usbi_transfer *itransfer); - int (*copy_transfer_data)(struct usbi_transfer *itransfer, uint32_t io_size); -}; - -extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX]; - -#define PRINT_UNSUPPORTED_API(fname) \ - usbi_dbg("unsupported API call for '" \ - #fname "' (unrecognized device driver)"); \ - return LIBUSB_ERROR_NOT_SUPPORTED; - -/* - * private structures definition - * with inline pseudo constructors/destructors - */ -typedef struct libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR; -struct windows_device_priv { - uint8_t depth; // distance to HCD - uint8_t port; // port number on the hub - struct libusb_device *parent_dev; // access to parent is required for usermode ops - char *path; // device interface path - struct windows_usb_api_backend const *apib; - struct { - char *path; // each interface needs a device interface path, - struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support), - int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS) - uint8_t *endpoint; - } usb_interface[USB_MAXINTERFACES]; - uint8_t composite_api_flags; // composite devices require additional data - uint8_t active_config; - USB_DEVICE_DESCRIPTOR dev_descriptor; - unsigned char **config_descriptor; // list of pointers to the cached config descriptors -}; - -static inline struct windows_device_priv *_device_priv(struct libusb_device *dev) { - return (struct windows_device_priv *)dev->os_priv; -} - -static inline void windows_device_priv_init(libusb_device* dev) { - struct windows_device_priv* p = _device_priv(dev); - int i; - p->depth = 0; - p->port = 0; - p->parent_dev = NULL; - p->path = NULL; - p->apib = &usb_api_backend[USB_API_UNSUPPORTED]; - p->composite_api_flags = 0; - p->active_config = 0; - p->config_descriptor = NULL; - memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR)); - for (i=0; i<USB_MAXINTERFACES; i++) { - p->usb_interface[i].path = NULL; - p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED]; - p->usb_interface[i].nb_endpoints = 0; - p->usb_interface[i].endpoint = NULL; - } -} - -static inline void windows_device_priv_release(libusb_device* dev) { - struct windows_device_priv* p = _device_priv(dev); - int i; - safe_free(p->path); - if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) { - for (i=0; i < dev->num_configurations; i++) - safe_free(p->config_descriptor[i]); - } - safe_free(p->config_descriptor); - for (i=0; i<USB_MAXINTERFACES; i++) { - safe_free(p->usb_interface[i].path); - safe_free(p->usb_interface[i].endpoint); - } -} - -struct interface_handle_t { - HANDLE dev_handle; // WinUSB needs an extra handle for the file - HANDLE api_handle; // used by the API to communicate with the device -}; - -struct windows_device_handle_priv { - int active_interface; - struct interface_handle_t interface_handle[USB_MAXINTERFACES]; -#if defined(AUTO_CLAIM) - int autoclaim_count[USB_MAXINTERFACES]; // For auto-release -#endif -}; - -static inline struct windows_device_handle_priv *_device_handle_priv( - struct libusb_device_handle *handle) -{ - return (struct windows_device_handle_priv *) handle->os_priv; -} - -// used for async polling functions -struct windows_transfer_priv { - struct winfd pollable_fd; - uint8_t interface_number; -}; - -// used to match a device driver (including filter drivers) against a supported API -struct driver_lookup { - char list[MAX_KEY_LENGTH+1];// REG_MULTI_SZ list of services (driver) names - const DWORD reg_prop; // SPDRP registry key to use to retreive list - const char* designation; // internal designation (for debug output) -}; - -/* - * API macros - from libusb-win32 1.x - */ -#define DLL_DECLARE_PREFIXED(api, ret, prefix, name, args) \ - typedef ret (api * __dll_##name##_t)args; \ - static __dll_##name##_t prefix##name = NULL - -#define DLL_LOAD_PREFIXED(dll, prefix, name, ret_on_failure) \ - do { \ - HMODULE h = GetModuleHandleA(#dll); \ - if (!h) \ - h = LoadLibraryA(#dll); \ - if (!h) { \ - if (ret_on_failure) { return LIBUSB_ERROR_NOT_FOUND; }\ - else { break; } \ - } \ - prefix##name = (__dll_##name##_t)GetProcAddress(h, #name);\ - if (prefix##name) break; \ - prefix##name = (__dll_##name##_t)GetProcAddress(h, #name "A");\ - if (prefix##name) break; \ - prefix##name = (__dll_##name##_t)GetProcAddress(h, #name "W");\ - if (prefix##name) break; \ - if(ret_on_failure) \ - return LIBUSB_ERROR_NOT_FOUND; \ - } while(0) - -#define DLL_DECLARE(api, ret, name, args) DLL_DECLARE_PREFIXED(api, ret, , name, args) -#define DLL_LOAD(dll, name, ret_on_failure) DLL_LOAD_PREFIXED(dll, , name, ret_on_failure) - -/* OLE32 dependency */ -DLL_DECLARE_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID)); - -/* SetupAPI dependencies */ -DLL_DECLARE_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA, - const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, - PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO)); -DLL_DECLARE_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM)); -DLL_DECLARE_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO, - PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD)); -DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD)); -DLL_DECLARE_PREFIXED(WINAPI, LONG, p, RegCloseKey, (HKEY)); - -/* - * Windows DDK API definitions. Most of it copied from MinGW's includes - */ -typedef DWORD DEVNODE, DEVINST; -typedef DEVNODE *PDEVNODE, *PDEVINST; -typedef DWORD RETURN_TYPE; -typedef RETURN_TYPE CONFIGRET; - -#define CR_SUCCESS 0x00000000 -#define CR_NO_SUCH_DEVNODE 0x0000000D - -#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE -#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG -#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING -#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE -#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT - -#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS -#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE -#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE -#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS -#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR -#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR -#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION -#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION -#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE -#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE -#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME - -#define USB_GET_NODE_INFORMATION 258 -#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION 260 -#define USB_GET_NODE_CONNECTION_NAME 261 -#define USB_GET_HUB_CAPABILITIES 271 -#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX) -#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 -#endif -#if !defined(USB_GET_HUB_CAPABILITIES_EX) -#define USB_GET_HUB_CAPABILITIES_EX 276 -#endif - -#ifndef METHOD_BUFFERED -#define METHOD_BUFFERED 0 -#endif -#ifndef FILE_ANY_ACCESS -#define FILE_ANY_ACCESS 0x00000000 -#endif -#ifndef FILE_DEVICE_UNKNOWN -#define FILE_DEVICE_UNKNOWN 0x00000022 -#endif -#ifndef FILE_DEVICE_USB -#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN -#endif - -#ifndef CTL_CODE -#define CTL_CODE(DeviceType, Function, Method, Access)( \ - ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) -#endif - -typedef enum USB_CONNECTION_STATUS { - NoDeviceConnected, - DeviceConnected, - DeviceFailedEnumeration, - DeviceGeneralFailure, - DeviceCausedOvercurrent, - DeviceNotEnoughPower, - DeviceNotEnoughBandwidth, - DeviceHubNestedTooDeeply, - DeviceInLegacyHub -} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS; - -typedef enum USB_HUB_NODE { - UsbHub, - UsbMIParent -} USB_HUB_NODE; - -/* Cfgmgr32.dll interface */ -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG)); -DLL_DECLARE(WINAPI, CONFIGRET, CM_Get_Device_IDA, (DEVINST, PCHAR, ULONG, ULONG)); - -#define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ - CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_HUB_CAPABILITIES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_ROOT_HUB_NAME \ - CTL_CODE(FILE_DEVICE_USB, HCD_GET_ROOT_HUB_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_INFORMATION \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_INFORMATION, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_ATTRIBUTES \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_ATTRIBUTES, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_USB_GET_NODE_CONNECTION_NAME \ - CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_NAME, METHOD_BUFFERED, FILE_ANY_ACCESS) - -// Most of the structures below need to be packed -#pragma pack(push, 1) - -typedef struct USB_INTERFACE_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bInterfaceNumber; - UCHAR bAlternateSetting; - UCHAR bNumEndpoints; - UCHAR bInterfaceClass; - UCHAR bInterfaceSubClass; - UCHAR bInterfaceProtocol; - UCHAR iInterface; -} USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR; - -typedef struct USB_CONFIGURATION_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - USHORT wTotalLength; - UCHAR bNumInterfaces; - UCHAR bConfigurationValue; - UCHAR iConfiguration; - UCHAR bmAttributes; - UCHAR MaxPower; -} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR; - -typedef struct USB_CONFIGURATION_DESCRIPTOR_SHORT { - struct { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; - } req; - USB_CONFIGURATION_DESCRIPTOR data; -} USB_CONFIGURATION_DESCRIPTOR_SHORT; - -typedef struct USB_ENDPOINT_DESCRIPTOR { - UCHAR bLength; - UCHAR bDescriptorType; - UCHAR bEndpointAddress; - UCHAR bmAttributes; - USHORT wMaxPacketSize; - UCHAR bInterval; -} USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR; - -typedef struct USB_DESCRIPTOR_REQUEST { - ULONG ConnectionIndex; - struct { - UCHAR bmRequest; - UCHAR bRequest; - USHORT wValue; - USHORT wIndex; - USHORT wLength; - } SetupPacket; -// UCHAR Data[0]; -} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST; - -typedef struct USB_HUB_DESCRIPTOR { - UCHAR bDescriptorLength; - UCHAR bDescriptorType; - UCHAR bNumberOfPorts; - USHORT wHubCharacteristics; - UCHAR bPowerOnToPowerGood; - UCHAR bHubControlCurrent; - UCHAR bRemoveAndPowerMask[64]; -} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR; - -typedef struct USB_ROOT_HUB_NAME { - ULONG ActualLength; - WCHAR RootHubName[1]; -} USB_ROOT_HUB_NAME, *PUSB_ROOT_HUB_NAME; - -typedef struct USB_ROOT_HUB_NAME_FIXED { - ULONG ActualLength; - WCHAR RootHubName[MAX_PATH_LENGTH]; -} USB_ROOT_HUB_NAME_FIXED; - -typedef struct USB_NODE_CONNECTION_NAME { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[1]; -} USB_NODE_CONNECTION_NAME, *PUSB_NODE_CONNECTION_NAME; - -typedef struct USB_NODE_CONNECTION_NAME_FIXED { - ULONG ConnectionIndex; - ULONG ActualLength; - WCHAR NodeName[MAX_PATH_LENGTH]; -} USB_NODE_CONNECTION_NAME_FIXED; - -typedef struct USB_HUB_NAME_FIXED { - union { - USB_ROOT_HUB_NAME_FIXED root; - USB_NODE_CONNECTION_NAME_FIXED node; - } u; -} USB_HUB_NAME_FIXED; - -typedef struct USB_HUB_INFORMATION { - USB_HUB_DESCRIPTOR HubDescriptor; - BOOLEAN HubIsBusPowered; -} USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION; - -typedef struct USB_MI_PARENT_INFORMATION { - ULONG NumberOfInterfaces; -} USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION; - -typedef struct USB_NODE_INFORMATION { - USB_HUB_NODE NodeType; - union { - USB_HUB_INFORMATION HubInformation; - USB_MI_PARENT_INFORMATION MiParentInformation; - } u; -} USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION; - -typedef struct USB_PIPE_INFO { - USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; - ULONG ScheduleOffset; -} USB_PIPE_INFO, *PUSB_PIPE_INFO; - -typedef struct USB_NODE_CONNECTION_INFORMATION_EX { - ULONG ConnectionIndex; - USB_DEVICE_DESCRIPTOR DeviceDescriptor; - UCHAR CurrentConfigurationValue; - UCHAR Speed; - BOOLEAN DeviceIsHub; - USHORT DeviceAddress; - ULONG NumberOfOpenPipes; - USB_CONNECTION_STATUS ConnectionStatus; -// USB_PIPE_INFO PipeList[0]; -} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; - -typedef struct USB_HUB_CAP_FLAGS { - ULONG HubIsHighSpeedCapable:1; - ULONG HubIsHighSpeed:1; - ULONG HubIsMultiTtCapable:1; - ULONG HubIsMultiTt:1; - ULONG HubIsRoot:1; - ULONG HubIsArmedWakeOnConnect:1; - ULONG ReservedMBZ:26; -} USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; - -typedef struct USB_HUB_CAPABILITIES { - ULONG HubIs2xCapable : 1; -} USB_HUB_CAPABILITIES, *PUSB_HUB_CAPABILITIES; - -typedef struct USB_HUB_CAPABILITIES_EX { - USB_HUB_CAP_FLAGS CapabilityFlags; -} USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; - -#pragma pack(pop) - -/* winusb.dll interface */ - -#define SHORT_PACKET_TERMINATE 0x01 -#define AUTO_CLEAR_STALL 0x02 -#define PIPE_TRANSFER_TIMEOUT 0x03 -#define IGNORE_SHORT_PACKETS 0x04 -#define ALLOW_PARTIAL_READS 0x05 -#define AUTO_FLUSH 0x06 -#define RAW_IO 0x07 -#define MAXIMUM_TRANSFER_SIZE 0x08 -#define AUTO_SUSPEND 0x81 -#define SUSPEND_DELAY 0x83 -#define DEVICE_SPEED 0x01 -#define LowSpeed 0x01 -#define FullSpeed 0x02 -#define HighSpeed 0x03 - -typedef enum USBD_PIPE_TYPE { - UsbdPipeTypeControl, - UsbdPipeTypeIsochronous, - UsbdPipeTypeBulk, - UsbdPipeTypeInterrupt -} USBD_PIPE_TYPE; - -typedef struct { - USBD_PIPE_TYPE PipeType; - UCHAR PipeId; - USHORT MaximumPacketSize; - UCHAR Interval; -} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; - -#pragma pack(1) -typedef struct { - UCHAR request_type; - UCHAR request; - USHORT value; - USHORT index; - USHORT length; -} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; -#pragma pack() - -typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; - -DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); -DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); diff --git a/third_party/libusb/libusb/sync.c b/third_party/libusb/libusb/sync.c deleted file mode 100644 index 8eed47b..0000000 --- a/third_party/libusb/libusb/sync.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Synchronous I/O functions for libusb - * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <config.h> -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include "libusbi.h" - -/** - * @defgroup syncio Synchronous device I/O - * - * This page documents libusb's synchronous (blocking) API for USB device I/O. - * This interface is easy to use but has some limitations. More advanced users - * may wish to consider using the \ref asyncio "asynchronous I/O API" instead. - */ - -static void LIBUSB_CALL ctrl_transfer_cb(struct libusb_transfer *transfer) -{ - int *completed = transfer->user_data; - *completed = 1; - usbi_dbg("actual_length=%d", transfer->actual_length); - /* caller interprets result and frees transfer */ -} - -/** \ingroup syncio - * Perform a USB control transfer. - * - * The direction of the transfer is inferred from the bmRequestType field of - * the setup packet. - * - * The wValue, wIndex and wLength fields values should be given in host-endian - * byte order. - * - * \param dev_handle a handle for the device to communicate with - * \param bmRequestType the request type field for the setup packet - * \param bRequest the request field for the setup packet - * \param wValue the value field for the setup packet - * \param wIndex the index field for the setup packet - * \param data a suitably-sized data buffer for either input or output - * (depending on direction bits within bmRequestType) - * \param wLength the length field for the setup packet. The data buffer should - * be at least this size. - * \param timeout timeout (in millseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * \returns on success, the number of bytes actually transferred - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the control request was not supported by the - * device - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failures - */ -int API_EXPORTED libusb_control_transfer(libusb_device_handle *dev_handle, - uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *data, uint16_t wLength, unsigned int timeout) -{ - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - unsigned char *buffer; - int completed = 0; - int r; - - if (!transfer) - return LIBUSB_ERROR_NO_MEM; - - buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + wLength); - if (!buffer) { - libusb_free_transfer(transfer); - return LIBUSB_ERROR_NO_MEM; - } - - libusb_fill_control_setup(buffer, bmRequestType, bRequest, wValue, wIndex, - wLength); - if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) - memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); - - libusb_fill_control_transfer(transfer, dev_handle, buffer, - ctrl_transfer_cb, &completed, timeout); - transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER; - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - return r; - } - - while (!completed) { - r = libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed); - if (r < 0) { - if (r == LIBUSB_ERROR_INTERRUPTED) - continue; - libusb_cancel_transfer(transfer); - while (!completed) - if (libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed) < 0) - break; - libusb_free_transfer(transfer); - return r; - } - } - - if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) - memcpy(data, libusb_control_transfer_get_data(transfer), - transfer->actual_length); - - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - r = transfer->actual_length; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - r = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - r = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - r = LIBUSB_ERROR_NO_DEVICE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - r = LIBUSB_ERROR_OVERFLOW; - break; - default: - usbi_warn(HANDLE_CTX(dev_handle), - "unrecognised status code %d", transfer->status); - r = LIBUSB_ERROR_OTHER; - } - - libusb_free_transfer(transfer); - return r; -} - -static void LIBUSB_CALL bulk_transfer_cb(struct libusb_transfer *transfer) -{ - int *completed = transfer->user_data; - *completed = 1; - usbi_dbg("actual_length=%d", transfer->actual_length); - /* caller interprets results and frees transfer */ -} - -static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *buffer, int length, - int *transferred, unsigned int timeout, unsigned char type) -{ - struct libusb_transfer *transfer = libusb_alloc_transfer(0); - int completed = 0; - int r; - - if (!transfer) - return LIBUSB_ERROR_NO_MEM; - - libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, - bulk_transfer_cb, &completed, timeout); - transfer->type = type; - - r = libusb_submit_transfer(transfer); - if (r < 0) { - libusb_free_transfer(transfer); - return r; - } - - while (!completed) { - r = libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed); - if (r < 0) { - if (r == LIBUSB_ERROR_INTERRUPTED) - continue; - libusb_cancel_transfer(transfer); - while (!completed) - if (libusb_handle_events_completed(HANDLE_CTX(dev_handle), &completed) < 0) - break; - libusb_free_transfer(transfer); - return r; - } - } - - *transferred = transfer->actual_length; - switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - r = 0; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - r = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - r = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - r = LIBUSB_ERROR_OVERFLOW; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - r = LIBUSB_ERROR_NO_DEVICE; - break; - default: - usbi_warn(HANDLE_CTX(dev_handle), - "unrecognised status code %d", transfer->status); - r = LIBUSB_ERROR_OTHER; - } - - libusb_free_transfer(transfer); - return r; -} - -/** \ingroup syncio - * Perform a USB bulk transfer. The direction of the transfer is inferred from - * the direction bits of the endpoint address. - * - * For bulk reads, the <tt>length</tt> field indicates the maximum length of - * data you are expecting to receive. If less data arrives than expected, - * this function will return that data, so be sure to check the - * <tt>transferred</tt> output parameter. - * - * You should also check the <tt>transferred</tt> parameter for bulk writes. - * Not all of the data may have been written. - * - * Also check <tt>transferred</tt> when dealing with a timeout error code. - * libusb may have to split your transfer into a number of chunks to satisfy - * underlying O/S requirements, meaning that the timeout may expire after - * the first few chunks have completed. libusb is careful not to lose any data - * that may have been transferred; do not assume that timeout conditions - * indicate a complete lack of I/O. - * - * \param dev_handle a handle for the device to communicate with - * \param endpoint the address of a valid endpoint to communicate with - * \param data a suitably-sized data buffer for either input or output - * (depending on endpoint) - * \param length for bulk writes, the number of bytes from data to be sent. for - * bulk reads, the maximum number of bytes to receive into the data buffer. - * \param transferred output location for the number of bytes actually - * transferred. - * \param timeout timeout (in millseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * - * \returns 0 on success (and populates <tt>transferred</tt>) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out (and populates - * <tt>transferred</tt>) - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other failures - */ -int API_EXPORTED libusb_bulk_transfer(struct libusb_device_handle *dev_handle, - unsigned char endpoint, unsigned char *data, int length, int *transferred, - unsigned int timeout) -{ - return do_sync_bulk_transfer(dev_handle, endpoint, data, length, - transferred, timeout, LIBUSB_TRANSFER_TYPE_BULK); -} - -/** \ingroup syncio - * Perform a USB interrupt transfer. The direction of the transfer is inferred - * from the direction bits of the endpoint address. - * - * For interrupt reads, the <tt>length</tt> field indicates the maximum length - * of data you are expecting to receive. If less data arrives than expected, - * this function will return that data, so be sure to check the - * <tt>transferred</tt> output parameter. - * - * You should also check the <tt>transferred</tt> parameter for interrupt - * writes. Not all of the data may have been written. - * - * Also check <tt>transferred</tt> when dealing with a timeout error code. - * libusb may have to split your transfer into a number of chunks to satisfy - * underlying O/S requirements, meaning that the timeout may expire after - * the first few chunks have completed. libusb is careful not to lose any data - * that may have been transferred; do not assume that timeout conditions - * indicate a complete lack of I/O. - * - * The default endpoint bInterval value is used as the polling interval. - * - * \param dev_handle a handle for the device to communicate with - * \param endpoint the address of a valid endpoint to communicate with - * \param data a suitably-sized data buffer for either input or output - * (depending on endpoint) - * \param length for bulk writes, the number of bytes from data to be sent. for - * bulk reads, the maximum number of bytes to receive into the data buffer. - * \param transferred output location for the number of bytes actually - * transferred. - * \param timeout timeout (in millseconds) that this function should wait - * before giving up due to no response being received. For an unlimited - * timeout, use value 0. - * - * \returns 0 on success (and populates <tt>transferred</tt>) - * \returns LIBUSB_ERROR_TIMEOUT if the transfer timed out - * \returns LIBUSB_ERROR_PIPE if the endpoint halted - * \returns LIBUSB_ERROR_OVERFLOW if the device offered more data, see - * \ref packetoverflow - * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected - * \returns another LIBUSB_ERROR code on other error - */ -int API_EXPORTED libusb_interrupt_transfer( - struct libusb_device_handle *dev_handle, unsigned char endpoint, - unsigned char *data, int length, int *transferred, unsigned int timeout) -{ - return do_sync_bulk_transfer(dev_handle, endpoint, data, length, - transferred, timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT); -} - diff --git a/third_party/libusb/libusb/version.h b/third_party/libusb/libusb/version.h deleted file mode 100644 index 08e2c872..0000000 --- a/third_party/libusb/libusb/version.h +++ /dev/null @@ -1,18 +0,0 @@ -/* This file is parsed by m4 and windres and RC.EXE so please keep it simple. */ -#ifndef LIBUSB_MAJOR -#define LIBUSB_MAJOR 1 -#endif -#ifndef LIBUSB_MINOR -#define LIBUSB_MINOR 0 -#endif -#ifndef LIBUSB_MICRO -#define LIBUSB_MICRO 9 -#endif -/* LIBUSB_NANO may be used for Windows internal versioning. 0 means unused. */ -#ifndef LIBUSB_NANO -#define LIBUSB_NANO 0 -#endif -/* LIBUSB_RC is the release candidate suffix. Should normally be empty. */ -#ifndef LIBUSB_RC -#define LIBUSB_RC "-rc3" -#endif diff --git a/third_party/libusb/msvc/config.h b/third_party/libusb/msvc/config.h deleted file mode 100644 index 9ac6134..0000000 --- a/third_party/libusb/msvc/config.h +++ /dev/null @@ -1,23 +0,0 @@ -/* config.h. Manual config for MSVC. */ - -#ifndef _MSC_VER -#warn "msvc/config.h shouldn't be included for your development environment." -#error "Please make sure the msvc/ directory is removed from your build path." -#endif - -/* Default visibility */ -#define DEFAULT_VISIBILITY /**/ - -/* Debug message logging */ -//#define ENABLE_DEBUG_LOGGING 1 - -/* Message logging */ -#define ENABLE_LOGGING 1 - -/* Windows backend */ -#define OS_WINDOWS 1 - -/* type of second poll() argument */ -#define POLL_NFDS_TYPE unsigned int - -#include <Winsock2.h> diff --git a/third_party/libusb/msvc/ddk_build.cmd b/third_party/libusb/msvc/ddk_build.cmd deleted file mode 100644 index fa79b82..0000000 --- a/third_party/libusb/msvc/ddk_build.cmd +++ /dev/null @@ -1,106 +0,0 @@ -@rem default builds static library. -@rem you can pass the following arguments (case insensitive): -@rem - "DLL" to build a DLL instead of a static library -@rem - "/MT" to build a static library compatible with MSVC's /MT option (LIBCMT vs MSVCRT) -@echo off - -if Test%BUILD_ALT_DIR%==Test goto usage - -rem process commandline parameters -set TARGET=LIBRARY -set STATIC_LIBC= -set version=1.0 - -if "%1" == "" goto no_more_args -rem /I for case insensitive -if /I Test%1==TestDLL set TARGET=DYNLINK -if /I Test%1==Test/MT set STATIC_LIBC=1 -:no_more_args - -cd ..\libusb\os -echo TARGETTYPE=%TARGET% > target -copy target+..\..\msvc\libusb_sources sources >NUL 2>&1 -del target -@echo on -build -cwgZ -@echo off -if errorlevel 1 goto builderror -cd ..\.. - -set cpudir=i386 -set destType=Win32 -if %_BUILDARCH%==x86 goto isI386 -set cpudir=amd64 -set destType=x64 -:isI386 - -set srcPath=libusb\os\obj%BUILD_ALT_DIR%\%cpudir% - -set dstPath=%destType%\Debug -if %DDKBUILDENV%==chk goto isDebug -set dstPath=%destType%\Release -:isDebug - -if exist %destType% goto md2 -mkdir %destType% -:md2 -if exist %dstPath% goto md3 -mkdir %dstPath% -:md3 -if exist %dstPath%\dll goto md4 -mkdir %dstPath%\dll -:md4 -if exist %dstPath%\lib goto md5 -md %dstPath%\lib -:md5 -if exist %dstPath%\examples goto md6 -md %dstPath%\examples -:md6 -@echo on - -@if /I NOT Test%1==TestDLL goto copylib -copy %srcPath%\libusb-%version%.dll %dstPath%\dll -copy %srcPath%\libusb-%version%.pdb %dstPath%\dll -:copylib -copy %srcPath%\libusb-%version%.lib %dstPath%\lib - -@echo off - -if exist examples\lsusb_ddkbuild goto md7 -md examples\lsusb_ddkbuild -:md7 - -cd examples\lsusb_ddkbuild -copy ..\..\msvc\lsusb_sources sources >NUL 2>&1 -@echo on -build -cwgZ -@echo off -if errorlevel 1 goto buildlsusberror -cd ..\.. - -set srcPath=examples\lsusb_ddkbuild\obj%BUILD_ALT_DIR%\%cpudir% -@echo on - -copy %srcPath%\lsusb.exe %dstPath%\examples -copy %srcPath%\lsusb.pdb %dstPath%\examples - -cd msvc -goto done - - -:builderror -cd ..\..\msvc -echo Build failed -goto done - -:buildlsusberror -cd ..\..\msvc -echo lsusb build failed -goto done - -:usage -echo ddk_build must be run in a WDK build environment -pause -goto done - -:done diff --git a/third_party/libusb/msvc/inttypes.h b/third_party/libusb/msvc/inttypes.h deleted file mode 100644 index 289bb50..0000000 --- a/third_party/libusb/msvc/inttypes.h +++ /dev/null @@ -1,295 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file was original part of the w64 mingw-runtime package. - */ - -/* - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * Modified for libusb/MSVC: Pete Batard <pbatard@gmail.com> - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Date: 2010-04-02 - */ - -#ifndef _MSC_VER -#error This header should only be used with Microsoft compilers -#endif - -/* 7.8 Format conversion of integer types <inttypes.h> */ - -#ifndef _INTTYPES_H_ -#define _INTTYPES_H_ - -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - intmax_t quot; - intmax_t rem; - } imaxdiv_t; - - -/* 7.8.1 Macros for format specifiers - * - * MS runtime does not yet understand C9x standard "ll" - * length specifier. It appears to treat "ll" as "l". - * The non-standard I64 length specifier causes warning in GCC, - * but understood by MS runtime functions. - */ - -/* fprintf macros for signed types */ -#define PRId8 "d" -#define PRId16 "d" -#define PRId32 "d" -#define PRId64 "I64d" - -#define PRIdLEAST8 "d" -#define PRIdLEAST16 "d" -#define PRIdLEAST32 "d" -#define PRIdLEAST64 "I64d" - -#define PRIdFAST8 "d" -#define PRIdFAST16 "d" -#define PRIdFAST32 "d" -#define PRIdFAST64 "I64d" - -#define PRIdMAX "I64d" - -#define PRIi8 "i" -#define PRIi16 "i" -#define PRIi32 "i" -#define PRIi64 "I64i" - -#define PRIiLEAST8 "i" -#define PRIiLEAST16 "i" -#define PRIiLEAST32 "i" -#define PRIiLEAST64 "I64i" - -#define PRIiFAST8 "i" -#define PRIiFAST16 "i" -#define PRIiFAST32 "i" -#define PRIiFAST64 "I64i" - -#define PRIiMAX "I64i" - -#define PRIo8 "o" -#define PRIo16 "o" -#define PRIo32 "o" -#define PRIo64 "I64o" - -#define PRIoLEAST8 "o" -#define PRIoLEAST16 "o" -#define PRIoLEAST32 "o" -#define PRIoLEAST64 "I64o" - -#define PRIoFAST8 "o" -#define PRIoFAST16 "o" -#define PRIoFAST32 "o" -#define PRIoFAST64 "I64o" - -#define PRIoMAX "I64o" - -/* fprintf macros for unsigned types */ -#define PRIu8 "u" -#define PRIu16 "u" -#define PRIu32 "u" -#define PRIu64 "I64u" - - -#define PRIuLEAST8 "u" -#define PRIuLEAST16 "u" -#define PRIuLEAST32 "u" -#define PRIuLEAST64 "I64u" - -#define PRIuFAST8 "u" -#define PRIuFAST16 "u" -#define PRIuFAST32 "u" -#define PRIuFAST64 "I64u" - -#define PRIuMAX "I64u" - -#define PRIx8 "x" -#define PRIx16 "x" -#define PRIx32 "x" -#define PRIx64 "I64x" - -#define PRIxLEAST8 "x" -#define PRIxLEAST16 "x" -#define PRIxLEAST32 "x" -#define PRIxLEAST64 "I64x" - -#define PRIxFAST8 "x" -#define PRIxFAST16 "x" -#define PRIxFAST32 "x" -#define PRIxFAST64 "I64x" - -#define PRIxMAX "I64x" - -#define PRIX8 "X" -#define PRIX16 "X" -#define PRIX32 "X" -#define PRIX64 "I64X" - -#define PRIXLEAST8 "X" -#define PRIXLEAST16 "X" -#define PRIXLEAST32 "X" -#define PRIXLEAST64 "I64X" - -#define PRIXFAST8 "X" -#define PRIXFAST16 "X" -#define PRIXFAST32 "X" -#define PRIXFAST64 "I64X" - -#define PRIXMAX "I64X" - -/* - * fscanf macros for signed int types - * NOTE: if 32-bit int is used for int_fast8_t and int_fast16_t - * (see stdint.h, 7.18.1.3), FAST8 and FAST16 should have - * no length identifiers - */ - -#define SCNd16 "hd" -#define SCNd32 "d" -#define SCNd64 "I64d" - -#define SCNdLEAST16 "hd" -#define SCNdLEAST32 "d" -#define SCNdLEAST64 "I64d" - -#define SCNdFAST16 "hd" -#define SCNdFAST32 "d" -#define SCNdFAST64 "I64d" - -#define SCNdMAX "I64d" - -#define SCNi16 "hi" -#define SCNi32 "i" -#define SCNi64 "I64i" - -#define SCNiLEAST16 "hi" -#define SCNiLEAST32 "i" -#define SCNiLEAST64 "I64i" - -#define SCNiFAST16 "hi" -#define SCNiFAST32 "i" -#define SCNiFAST64 "I64i" - -#define SCNiMAX "I64i" - -#define SCNo16 "ho" -#define SCNo32 "o" -#define SCNo64 "I64o" - -#define SCNoLEAST16 "ho" -#define SCNoLEAST32 "o" -#define SCNoLEAST64 "I64o" - -#define SCNoFAST16 "ho" -#define SCNoFAST32 "o" -#define SCNoFAST64 "I64o" - -#define SCNoMAX "I64o" - -#define SCNx16 "hx" -#define SCNx32 "x" -#define SCNx64 "I64x" - -#define SCNxLEAST16 "hx" -#define SCNxLEAST32 "x" -#define SCNxLEAST64 "I64x" - -#define SCNxFAST16 "hx" -#define SCNxFAST32 "x" -#define SCNxFAST64 "I64x" - -#define SCNxMAX "I64x" - -/* fscanf macros for unsigned int types */ - -#define SCNu16 "hu" -#define SCNu32 "u" -#define SCNu64 "I64u" - -#define SCNuLEAST16 "hu" -#define SCNuLEAST32 "u" -#define SCNuLEAST64 "I64u" - -#define SCNuFAST16 "hu" -#define SCNuFAST32 "u" -#define SCNuFAST64 "I64u" - -#define SCNuMAX "I64u" - -#ifdef _WIN64 -#define PRIdPTR "I64d" -#define PRIiPTR "I64i" -#define PRIoPTR "I64o" -#define PRIuPTR "I64u" -#define PRIxPTR "I64x" -#define PRIXPTR "I64X" -#define SCNdPTR "I64d" -#define SCNiPTR "I64i" -#define SCNoPTR "I64o" -#define SCNxPTR "I64x" -#define SCNuPTR "I64u" -#else -#define PRIdPTR "d" -#define PRIiPTR "i" -#define PRIoPTR "o" -#define PRIuPTR "u" -#define PRIxPTR "x" -#define PRIXPTR "X" -#define SCNdPTR "d" -#define SCNiPTR "i" -#define SCNoPTR "o" -#define SCNxPTR "x" - #define SCNuPTR "u" -#endif - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* - * no length modifier for char types prior to C9x - * MS runtime scanf appears to treat "hh" as "h" - */ - -/* signed char */ -#define SCNd8 "hhd" -#define SCNdLEAST8 "hhd" -#define SCNdFAST8 "hhd" - -#define SCNi8 "hhi" -#define SCNiLEAST8 "hhi" -#define SCNiFAST8 "hhi" - -#define SCNo8 "hho" -#define SCNoLEAST8 "hho" -#define SCNoFAST8 "hho" - -#define SCNx8 "hhx" -#define SCNxLEAST8 "hhx" -#define SCNxFAST8 "hhx" - -/* unsigned char */ -#define SCNu8 "hhu" -#define SCNuLEAST8 "hhu" -#define SCNuFAST8 "hhu" -#endif /* __STDC_VERSION__ >= 199901 */ - - -#ifdef __cplusplus -} -#endif - -#endif /* ndef _INTTYPES_H */ diff --git a/third_party/libusb/msvc/libusb.dsw b/third_party/libusb/msvc/libusb.dsw deleted file mode 100644 index e4de346..0000000 --- a/third_party/libusb/msvc/libusb.dsw +++ /dev/null @@ -1,56 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "libusb_dll"=".\libusb_dll.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "libusb_static"=".\libusb_static.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "lsusb"=".\lsusb.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name libusb_static - End Project Dependency -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/third_party/libusb/msvc/libusb_dll.dsp b/third_party/libusb/msvc/libusb_dll.dsp deleted file mode 100644 index 4754a531..0000000 --- a/third_party/libusb/msvc/libusb_dll.dsp +++ /dev/null @@ -1,190 +0,0 @@ -# Microsoft Developer Studio Project File - Name="libusb_dll" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=libusb_dll - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "libusb_dll.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "libusb_dll.mak" CFG="libusb_dll - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "libusb_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "libusb_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "libusb_dll - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "../Win32/Release/dll" -# PROP Intermediate_Dir "../Win32/Release/dll" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBUSB_DLL_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../libusb" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /FD /EHsc /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /machine:I386 /out:"Win32/Release/dll/libusb-1.0.dll" - -!ELSEIF "$(CFG)" == "libusb_dll - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "../Win32/Debug/dll" -# PROP Intermediate_Dir "../Win32/Debug/dll" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBUSB_DLL_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "../libusb" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /FD /EHsc /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /n -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib setupapi.lib /nologo /dll /debug /machine:I386 /out:"Win32/Debug/dll/libusb-1.0.dll" -# SUBTRACT LINK32 /pdb:none /incremental:no - -!ENDIF - -# Begin Target - -# Name "libusb_dll - Win32 Release" -# Name "libusb_dll - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\libusb\core.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\darwin_usb.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\libusb\descriptor.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\io.c -# End Source File -# Begin Source File - -SOURCE="..\libusb\libusb-1.0.rc" -# End Source File -# Begin Source File - -SOURCE="..\libusb\libusb-1.0.def" -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\linux_usbfs.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\poll_windows.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\sync.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\threads_windows.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\windows_usb.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\config.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\darwin_usb.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\libusb.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\libusbi.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\linux_usbfs.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\poll_posix.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\poll_windows.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\threads_posix.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\threads_windows.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\windows_usb.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group -# End Target -# End Project diff --git a/third_party/libusb/msvc/libusb_sources b/third_party/libusb/msvc/libusb_sources deleted file mode 100644 index 8e8e65c..0000000 --- a/third_party/libusb/msvc/libusb_sources +++ /dev/null @@ -1,36 +0,0 @@ -#TARGETTYPE is not defined, to allow selection between static lib or DLL with ddk_build -TARGETNAME=libusb-1.0 -DLLDEF=..\libusb-1.0.def - -!IFNDEF MSC_WARNING_LEVEL -MSC_WARNING_LEVEL=/W3 -!ENDIF - -!IFDEF STATIC_LIBC -USE_LIBCMT=1 -!ELSE -USE_MSVCRT=1 -!ENDIF - -INCLUDES=..;..\..\msvc;$(DDK_INC_PATH) -C_DEFINES= $(C_DEFINES) $(LIBUSB_DEFINES) /DDDKBUILD - -# http://jpassing.com/2009/10/21/ltcg-issues-with-the-win7amd64-environment-of-wdk-7600/ -# prevents the following error when using the 64 bit static lib with Visual Studio 2010: -# "fatal error C1001: An internal error has occurred in the compiler. -# (compiler file 'f:\dd\vctools\compiler\utc\src\p2\p2symtab.c', line 1823)" -# and the following with Visual Studio 2010: -# "fatal error C1047: The object or library file 'libusb-1.0.lib' was created with -# an older compiler than other objects; rebuild old objects and libraries" -USER_C_FLAGS=/GL- - -TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib - -SOURCES=..\core.c \ - ..\descriptor.c \ - ..\io.c \ - ..\sync.c \ - threads_windows.c \ - poll_windows.c \ - windows_usb.c \ - ..\libusb-1.0.rc diff --git a/third_party/libusb/msvc/libusb_static.dsp b/third_party/libusb/msvc/libusb_static.dsp deleted file mode 100644 index f866a63..0000000 --- a/third_party/libusb/msvc/libusb_static.dsp +++ /dev/null @@ -1,170 +0,0 @@ -# Microsoft Developer Studio Project File - Name="libusb_static" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Static Library" 0x0104 - -CFG=libusb_static - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "libusb_static.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "libusb_static.mak" CFG="libusb_static - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "libusb_static - Win32 Release" (based on "Win32 (x86) Static Library") -!MESSAGE "libusb_static - Win32 Debug" (based on "Win32 (x86) Static Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "libusb_static - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "../Win32/Release/lib" -# PROP Intermediate_Dir "../Win32/Release/lib" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "../libusb" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FR /FD /EHsc /c -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"../Win32/Release/lib/libusb-1.0.lib" - -!ELSEIF "$(CFG)" == "libusb_static - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "../Win32/Debug/lib" -# PROP Intermediate_Dir "../Win32/Debug/lib" -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "../libusb" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /EHsc /c -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /n -LIB32=link.exe -lib -# ADD BASE LIB32 /nologo -# ADD LIB32 /nologo /out:"../Win32/Debug/lib/libusb-1.0.lib" - -!ENDIF - -# Begin Target - -# Name "libusb_static - Win32 Release" -# Name "libusb_static - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=..\libusb\core.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\darwin_usb.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\libusb\descriptor.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\io.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\linux_usbfs.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\poll_windows.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\sync.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\threads_windows.c -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\windows_usb.c -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\config.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\darwin_usb.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\libusb.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\libusbi.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\linux_usbfs.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\poll_posix.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\poll_windows.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\threads_posix.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\threads_windows.h -# End Source File -# Begin Source File - -SOURCE=..\libusb\os\windows_usb.h -# End Source File -# End Group -# End Target -# End Project diff --git a/third_party/libusb/msvc/lsusb_sources b/third_party/libusb/msvc/lsusb_sources deleted file mode 100644 index dbfefbb..0000000 --- a/third_party/libusb/msvc/lsusb_sources +++ /dev/null @@ -1,19 +0,0 @@ -TARGETNAME=lsusb -TARGETTYPE=PROGRAM -386_STDCALL=0 - -_NT_TARGET_VERSION= $(_NT_TARGET_VERSION_WINXP) -!IFNDEF MSC_WARNING_LEVEL -MSC_WARNING_LEVEL=/W3 -!ENDIF - -!IFDEF STATIC_LIBC -USE_LIBCMT=1 -!ELSE -USE_MSVCRT=1 -!ENDIF - -UMTYPE=console -INCLUDES=..\..\libusb;$(DDK_INC_PATH) -UMLIBS=..\..\libusb\os\obj$(BUILD_ALT_DIR)\*\libusb-1.0.lib -SOURCES=..\lsusb.c diff --git a/third_party/libusb/msvc/stdint.h b/third_party/libusb/msvc/stdint.h deleted file mode 100644 index 00988d9..0000000 --- a/third_party/libusb/msvc/stdint.h +++ /dev/null @@ -1,256 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file was originally part of the w64 mingw-runtime package. - */ - -/* ISO C9x 7.18 Integer types <stdint.h> - * Based on ISO/IEC SC22/WG14 9899 Committee draft (SC22 N2794) - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * Contributor: Danny Smith <danny_r_smith_2001@yahoo.co.nz> - * Modified for libusb/MSVC: Pete Batard <pbatard@gmail.com> - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Date: 2010-04-02 - */ - -#ifndef _MSC_VER -#error This header should only be used with Microsoft compilers -#endif - -#ifndef _STDINT_H -#define _STDINT_H - -#ifndef _INTPTR_T_DEFINED -#define _INTPTR_T_DEFINED -#ifndef __intptr_t_defined -#define __intptr_t_defined -#undef intptr_t -#ifdef _WIN64 - typedef __int64 intptr_t; -#else - typedef int intptr_t; -#endif /* _WIN64 */ -#endif /* __intptr_t_defined */ -#endif /* _INTPTR_T_DEFINED */ - -#ifndef _UINTPTR_T_DEFINED -#define _UINTPTR_T_DEFINED -#ifndef __uintptr_t_defined -#define __uintptr_t_defined -#undef uintptr_t -#ifdef _WIN64 - typedef unsigned __int64 uintptr_t; -#else - typedef unsigned int uintptr_t; -#endif /* _WIN64 */ -#endif /* __uintptr_t_defined */ -#endif /* _UINTPTR_T_DEFINED */ - -#ifndef _PTRDIFF_T_DEFINED -#define _PTRDIFF_T_DEFINED -#ifndef _PTRDIFF_T_ -#define _PTRDIFF_T_ -#undef ptrdiff_t -#ifdef _WIN64 - typedef __int64 ptrdiff_t; -#else - typedef int ptrdiff_t; -#endif /* _WIN64 */ -#endif /* _PTRDIFF_T_ */ -#endif /* _PTRDIFF_T_DEFINED */ - -#ifndef _WCHAR_T_DEFINED -#define _WCHAR_T_DEFINED -#ifndef __cplusplus - typedef unsigned short wchar_t; -#endif /* C++ */ -#endif /* _WCHAR_T_DEFINED */ - -#ifndef _WCTYPE_T_DEFINED -#define _WCTYPE_T_DEFINED -#ifndef _WINT_T -#define _WINT_T - typedef unsigned short wint_t; - typedef unsigned short wctype_t; -#endif /* _WINT_T */ -#endif /* _WCTYPE_T_DEFINED */ - -/* 7.18.1.1 Exact-width integer types */ -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; - -/* 7.18.1.2 Minimum-width integer types */ -typedef signed char int_least8_t; -typedef unsigned char uint_least8_t; -typedef short int_least16_t; -typedef unsigned short uint_least16_t; -typedef int int_least32_t; -typedef unsigned uint_least32_t; -typedef __int64 int_least64_t; -typedef unsigned __int64 uint_least64_t; - -/* 7.18.1.3 Fastest minimum-width integer types - * Not actually guaranteed to be fastest for all purposes - * Here we use the exact-width types for 8 and 16-bit ints. - */ -typedef __int8 int_fast8_t; -typedef unsigned __int8 uint_fast8_t; -typedef __int16 int_fast16_t; -typedef unsigned __int16 uint_fast16_t; -typedef __int32 int_fast32_t; -typedef unsigned __int32 uint_fast32_t; -typedef __int64 int_fast64_t; -typedef unsigned __int64 uint_fast64_t; - -/* 7.18.1.5 Greatest-width integer types */ -typedef __int64 intmax_t; -typedef unsigned __int64 uintmax_t; - -/* 7.18.2 Limits of specified-width integer types */ - -/* 7.18.2.1 Limits of exact-width integer types */ -#define INT8_MIN (-128) -#define INT16_MIN (-32768) -#define INT32_MIN (-2147483647 - 1) -#define INT64_MIN (-9223372036854775807LL - 1) - -#define INT8_MAX 127 -#define INT16_MAX 32767 -#define INT32_MAX 2147483647 -#define INT64_MAX 9223372036854775807LL - -#define UINT8_MAX 255 -#define UINT16_MAX 65535 -#define UINT32_MAX 0xffffffffU /* 4294967295U */ -#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ - -/* 7.18.2.2 Limits of minimum-width integer types */ -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST64_MIN INT64_MIN - -#define INT_LEAST8_MAX INT8_MAX -#define INT_LEAST16_MAX INT16_MAX -#define INT_LEAST32_MAX INT32_MAX -#define INT_LEAST64_MAX INT64_MAX - -#define UINT_LEAST8_MAX UINT8_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define UINT_LEAST64_MAX UINT64_MAX - -/* 7.18.2.3 Limits of fastest minimum-width integer types */ -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST64_MIN INT64_MIN - -#define INT_FAST8_MAX INT8_MAX -#define INT_FAST16_MAX INT16_MAX -#define INT_FAST32_MAX INT32_MAX -#define INT_FAST64_MAX INT64_MAX - -#define UINT_FAST8_MAX UINT8_MAX -#define UINT_FAST16_MAX UINT16_MAX -#define UINT_FAST32_MAX UINT32_MAX -#define UINT_FAST64_MAX UINT64_MAX - -/* 7.18.2.4 Limits of integer types capable of holding - object pointers */ -#ifdef _WIN64 -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX -#else -#define INTPTR_MIN INT32_MIN -#define INTPTR_MAX INT32_MAX -#define UINTPTR_MAX UINT32_MAX -#endif - -/* 7.18.2.5 Limits of greatest-width integer types */ -#define INTMAX_MIN INT64_MIN -#define INTMAX_MAX INT64_MAX -#define UINTMAX_MAX UINT64_MAX - -/* 7.18.3 Limits of other integer types */ -#ifdef _WIN64 -#define PTRDIFF_MIN INT64_MIN -#define PTRDIFF_MAX INT64_MAX -#else -#define PTRDIFF_MIN INT32_MIN -#define PTRDIFF_MAX INT32_MAX -#endif - -#define SIG_ATOMIC_MIN INT32_MIN -#define SIG_ATOMIC_MAX INT32_MAX - -#ifndef SIZE_MAX -#ifdef _WIN64 -#define SIZE_MAX UINT64_MAX -#else -#define SIZE_MAX UINT32_MAX -#endif -#endif - -#ifndef WCHAR_MIN /* also in wchar.h */ -#define WCHAR_MIN 0U -#define WCHAR_MAX 0xffffU -#endif - -/* - * wint_t is unsigned short for compatibility with MS runtime - */ -#define WINT_MIN 0U -#define WINT_MAX 0xffffU - - -/* 7.18.4 Macros for integer constants */ - -/* 7.18.4.1 Macros for minimum-width integer constants - - Accoding to Douglas Gwyn <gwyn@arl.mil>: - "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC - 9899:1999 as initially published, the expansion was required - to be an integer constant of precisely matching type, which - is impossible to accomplish for the shorter types on most - platforms, because C99 provides no standard way to designate - an integer constant with width less than that of type int. - TC1 changed this to require just an integer constant - *expression* with *promoted* type." - - The trick used here is from Clive D W Feather. -*/ - -#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) -#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) -#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) -/* The 'trick' doesn't work in C89 for long long because, without - suffix, (val) will be evaluated as int, not intmax_t */ -#define INT64_C(val) val##i64 - -#define UINT8_C(val) (val) -#define UINT16_C(val) (val) -#define UINT32_C(val) (val##i32) -#define UINT64_C(val) val##ui64 - -/* 7.18.4.2 Macros for greatest-width integer constants */ -#define INTMAX_C(val) val##i64 -#define UINTMAX_C(val) val##ui64 - -#endif |