aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/karalabe/hid/libusb
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2018-09-27 20:03:23 +0200
committerDimitri Sokolyuk <demon@dim13.org>2018-09-27 20:03:23 +0200
commit14bb08c1df8db9ec6c8a05520d4eee67971235d9 (patch)
treefc820e59c26ed4c5e87e65737909b47959f0faa5 /vendor/github.com/karalabe/hid/libusb
parent54eb169e8fc9bc0357139e7c259e977b184f8fbb (diff)
mod tidy
Diffstat (limited to 'vendor/github.com/karalabe/hid/libusb')
-rw-r--r--vendor/github.com/karalabe/hid/libusb/AUTHORS89
-rw-r--r--vendor/github.com/karalabe/hid/libusb/COPYING504
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/config.h3
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/core.c2523
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c1191
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c350
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h90
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/io.c2819
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/libusb.h2008
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h1149
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c2094
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h164
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp367
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h112
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp517
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp250
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h180
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c400
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c311
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c2738
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h193
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c677
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c771
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c53
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h11
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c728
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h131
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c1292
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h74
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c79
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h55
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c259
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h76
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c899
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h126
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h124
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c591
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h63
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c905
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h146
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c4290
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h937
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/strerror.c202
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/sync.c327
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/version.h18
-rw-r--r--vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h1
46 files changed, 0 insertions, 30887 deletions
diff --git a/vendor/github.com/karalabe/hid/libusb/AUTHORS b/vendor/github.com/karalabe/hid/libusb/AUTHORS
deleted file mode 100644
index 70d407b..0000000
--- a/vendor/github.com/karalabe/hid/libusb/AUTHORS
+++ /dev/null
@@ -1,89 +0,0 @@
-Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
-Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
-Copyright © 2010-2012 Peter Stuge <peter@stuge.se>
-Copyright © 2008-2016 Nathan Hjelm <hjelmn@users.sourceforge.net>
-Copyright © 2009-2013 Pete Batard <pete@akeo.ie>
-Copyright © 2009-2013 Ludovic Rousseau <ludovic.rousseau@gmail.com>
-Copyright © 2010-2012 Michael Plante <michael.plante@gmail.com>
-Copyright © 2011-2013 Hans de Goede <hdegoede@redhat.com>
-Copyright © 2012-2013 Martin Pieuchot <mpi@openbsd.org>
-Copyright © 2012-2013 Toby Gray <toby.gray@realvnc.com>
-Copyright © 2013-2015 Chris Dickens <christopher.a.dickens@gmail.com>
-
-Other contributors:
-Akshay Jaggi
-Alan Ott
-Alan Stern
-Alex Vatchenko
-Andrew Fernandes
-Anthony Clay
-Antonio Ospite
-Artem Egorkine
-Aurelien Jarno
-Bastien Nocera
-Bei Zhang
-Benjamin Dobell
-Carl Karsten
-Colin Walters
-Dave Camarillo
-David Engraf
-David Moore
-Davidlohr Bueso
-Federico Manzan
-Felipe Balbi
-Florian Albrechtskirchinger
-Francesco Montorsi
-Francisco Facioni
-Gaurav Gupta
-Graeme Gill
-Gustavo Zacarias
-Hans Ulrich Niedermann
-Hector Martin
-Hoi-Ho Chan
-Ilya Konstantinov
-James Hanko
-John Sheu
-Joshua Blake
-Justin Bischoff
-Karsten Koenig
-Konrad Rzepecki
-Kuangye Guo
-Lars Kanis
-Lars Wirzenius
-Luca Longinotti
-Marcus Meissner
-Markus Heidelberg
-Martin Ettl
-Martin Koegler
-Matthias Bolte
-Mike Frysinger
-Mikhail Gusarov
-Moritz Fischer
-Ларионов Даниил
-Nicholas Corgan
-Omri Iluz
-Orin Eman
-Paul Fertser
-Pekka Nikander
-Rob Walker
-Sean McBride
-Sebastian Pipping
-Simon Haggett
-Simon Newton
-Thomas Röfer
-Tim Hutt
-Tim Roberts
-Tobias Klauser
-Toby Peterson
-Tormod Volden
-Trygve Laugstøl
-Uri Lublin
-Vasily Khoruzhick
-Vegard Storheil Eriksen
-Venkatesh Shukla
-Vitali Lovich
-Xiaofan Chen
-Zoltán Kovács
-Роман Донченко
-parafin
-xantares
diff --git a/vendor/github.com/karalabe/hid/libusb/COPYING b/vendor/github.com/karalabe/hid/libusb/COPYING
deleted file mode 100644
index 5ab7695..0000000
--- a/vendor/github.com/karalabe/hid/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/vendor/github.com/karalabe/hid/libusb/libusb/config.h b/vendor/github.com/karalabe/hid/libusb/libusb/config.h
deleted file mode 100644
index e004f03..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/config.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifndef CONFIG_H
-#define CONFIG_H
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/core.c b/vendor/github.com/karalabe/hid/libusb/libusb/core.c
deleted file mode 100644
index d45bfe1..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/core.c
+++ /dev/null
@@ -1,2523 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
-/*
- * Core functions for libusb
- * Copyright © 2012-2013 Nathan Hjelm <hjelmn@cs.unm.edu>
- * Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
- * Copyright © 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>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYSLOG_H
-#include <syslog.h>
-#endif
-
-#ifdef __ANDROID__
-#include <android/log.h>
-#endif
-
-#include "libusbi.h"
-#include "hotplug.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_OPENBSD)
-const struct usbi_os_backend * const usbi_backend = &openbsd_backend;
-#elif defined(OS_NETBSD)
-const struct usbi_os_backend * const usbi_backend = &netbsd_backend;
-#elif defined(OS_WINDOWS)
-
-#if defined(USE_USBDK)
-const struct usbi_os_backend * const usbi_backend = &usbdk_backend;
-#else
-const struct usbi_os_backend * const usbi_backend = &windows_backend;
-#endif
-
-#elif defined(OS_WINCE)
-const struct usbi_os_backend * const usbi_backend = &wince_backend;
-#elif defined(OS_HAIKU)
-const struct usbi_os_backend * const usbi_backend = &haiku_usb_raw_backend;
-#elif defined (OS_SUNOS)
-const struct usbi_os_backend * const usbi_backend = &sunos_backend;
-#else
-#error "Unsupported OS"
-#endif
-
-struct libusb_context *usbi_default_context = NULL;
-static const struct libusb_version libusb_version_internal =
- { LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO,
- LIBUSB_RC, "http://libusb.info" };
-static int default_context_refcnt = 0;
-static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
-static struct timespec timestamp_origin = { 0, 0 };
-
-usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER;
-struct list_head active_contexts_list;
-
-/**
- * \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.info">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://mailing-list.libusb.info">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 3.0
- * Specification</a> which is available for free download. You can probably
- * find less verbose introductions by searching the web.
- *
- * \section API Application Programming Interface (API)
- *
- * See the \ref libusb_api page for a complete list of the libusb functions.
- *
- * \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
- * - Hotplug support (on some platforms). See \ref libusb_hotplug.
- *
- * \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 libusb_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 libusb_misc "miscellaneous" documentation page.
- *
- * \section msglog Debug message logging
- *
- * libusb uses stderr for all logging. By default, logging is set to NONE,
- * which means that no output will be produced. However, unless the library
- * has been compiled with logging disabled, then any application calls to
- * libusb_set_debug(), or the setting of the environmental variable
- * LIBUSB_DEBUG outside of the application, can result in logging being
- * produced. Your application should therefore not close stderr, but instead
- * direct it to the null device if its output is undesirable.
- *
- * The libusb_set_debug() function can be used to enable logging of certain
- * messages. Under standard configuration, libusb doesn't really log much
- * so you are advised to use this function to enable all error/warning/
- * informational messages. It will help 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 intended to 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 log level 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 always. 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 libusb_caveats "caveats" page attempts
- * to document these.
- */
-
-/**
- * \page libusb_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 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.
- * -# 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.)
- * -# libusb will be unable to set a configuration if other programs or
- * drivers have claimed interfaces. In particular, this means that kernel
- * drivers must be detached from all the interfaces before
- * libusb_set_configuration() may succeed.
- *
- * 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 = -1;
-libusb_get_configuration(dev, &cfg);
-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. For recent
- * versions of libusb, 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.
- *
- *
- * \section zlp Zero length packets
- *
- * - libusb is able to send a packet of zero length to an endpoint simply by
- * submitting a transfer of zero length.
- * - The \ref libusb_transfer_flags::LIBUSB_TRANSFER_ADD_ZERO_PACKET
- * "LIBUSB_TRANSFER_ADD_ZERO_PACKET" flag is currently only supported on Linux.
- */
-
-/**
- * \page libusb_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.
- */
-
- /**
- * \page libusb_api Application Programming Interface
- *
- * This is the complete list of libusb functions, structures and
- * enumerations in alphabetical order.
- *
- * \section Functions
- * - libusb_alloc_streams()
- * - libusb_alloc_transfer()
- * - libusb_attach_kernel_driver()
- * - libusb_bulk_transfer()
- * - libusb_cancel_transfer()
- * - libusb_claim_interface()
- * - libusb_clear_halt()
- * - libusb_close()
- * - libusb_control_transfer()
- * - libusb_control_transfer_get_data()
- * - libusb_control_transfer_get_setup()
- * - libusb_cpu_to_le16()
- * - libusb_detach_kernel_driver()
- * - libusb_dev_mem_alloc()
- * - libusb_dev_mem_free()
- * - libusb_error_name()
- * - libusb_event_handler_active()
- * - libusb_event_handling_ok()
- * - libusb_exit()
- * - libusb_fill_bulk_stream_transfer()
- * - libusb_fill_bulk_transfer()
- * - libusb_fill_control_setup()
- * - libusb_fill_control_transfer()
- * - libusb_fill_interrupt_transfer()
- * - libusb_fill_iso_transfer()
- * - libusb_free_bos_descriptor()
- * - libusb_free_config_descriptor()
- * - libusb_free_container_id_descriptor()
- * - libusb_free_device_list()
- * - libusb_free_pollfds()
- * - libusb_free_ss_endpoint_companion_descriptor()
- * - libusb_free_ss_usb_device_capability_descriptor()
- * - libusb_free_streams()
- * - libusb_free_transfer()
- * - libusb_free_usb_2_0_extension_descriptor()
- * - libusb_get_active_config_descriptor()
- * - libusb_get_bos_descriptor()
- * - libusb_get_bus_number()
- * - libusb_get_config_descriptor()
- * - libusb_get_config_descriptor_by_value()
- * - libusb_get_configuration()
- * - libusb_get_container_id_descriptor()
- * - libusb_get_descriptor()
- * - libusb_get_device()
- * - libusb_get_device_address()
- * - libusb_get_device_descriptor()
- * - libusb_get_device_list()
- * - libusb_get_device_speed()
- * - libusb_get_iso_packet_buffer()
- * - libusb_get_iso_packet_buffer_simple()
- * - libusb_get_max_iso_packet_size()
- * - libusb_get_max_packet_size()
- * - libusb_get_next_timeout()
- * - libusb_get_parent()
- * - libusb_get_pollfds()
- * - libusb_get_port_number()
- * - libusb_get_port_numbers()
- * - libusb_get_port_path()
- * - libusb_get_ss_endpoint_companion_descriptor()
- * - libusb_get_ss_usb_device_capability_descriptor()
- * - libusb_get_string_descriptor()
- * - libusb_get_string_descriptor_ascii()
- * - libusb_get_usb_2_0_extension_descriptor()
- * - libusb_get_version()
- * - libusb_handle_events()
- * - libusb_handle_events_completed()
- * - libusb_handle_events_locked()
- * - libusb_handle_events_timeout()
- * - libusb_handle_events_timeout_completed()
- * - libusb_has_capability()
- * - libusb_hotplug_deregister_callback()
- * - libusb_hotplug_register_callback()
- * - libusb_init()
- * - libusb_interrupt_event_handler()
- * - libusb_interrupt_transfer()
- * - libusb_kernel_driver_active()
- * - libusb_lock_events()
- * - libusb_lock_event_waiters()
- * - libusb_open()
- * - libusb_open_device_with_vid_pid()
- * - libusb_pollfds_handle_timeouts()
- * - libusb_ref_device()
- * - libusb_release_interface()
- * - libusb_reset_device()
- * - libusb_set_auto_detach_kernel_driver()
- * - libusb_set_configuration()
- * - libusb_set_debug()
- * - libusb_set_interface_alt_setting()
- * - libusb_set_iso_packet_lengths()
- * - libusb_setlocale()
- * - libusb_set_pollfd_notifiers()
- * - libusb_strerror()
- * - libusb_submit_transfer()
- * - libusb_transfer_get_stream_id()
- * - libusb_transfer_set_stream_id()
- * - libusb_try_lock_events()
- * - libusb_unlock_events()
- * - libusb_unlock_event_waiters()
- * - libusb_unref_device()
- * - libusb_wait_for_event()
- *
- * \section Structures
- * - libusb_bos_descriptor
- * - libusb_bos_dev_capability_descriptor
- * - libusb_config_descriptor
- * - libusb_container_id_descriptor
- * - \ref libusb_context
- * - libusb_control_setup
- * - \ref libusb_device
- * - libusb_device_descriptor
- * - \ref libusb_device_handle
- * - libusb_endpoint_descriptor
- * - libusb_interface
- * - libusb_interface_descriptor
- * - libusb_iso_packet_descriptor
- * - libusb_pollfd
- * - libusb_ss_endpoint_companion_descriptor
- * - libusb_ss_usb_device_capability_descriptor
- * - libusb_transfer
- * - libusb_usb_2_0_extension_descriptor
- * - libusb_version
- *
- * \section Enums
- * - \ref libusb_bos_type
- * - \ref libusb_capability
- * - \ref libusb_class_code
- * - \ref libusb_descriptor_type
- * - \ref libusb_endpoint_direction
- * - \ref libusb_error
- * - \ref libusb_iso_sync_type
- * - \ref libusb_iso_usage_type
- * - \ref libusb_log_level
- * - \ref libusb_request_recipient
- * - \ref libusb_request_type
- * - \ref libusb_speed
- * - \ref libusb_ss_usb_device_capability_attributes
- * - \ref libusb_standard_request
- * - \ref libusb_supported_speed
- * - \ref libusb_transfer_flags
- * - \ref libusb_transfer_status
- * - \ref libusb_transfer_type
- * - \ref libusb_usb_2_0_extension_attributes
- */
-
-/**
- * @defgroup libusb_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 libusb_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 libusb_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;
-}
-
-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);
-}
-
-/* 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;
- struct discovered_devs *new_discdevs;
-
- /* 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;
- /* can't use usbi_reallocf here because in failure cases it would
- * free the existing discdevs without unreferencing its devices. */
- new_discdevs = realloc(discdevs,
- sizeof(*discdevs) + (sizeof(void *) * capacity));
- if (!new_discdevs) {
- discovered_devs_free(discdevs);
- return NULL;
- }
-
- discdevs = new_discdevs;
- discdevs->capacity = capacity;
- discdevs->devices[len] = libusb_ref_device(dev);
- discdevs->len++;
-
- return 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);
- if (r) {
- free(dev);
- return NULL;
- }
-
- dev->ctx = ctx;
- dev->refcnt = 1;
- dev->session_data = session_id;
- dev->speed = LIBUSB_SPEED_UNKNOWN;
-
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- usbi_connect_device (dev);
- }
-
- return dev;
-}
-
-void usbi_connect_device(struct libusb_device *dev)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
-
- dev->attached = 1;
-
- usbi_mutex_lock(&dev->ctx->usb_devs_lock);
- list_add(&dev->list, &dev->ctx->usb_devs);
- usbi_mutex_unlock(&dev->ctx->usb_devs_lock);
-
- /* Signal that an event has occurred for this device if we support hotplug AND
- * the hotplug message list is ready. This prevents an event from getting raised
- * during initial enumeration. */
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_msgs.next) {
- usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
- }
-}
-
-void usbi_disconnect_device(struct libusb_device *dev)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
-
- usbi_mutex_lock(&dev->lock);
- dev->attached = 0;
- usbi_mutex_unlock(&dev->lock);
-
- usbi_mutex_lock(&ctx->usb_devs_lock);
- list_del(&dev->list);
- usbi_mutex_unlock(&ctx->usb_devs_lock);
-
- /* Signal that an event has occurred for this device if we support hotplug AND
- * the hotplug message list is ready. This prevents an event from getting raised
- * during initial enumeration. libusb_handle_events will take care of dereferencing
- * the device. */
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_msgs.next) {
- usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
- }
-}
-
-/* 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;
- uint8_t num_configurations;
-
- r = usbi_device_cache_descriptor(dev);
- if (r < 0)
- return r;
-
- num_configurations = dev->device_descriptor.bNumConfigurations;
- 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 = libusb_ref_device(dev);
- break;
- }
- usbi_mutex_unlock(&ctx->usb_devs_lock);
-
- return ret;
-}
-
-/** @ingroup libusb_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;
-
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- /* backend provides hotplug support */
- struct libusb_device *dev;
-
- if (usbi_backend->hotplug_poll)
- usbi_backend->hotplug_poll();
-
- usbi_mutex_lock(&ctx->usb_devs_lock);
- list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
- discdevs = discovered_devs_append(discdevs, dev);
-
- if (!discdevs) {
- r = LIBUSB_ERROR_NO_MEM;
- break;
- }
- }
- usbi_mutex_unlock(&ctx->usb_devs_lock);
- } else {
- /* backend does not provide hotplug support */
- 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 = calloc(len + 1, sizeof(struct libusb_device *));
- 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:
- if (discdevs)
- discovered_devs_free(discdevs);
- return len;
-}
-
-/** \ingroup libusb_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 libusb_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 libusb_dev
- * Get the number of the port that a device is connected to.
- * Unless the OS does something funky, or you are hot-plugging USB extension cards,
- * the port number returned by this call is usually guaranteed to be uniquely tied
- * to a physical port, meaning that different devices plugged on the same physical
- * port should return the same port number.
- *
- * But outside of this, there is no guarantee that the port number returned by this
- * call will remain the same, or even match the order in which ports have been
- * numbered by the HUB/HCD manufacturer.
- *
- * \param dev a device
- * \returns the port number (0 if not available)
- */
-uint8_t API_EXPORTED libusb_get_port_number(libusb_device *dev)
-{
- return dev->port_number;
-}
-
-/** \ingroup libusb_dev
- * Get the list of all port numbers from root for the specified device
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- * \param dev a device
- * \param port_numbers the array that should contain the port numbers
- * \param port_numbers_len the maximum length of the array. As per the USB 3.0
- * specs, the current maximum limit for the depth is 7.
- * \returns the number of elements filled
- * \returns LIBUSB_ERROR_OVERFLOW if the array is too small
- */
-int API_EXPORTED libusb_get_port_numbers(libusb_device *dev,
- uint8_t* port_numbers, int port_numbers_len)
-{
- int i = port_numbers_len;
- struct libusb_context *ctx = DEVICE_CTX(dev);
-
- if (port_numbers_len <= 0)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- // HCDs can be listed as devices with port #0
- while((dev) && (dev->port_number != 0)) {
- if (--i < 0) {
- usbi_warn(ctx, "port numbers array is too small");
- return LIBUSB_ERROR_OVERFLOW;
- }
- port_numbers[i] = dev->port_number;
- dev = dev->parent_dev;
- }
- if (i < port_numbers_len)
- memmove(port_numbers, &port_numbers[i], port_numbers_len - i);
- return port_numbers_len - i;
-}
-
-/** \ingroup libusb_dev
- * Deprecated please use libusb_get_port_numbers instead.
- */
-int API_EXPORTED libusb_get_port_path(libusb_context *ctx, libusb_device *dev,
- uint8_t* port_numbers, uint8_t port_numbers_len)
-{
- UNUSED(ctx);
-
- return libusb_get_port_numbers(dev, port_numbers, port_numbers_len);
-}
-
-/** \ingroup libusb_dev
- * Get the the parent from the specified device.
- * \param dev a device
- * \returns the device parent or NULL if not available
- * You should issue a \ref libusb_get_device_list() before calling this
- * function and make sure that you only access the parent before issuing
- * \ref libusb_free_device_list(). The reason is that libusb currently does
- * not maintain a permanent list of device instances, and therefore can
- * only guarantee that parents are fully instantiated within a
- * libusb_get_device_list() - libusb_free_device_list() block.
- */
-DEFAULT_VISIBILITY
-libusb_device * LIBUSB_CALL libusb_get_parent(libusb_device *dev)
-{
- return dev->parent_dev;
-}
-
-/** \ingroup libusb_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 libusb_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 libusb_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) {
- r = LIBUSB_ERROR_NOT_FOUND;
- goto out;
- }
-
- r = ep->wMaxPacketSize;
-
-out:
- libusb_free_config_descriptor(config);
- return r;
-}
-
-/** \ingroup libusb_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 configuration 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) {
- r = LIBUSB_ERROR_NOT_FOUND;
- goto out;
- }
-
- val = ep->wMaxPacketSize;
- ep_type = (enum libusb_transfer_type) (ep->bmAttributes & 0x3);
-
- r = val & 0x07ff;
- if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
- || ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT)
- r *= (1 + ((val >> 11) & 3));
-
-out:
- libusb_free_config_descriptor(config);
- return r;
-}
-
-/** \ingroup libusb_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 libusb_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);
-
- libusb_unref_device(dev->parent_dev);
-
- if (usbi_backend->destroy_device)
- usbi_backend->destroy_device(dev);
-
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- /* backend does not support hotplug */
- usbi_disconnect_device(dev);
- }
-
- usbi_mutex_destroy(&dev->lock);
- free(dev);
- }
-}
-
-/*
- * Signal the event pipe so that the event handling thread will be
- * interrupted to process an internal event.
- */
-int usbi_signal_event(struct libusb_context *ctx)
-{
- unsigned char dummy = 1;
- ssize_t r;
-
- /* write some data on event pipe to interrupt event handlers */
- r = usbi_write(ctx->event_pipe[1], &dummy, sizeof(dummy));
- if (r != sizeof(dummy)) {
- usbi_warn(ctx, "internal signalling write failed");
- return LIBUSB_ERROR_IO;
- }
-
- return 0;
-}
-
-/*
- * Clear the event pipe so that the event handling will no longer be
- * interrupted.
- */
-int usbi_clear_event(struct libusb_context *ctx)
-{
- unsigned char dummy;
- ssize_t r;
-
- /* read some data on event pipe to clear it */
- r = usbi_read(ctx->event_pipe[0], &dummy, sizeof(dummy));
- if (r != sizeof(dummy)) {
- usbi_warn(ctx, "internal signalling read failed");
- return LIBUSB_ERROR_IO;
- }
-
- return 0;
-}
-
-/** \ingroup libusb_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 dev_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 **dev_handle)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct libusb_device_handle *_dev_handle;
- size_t priv_size = usbi_backend->device_handle_priv_size;
- int r;
- usbi_dbg("open %d.%d", dev->bus_number, dev->device_address);
-
- if (!dev->attached) {
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- _dev_handle = malloc(sizeof(*_dev_handle) + priv_size);
- if (!_dev_handle)
- return LIBUSB_ERROR_NO_MEM;
-
- r = usbi_mutex_init(&_dev_handle->lock);
- if (r) {
- free(_dev_handle);
- return LIBUSB_ERROR_OTHER;
- }
-
- _dev_handle->dev = libusb_ref_device(dev);
- _dev_handle->auto_detach_kernel_driver = 0;
- _dev_handle->claimed_interfaces = 0;
- memset(&_dev_handle->os_priv, 0, priv_size);
-
- r = usbi_backend->open(_dev_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(&_dev_handle->lock);
- free(_dev_handle);
- return r;
- }
-
- usbi_mutex_lock(&ctx->open_devs_lock);
- list_add(&_dev_handle->list, &ctx->open_devs);
- usbi_mutex_unlock(&ctx->open_devs_lock);
- *dev_handle = _dev_handle;
-
- return 0;
-}
-
-/** \ingroup libusb_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 device 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 *dev_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, &dev_handle);
- if (r < 0)
- dev_handle = NULL;
- }
-
-out:
- libusb_free_device_list(devs, 1);
- return dev_handle;
-}
-
-static void do_close(struct libusb_context *ctx,
- struct libusb_device_handle *dev_handle)
-{
- struct usbi_transfer *itransfer;
- struct usbi_transfer *tmp;
-
- /* 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;
-
- usbi_mutex_lock(&itransfer->lock);
- if (!(itransfer->state_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->state_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");
- }
- usbi_mutex_unlock(&itransfer->lock);
-
- /* 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)
- */
- list_del(&itransfer->list);
- transfer->dev_handle = NULL;
-
- /* 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);
-
- 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 libusb_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 device handle to close
- */
-void API_EXPORTED libusb_close(libusb_device_handle *dev_handle)
-{
- struct libusb_context *ctx;
- int handling_events;
- int pending_events;
-
- if (!dev_handle)
- return;
- usbi_dbg("");
-
- ctx = HANDLE_CTX(dev_handle);
- handling_events = usbi_handling_events(ctx);
-
- /* 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. If this is being called by the current
- * event handler, we can bypass the interruption code because we already
- * hold the event handling lock. */
-
- if (!handling_events) {
- /* Record that we are closing a device.
- * Only signal an event if there are no prior pending events. */
- usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
- ctx->device_close++;
- if (!pending_events)
- usbi_signal_event(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
-
- /* take event handling lock */
- libusb_lock_events(ctx);
- }
-
- /* Close the device */
- do_close(ctx, dev_handle);
-
- if (!handling_events) {
- /* We're done with closing this device.
- * Clear the event pipe if there are no further pending events. */
- usbi_mutex_lock(&ctx->event_data_lock);
- ctx->device_close--;
- pending_events = usbi_pending_events(ctx);
- if (!pending_events)
- usbi_clear_event(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
-
- /* Release event handling lock and wake up event waiters */
- libusb_unlock_events(ctx);
- }
-}
-
-/** \ingroup libusb_dev
- * Get the underlying device for a device 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 libusb_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_handle 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_handle,
- int *config)
-{
- int r = LIBUSB_ERROR_NOT_SUPPORTED;
-
- usbi_dbg("");
- if (usbi_backend->get_configuration)
- r = usbi_backend->get_configuration(dev_handle, config);
-
- if (r == LIBUSB_ERROR_NOT_SUPPORTED) {
- uint8_t tmp = 0;
- usbi_dbg("falling back to control message");
- r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN,
- LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000);
- if (r == 0) {
- usbi_err(HANDLE_CTX(dev_handle), "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 libusb_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. It is advised to set the desired configuration before claiming
- * interfaces.
- *
- * Alternatively you can call libusb_release_interface() first. Note if you
- * do things this way you must ensure that auto_detach_kernel_driver for
- * <tt>dev</tt> is 0, otherwise the kernel driver will be re-attached when you
- * release the interface(s).
- *
- * 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_handle a device handle
- * \param configuration the bConfigurationValue of the configuration you
- * wish to activate, or -1 if you wish to put the device in an 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
- * \see libusb_set_auto_detach_kernel_driver()
- */
-int API_EXPORTED libusb_set_configuration(libusb_device_handle *dev_handle,
- int configuration)
-{
- usbi_dbg("configuration %d", configuration);
- return usbi_backend->set_configuration(dev_handle, configuration);
-}
-
-/** \ingroup libusb_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.
- *
- * If auto_detach_kernel_driver is set to 1 for <tt>dev</tt>, the kernel driver
- * will be detached if necessary, on failure the detach error is returned.
- *
- * 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_handle 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
- * \see libusb_set_auto_detach_kernel_driver()
- */
-int API_EXPORTED libusb_claim_interface(libusb_device_handle *dev_handle,
- int interface_number)
-{
- int r = 0;
-
- usbi_dbg("interface %d", interface_number);
- if (interface_number >= USB_MAXINTERFACES)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- usbi_mutex_lock(&dev_handle->lock);
- if (dev_handle->claimed_interfaces & (1 << interface_number))
- goto out;
-
- r = usbi_backend->claim_interface(dev_handle, interface_number);
- if (r == 0)
- dev_handle->claimed_interfaces |= 1 << interface_number;
-
-out:
- usbi_mutex_unlock(&dev_handle->lock);
- return r;
-}
-
-/** \ingroup libusb_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.
- *
- * If auto_detach_kernel_driver is set to 1 for <tt>dev</tt>, the kernel
- * driver will be re-attached after releasing the interface.
- *
- * \param dev_handle 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
- * \see libusb_set_auto_detach_kernel_driver()
- */
-int API_EXPORTED libusb_release_interface(libusb_device_handle *dev_handle,
- 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_handle->lock);
- if (!(dev_handle->claimed_interfaces & (1 << interface_number))) {
- r = LIBUSB_ERROR_NOT_FOUND;
- goto out;
- }
-
- r = usbi_backend->release_interface(dev_handle, interface_number);
- if (r == 0)
- dev_handle->claimed_interfaces &= ~(1 << interface_number);
-
-out:
- usbi_mutex_unlock(&dev_handle->lock);
- return r;
-}
-
-/** \ingroup libusb_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_handle 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_handle,
- 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_handle->lock);
- if (!dev_handle->dev->attached) {
- usbi_mutex_unlock(&dev_handle->lock);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- if (!(dev_handle->claimed_interfaces & (1 << interface_number))) {
- usbi_mutex_unlock(&dev_handle->lock);
- return LIBUSB_ERROR_NOT_FOUND;
- }
- usbi_mutex_unlock(&dev_handle->lock);
-
- return usbi_backend->set_interface_altsetting(dev_handle, interface_number,
- alternate_setting);
-}
-
-/** \ingroup libusb_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_handle 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_handle,
- unsigned char endpoint)
-{
- usbi_dbg("endpoint %x", endpoint);
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- return usbi_backend->clear_halt(dev_handle, endpoint);
-}
-
-/** \ingroup libusb_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_handle 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_handle)
-{
- usbi_dbg("");
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- return usbi_backend->reset_device(dev_handle);
-}
-
-/** \ingroup libusb_asyncio
- * Allocate up to num_streams usb bulk streams on the specified endpoints. This
- * function takes an array of endpoints rather then a single endpoint because
- * some protocols require that endpoints are setup with similar stream ids.
- * All endpoints passed in must belong to the same interface.
- *
- * Note this function may return less streams then requested. Also note that the
- * same number of streams are allocated for each endpoint in the endpoint array.
- *
- * Stream id 0 is reserved, and should not be used to communicate with devices.
- * If libusb_alloc_streams() returns with a value of N, you may use stream ids
- * 1 to N.
- *
- * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
- *
- * \param dev_handle a device handle
- * \param num_streams number of streams to try to allocate
- * \param endpoints array of endpoints to allocate streams on
- * \param num_endpoints length of the endpoints array
- * \returns number of streams allocated, or a LIBUSB_ERROR code on failure
- */
-int API_EXPORTED libusb_alloc_streams(libusb_device_handle *dev_handle,
- uint32_t num_streams, unsigned char *endpoints, int num_endpoints)
-{
- usbi_dbg("streams %u eps %d", (unsigned) num_streams, num_endpoints);
-
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- if (usbi_backend->alloc_streams)
- return usbi_backend->alloc_streams(dev_handle, num_streams, endpoints,
- num_endpoints);
- else
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-/** \ingroup libusb_asyncio
- * Free usb bulk streams allocated with libusb_alloc_streams().
- *
- * Note streams are automatically free-ed when releasing an interface.
- *
- * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
- *
- * \param dev_handle a device handle
- * \param endpoints array of endpoints to free streams on
- * \param num_endpoints length of the endpoints array
- * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure
- */
-int API_EXPORTED libusb_free_streams(libusb_device_handle *dev_handle,
- unsigned char *endpoints, int num_endpoints)
-{
- usbi_dbg("eps %d", num_endpoints);
-
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- if (usbi_backend->free_streams)
- return usbi_backend->free_streams(dev_handle, endpoints,
- num_endpoints);
- else
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-/** \ingroup libusb_asyncio
- * Attempts to allocate a block of persistent DMA memory suitable for transfers
- * against the given device. If successful, will return a block of memory
- * that is suitable for use as "buffer" in \ref libusb_transfer against this
- * device. Using this memory instead of regular memory means that the host
- * controller can use DMA directly into the buffer to increase performance, and
- * also that transfers can no longer fail due to kernel memory fragmentation.
- *
- * Note that this means you should not modify this memory (or even data on
- * the same cache lines) when a transfer is in progress, although it is legal
- * to have several transfers going on within the same memory block.
- *
- * Will return NULL on failure. Many systems do not support such zerocopy
- * and will always return NULL. Memory allocated with this function must be
- * freed with \ref libusb_dev_mem_free. Specifically, this means that the
- * flag \ref LIBUSB_TRANSFER_FREE_BUFFER cannot be used to free memory allocated
- * with this function.
- *
- * Since version 1.0.21, \ref LIBUSB_API_VERSION >= 0x01000105
- *
- * \param dev_handle a device handle
- * \param length size of desired data buffer
- * \returns a pointer to the newly allocated memory, or NULL on failure
- */
-DEFAULT_VISIBILITY
-unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handle,
- size_t length)
-{
- if (!dev_handle->dev->attached)
- return NULL;
-
- if (usbi_backend->dev_mem_alloc)
- return usbi_backend->dev_mem_alloc(dev_handle, length);
- else
- return NULL;
-}
-
-/** \ingroup libusb_asyncio
- * Free device memory allocated with libusb_dev_mem_alloc().
- *
- * \param dev_handle a device handle
- * \param buffer pointer to the previously allocated memory
- * \param length size of previously allocated memory
- * \returns LIBUSB_SUCCESS, or a LIBUSB_ERROR code on failure
- */
-int API_EXPORTED libusb_dev_mem_free(libusb_device_handle *dev_handle,
- unsigned char *buffer, size_t length)
-{
- if (usbi_backend->dev_mem_free)
- return usbi_backend->dev_mem_free(dev_handle, buffer, length);
- else
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-/** \ingroup libusb_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_handle 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_handle,
- int interface_number)
-{
- usbi_dbg("interface %d", interface_number);
-
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- if (usbi_backend->kernel_driver_active)
- return usbi_backend->kernel_driver_active(dev_handle, interface_number);
- else
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-/** \ingroup libusb_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.
- *
- * Note that libusb itself also talks to the device through a special kernel
- * driver, if this driver is already attached to the device, this call will
- * not detach it and return LIBUSB_ERROR_NOT_FOUND.
- *
- * \param dev_handle 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_handle,
- int interface_number)
-{
- usbi_dbg("interface %d", interface_number);
-
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- if (usbi_backend->detach_kernel_driver)
- return usbi_backend->detach_kernel_driver(dev_handle, interface_number);
- else
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-/** \ingroup libusb_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_handle 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_handle,
- int interface_number)
-{
- usbi_dbg("interface %d", interface_number);
-
- if (!dev_handle->dev->attached)
- return LIBUSB_ERROR_NO_DEVICE;
-
- if (usbi_backend->attach_kernel_driver)
- return usbi_backend->attach_kernel_driver(dev_handle, interface_number);
- else
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-/** \ingroup libusb_dev
- * Enable/disable libusb's automatic kernel driver detachment. When this is
- * enabled libusb will automatically detach the kernel driver on an interface
- * when claiming the interface, and attach it when releasing the interface.
- *
- * Automatic kernel driver detachment is disabled on newly opened device
- * handles by default.
- *
- * On platforms which do not have LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER
- * this function will return LIBUSB_ERROR_NOT_SUPPORTED, and libusb will
- * continue as if this function was never called.
- *
- * \param dev_handle a device handle
- * \param enable whether to enable or disable auto kernel driver detachment
- *
- * \returns LIBUSB_SUCCESS on success
- * \returns LIBUSB_ERROR_NOT_SUPPORTED on platforms where the functionality
- * is not available
- * \see libusb_claim_interface()
- * \see libusb_release_interface()
- * \see libusb_set_configuration()
- */
-int API_EXPORTED libusb_set_auto_detach_kernel_driver(
- libusb_device_handle *dev_handle, int enable)
-{
- if (!(usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
- return LIBUSB_ERROR_NOT_SUPPORTED;
-
- dev_handle->auto_detach_kernel_driver = enable;
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_lib
- * Set log message verbosity.
- *
- * The default level is LIBUSB_LOG_LEVEL_NONE, 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 use level LIBUSB_LOG_LEVEL_WARNING. 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 libusb_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 libusb_contexts
- */
-int API_EXPORTED libusb_init(libusb_context **context)
-{
- struct libusb_device *dev, *next;
- char *dbg = getenv("LIBUSB_DEBUG");
- struct libusb_context *ctx;
- static int first_init = 1;
- int r = 0;
-
- usbi_mutex_static_lock(&default_context_lock);
-
- if (!timestamp_origin.tv_sec) {
- usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timestamp_origin);
- }
-
- if (!context && usbi_default_context) {
- usbi_dbg("reusing default context");
- default_context_refcnt++;
- usbi_mutex_static_unlock(&default_context_lock);
- return 0;
- }
-
- ctx = calloc(1, sizeof(*ctx));
- if (!ctx) {
- r = LIBUSB_ERROR_NO_MEM;
- goto err_unlock;
- }
-
-#ifdef ENABLE_DEBUG_LOGGING
- ctx->debug = LIBUSB_LOG_LEVEL_DEBUG;
-#endif
-
- if (dbg) {
- ctx->debug = atoi(dbg);
- if (ctx->debug)
- ctx->debug_fixed = 1;
- }
-
- /* default context should be initialized before calling usbi_dbg */
- if (!usbi_default_context) {
- usbi_default_context = ctx;
- default_context_refcnt++;
- usbi_dbg("created default context");
- }
-
- usbi_dbg("libusb v%u.%u.%u.%u%s", libusb_version_internal.major, libusb_version_internal.minor,
- libusb_version_internal.micro, libusb_version_internal.nano, libusb_version_internal.rc);
-
- usbi_mutex_init(&ctx->usb_devs_lock);
- usbi_mutex_init(&ctx->open_devs_lock);
- usbi_mutex_init(&ctx->hotplug_cbs_lock);
- list_init(&ctx->usb_devs);
- list_init(&ctx->open_devs);
- list_init(&ctx->hotplug_cbs);
-
- usbi_mutex_static_lock(&active_contexts_lock);
- if (first_init) {
- first_init = 0;
- list_init (&active_contexts_list);
- }
- list_add (&ctx->list, &active_contexts_list);
- usbi_mutex_static_unlock(&active_contexts_lock);
-
- if (usbi_backend->init) {
- r = usbi_backend->init(ctx);
- if (r)
- goto err_free_ctx;
- }
-
- r = usbi_io_init(ctx);
- if (r < 0)
- goto err_backend_exit;
-
- usbi_mutex_static_unlock(&default_context_lock);
-
- if (context)
- *context = ctx;
-
- return 0;
-
-err_backend_exit:
- if (usbi_backend->exit)
- usbi_backend->exit();
-err_free_ctx:
- if (ctx == usbi_default_context) {
- usbi_default_context = NULL;
- default_context_refcnt--;
- }
-
- usbi_mutex_static_lock(&active_contexts_lock);
- list_del (&ctx->list);
- usbi_mutex_static_unlock(&active_contexts_lock);
-
- usbi_mutex_lock(&ctx->usb_devs_lock);
- list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
- list_del(&dev->list);
- libusb_unref_device(dev);
- }
- usbi_mutex_unlock(&ctx->usb_devs_lock);
-
- usbi_mutex_destroy(&ctx->open_devs_lock);
- usbi_mutex_destroy(&ctx->usb_devs_lock);
- usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
-
- free(ctx);
-err_unlock:
- usbi_mutex_static_unlock(&default_context_lock);
- return r;
-}
-
-/** \ingroup libusb_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)
-{
- struct libusb_device *dev, *next;
- struct timeval tv = { 0, 0 };
-
- usbi_dbg("");
- USBI_GET_CONTEXT(ctx);
-
- /* if working with default context, only actually do the deinitialization
- * if we're the last user */
- usbi_mutex_static_lock(&default_context_lock);
- if (ctx == usbi_default_context) {
- 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);
-
- usbi_mutex_static_lock(&active_contexts_lock);
- list_del (&ctx->list);
- usbi_mutex_static_unlock(&active_contexts_lock);
-
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- usbi_hotplug_deregister_all(ctx);
-
- /*
- * Ensure any pending unplug events are read from the hotplug
- * pipe. The usb_device-s hold in the events are no longer part
- * of usb_devs, but the events still hold a reference!
- *
- * Note we don't do this if the application has left devices
- * open (which implies a buggy app) to avoid packet completion
- * handlers running when the app does not expect them to run.
- */
- if (list_empty(&ctx->open_devs))
- libusb_handle_events_timeout(ctx, &tv);
-
- usbi_mutex_lock(&ctx->usb_devs_lock);
- list_for_each_entry_safe(dev, next, &ctx->usb_devs, list, struct libusb_device) {
- list_del(&dev->list);
- libusb_unref_device(dev);
- }
- usbi_mutex_unlock(&ctx->usb_devs_lock);
- }
-
- /* a few sanity checks. don't bother with locking because unless
- * there is an application bug, nobody will be accessing these. */
- if (!list_empty(&ctx->usb_devs))
- usbi_warn(ctx, "some libusb_devices were leaked");
- 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);
- usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
- free(ctx);
-}
-
-/** \ingroup libusb_misc
- * Check at runtime if the loaded library has a given capability.
- * This call should be performed after \ref libusb_init(), to ensure the
- * backend has updated its capability set.
- *
- * \param capability the \ref libusb_capability to check for
- * \returns nonzero if the running library has the capability, 0 otherwise
- */
-int API_EXPORTED libusb_has_capability(uint32_t capability)
-{
- switch (capability) {
- case LIBUSB_CAP_HAS_CAPABILITY:
- return 1;
- case LIBUSB_CAP_HAS_HOTPLUG:
- return !(usbi_backend->get_device_list);
- case LIBUSB_CAP_HAS_HID_ACCESS:
- return (usbi_backend->caps & USBI_CAP_HAS_HID_ACCESS);
- case LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER:
- return (usbi_backend->caps & USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER);
- }
- return 0;
-}
-
-/* this is defined in libusbi.h if needed */
-#ifdef LIBUSB_PRINTF_WIN32
-/*
- * Prior to VS2015, Microsoft did not provide the snprintf() function and
- * provided a vsnprintf() that did not guarantee NULL-terminated output.
- * Microsoft did provide a _snprintf() function, but again it did not
- * guarantee NULL-terminated output.
- *
- * The below implementations guarantee NULL-terminated output and are
- * C99 compliant.
- */
-
-int usbi_snprintf(char *str, size_t size, const char *format, ...)
-{
- va_list ap;
- int ret;
-
- va_start(ap, format);
- ret = usbi_vsnprintf(str, size, format, ap);
- va_end(ap);
-
- return ret;
-}
-
-int usbi_vsnprintf(char *str, size_t size, const char *format, va_list ap)
-{
- int ret;
-
- ret = _vsnprintf(str, size, format, ap);
- if (ret < 0 || ret == (int)size) {
- /* Output is truncated, ensure buffer is NULL-terminated and
- * determine how many characters would have been written. */
- str[size - 1] = '\0';
- if (ret < 0)
- ret = _vsnprintf(NULL, 0, format, ap);
- }
-
- return ret;
-}
-#endif
-
-static void usbi_log_str(struct libusb_context *ctx,
- enum libusb_log_level level, const char * str)
-{
-#if defined(USE_SYSTEM_LOGGING_FACILITY)
-#if defined(OS_WINDOWS)
- OutputDebugString(str);
-#elif defined(OS_WINCE)
- /* Windows CE only supports the Unicode version of OutputDebugString. */
- WCHAR wbuf[USBI_MAX_LOG_LEN];
- MultiByteToWideChar(CP_UTF8, 0, str, -1, wbuf, sizeof(wbuf));
- OutputDebugStringW(wbuf);
-#elif defined(__ANDROID__)
- int priority = ANDROID_LOG_UNKNOWN;
- switch (level) {
- case LIBUSB_LOG_LEVEL_INFO: priority = ANDROID_LOG_INFO; break;
- case LIBUSB_LOG_LEVEL_WARNING: priority = ANDROID_LOG_WARN; break;
- case LIBUSB_LOG_LEVEL_ERROR: priority = ANDROID_LOG_ERROR; break;
- case LIBUSB_LOG_LEVEL_DEBUG: priority = ANDROID_LOG_DEBUG; break;
- }
- __android_log_write(priority, "libusb", str);
-#elif defined(HAVE_SYSLOG_FUNC)
- int syslog_level = LOG_INFO;
- switch (level) {
- case LIBUSB_LOG_LEVEL_INFO: syslog_level = LOG_INFO; break;
- case LIBUSB_LOG_LEVEL_WARNING: syslog_level = LOG_WARNING; break;
- case LIBUSB_LOG_LEVEL_ERROR: syslog_level = LOG_ERR; break;
- case LIBUSB_LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break;
- }
- syslog(syslog_level, "%s", str);
-#else /* All of gcc, Clang, XCode seem to use #warning */
-#warning System logging is not supported on this platform. Logging to stderr will be used instead.
- fputs(str, stderr);
-#endif
-#else
- fputs(str, stderr);
-#endif /* USE_SYSTEM_LOGGING_FACILITY */
- UNUSED(ctx);
- UNUSED(level);
-}
-
-void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
- const char *function, const char *format, va_list args)
-{
- const char *prefix = "";
- char buf[USBI_MAX_LOG_LEN];
- struct timespec now;
- int global_debug, header_len, text_len;
- static int has_debug_header_been_displayed = 0;
-
-#ifdef ENABLE_DEBUG_LOGGING
- global_debug = 1;
- UNUSED(ctx);
-#else
- int ctx_level = 0;
-
- USBI_GET_CONTEXT(ctx);
- if (ctx) {
- ctx_level = ctx->debug;
- } else {
- char *dbg = getenv("LIBUSB_DEBUG");
- if (dbg)
- ctx_level = atoi(dbg);
- }
- global_debug = (ctx_level == LIBUSB_LOG_LEVEL_DEBUG);
- if (!ctx_level)
- return;
- if (level == LIBUSB_LOG_LEVEL_WARNING && ctx_level < LIBUSB_LOG_LEVEL_WARNING)
- return;
- if (level == LIBUSB_LOG_LEVEL_INFO && ctx_level < LIBUSB_LOG_LEVEL_INFO)
- return;
- if (level == LIBUSB_LOG_LEVEL_DEBUG && ctx_level < LIBUSB_LOG_LEVEL_DEBUG)
- return;
-#endif
-
- usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &now);
- if ((global_debug) && (!has_debug_header_been_displayed)) {
- has_debug_header_been_displayed = 1;
- usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "[timestamp] [threadID] facility level [function call] <message>" USBI_LOG_LINE_END);
- usbi_log_str(ctx, LIBUSB_LOG_LEVEL_DEBUG, "--------------------------------------------------------------------------------" USBI_LOG_LINE_END);
- }
- if (now.tv_nsec < timestamp_origin.tv_nsec) {
- now.tv_sec--;
- now.tv_nsec += 1000000000L;
- }
- now.tv_sec -= timestamp_origin.tv_sec;
- now.tv_nsec -= timestamp_origin.tv_nsec;
-
- switch (level) {
- case LIBUSB_LOG_LEVEL_INFO:
- prefix = "info";
- break;
- case LIBUSB_LOG_LEVEL_WARNING:
- prefix = "warning";
- break;
- case LIBUSB_LOG_LEVEL_ERROR:
- prefix = "error";
- break;
- case LIBUSB_LOG_LEVEL_DEBUG:
- prefix = "debug";
- break;
- case LIBUSB_LOG_LEVEL_NONE:
- return;
- default:
- prefix = "unknown";
- break;
- }
-
- if (global_debug) {
- header_len = snprintf(buf, sizeof(buf),
- "[%2d.%06d] [%08x] libusb: %s [%s] ",
- (int)now.tv_sec, (int)(now.tv_nsec / 1000L), usbi_get_tid(), prefix, function);
- } else {
- header_len = snprintf(buf, sizeof(buf),
- "libusb: %s [%s] ", prefix, function);
- }
-
- if (header_len < 0 || header_len >= (int)sizeof(buf)) {
- /* Somehow snprintf failed to write to the buffer,
- * remove the header so something useful is output. */
- header_len = 0;
- }
- /* Make sure buffer is NUL terminated */
- buf[header_len] = '\0';
- text_len = vsnprintf(buf + header_len, sizeof(buf) - header_len,
- format, args);
- if (text_len < 0 || text_len + header_len >= (int)sizeof(buf)) {
- /* Truncated log output. On some platforms a -1 return value means
- * that the output was truncated. */
- text_len = sizeof(buf) - header_len;
- }
- if (header_len + text_len + sizeof(USBI_LOG_LINE_END) >= sizeof(buf)) {
- /* Need to truncate the text slightly to fit on the terminator. */
- text_len -= (header_len + text_len + sizeof(USBI_LOG_LINE_END)) - sizeof(buf);
- }
- strcpy(buf + header_len + text_len, USBI_LOG_LINE_END);
-
- usbi_log_str(ctx, level, buf);
-}
-
-void usbi_log(struct libusb_context *ctx, enum libusb_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 libusb_misc
- * Returns a constant NULL-terminated string with the ASCII name of a libusb
- * error or transfer status code. The caller must not free() the returned
- * string.
- *
- * \param error_code The \ref libusb_error or libusb_transfer_status 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 / status code.
- */
-DEFAULT_VISIBILITY const char * LIBUSB_CALL libusb_error_name(int error_code)
-{
- switch (error_code) {
- 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";
-
- case LIBUSB_TRANSFER_ERROR:
- return "LIBUSB_TRANSFER_ERROR";
- case LIBUSB_TRANSFER_TIMED_OUT:
- return "LIBUSB_TRANSFER_TIMED_OUT";
- case LIBUSB_TRANSFER_CANCELLED:
- return "LIBUSB_TRANSFER_CANCELLED";
- case LIBUSB_TRANSFER_STALL:
- return "LIBUSB_TRANSFER_STALL";
- case LIBUSB_TRANSFER_NO_DEVICE:
- return "LIBUSB_TRANSFER_NO_DEVICE";
- case LIBUSB_TRANSFER_OVERFLOW:
- return "LIBUSB_TRANSFER_OVERFLOW";
-
- case 0:
- return "LIBUSB_SUCCESS / LIBUSB_TRANSFER_COMPLETED";
- default:
- return "**UNKNOWN**";
- }
-}
-
-/** \ingroup libusb_misc
- * Returns a pointer to const struct libusb_version with the version
- * (major, minor, micro, nano and rc) of the running library.
- */
-DEFAULT_VISIBILITY
-const struct libusb_version * LIBUSB_CALL libusb_get_version(void)
-{
- return &libusb_version_internal;
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c b/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c
deleted file mode 100644
index 4c9435f..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/descriptor.c
+++ /dev/null
@@ -1,1191 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
-/*
- * USB descriptor handling functions for libusb
- * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
- * Copyright © 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 <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 libusb_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(const unsigned char *source, const char *descriptor,
- void *dest, int host_endian)
-{
- const unsigned char *sp = source;
- unsigned char *dp = dest;
- uint16_t w;
- const char *cp;
- uint32_t d;
-
- 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;
- case 'd': /* 32-bit word, convert from little endian to CPU */
- dp += ((uintptr_t)dp & 1); /* Align to word boundary */
-
- if (host_endian) {
- memcpy(dp, sp, 4);
- } else {
- d = (sp[3] << 24) | (sp[2] << 16) |
- (sp[1] << 8) | sp[0];
- *((uint32_t *)dp) = d;
- }
- sp += 4;
- dp += 4;
- break;
- case 'u': /* 16 byte UUID */
- memcpy(dp, sp, 16);
- sp += 16;
- dp += 16;
- break;
- }
- }
-
- return (int) (sp - source);
-}
-
-static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
-{
- free((void *) 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;
-
- if (size < DESC_HEADER_LENGTH) {
- usbi_err(ctx, "short endpoint descriptor read %d/%d",
- size, DESC_HEADER_LENGTH);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(buffer, "bb", &header, 0);
- if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) {
- usbi_err(ctx, "unexpected descriptor %x (expected %x)",
- header.bDescriptorType, LIBUSB_DT_ENDPOINT);
- return parsed;
- }
- if (header.bLength > size) {
- usbi_warn(ctx, "short endpoint descriptor read %d/%d",
- size, header.bLength);
- 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);
- else {
- usbi_err(ctx, "invalid endpoint bLength (%d)", header.bLength);
- return LIBUSB_ERROR_IO;
- }
-
- 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 < DESC_HEADER_LENGTH) {
- usbi_err(ctx, "invalid extra ep desc len (%d)",
- header.bLength);
- return LIBUSB_ERROR_IO;
- } else if (header.bLength > size) {
- usbi_warn(ctx, "short extra ep desc read %d/%d",
- size, header.bLength);
- return parsed;
- }
-
- /* 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;
- 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;
- int interface_number = -1;
- 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 = usbi_reallocf(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;
- usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0);
- if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) {
- usbi_err(ctx, "unexpected descriptor %x (expected %x)",
- ifp->bDescriptorType, LIBUSB_DT_INTERFACE);
- return parsed;
- }
- if (ifp->bLength < INTERFACE_DESC_LENGTH) {
- usbi_err(ctx, "invalid interface bLength (%d)",
- ifp->bLength);
- r = LIBUSB_ERROR_IO;
- goto err;
- }
- if (ifp->bLength > size) {
- usbi_warn(ctx, "short intf descriptor read %d/%d",
- size, ifp->bLength);
- return parsed;
- }
- if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
- usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints);
- r = LIBUSB_ERROR_IO;
- goto err;
- }
-
- usb_interface->num_altsetting++;
- ifp->extra = NULL;
- ifp->extra_length = 0;
- ifp->endpoint = NULL;
-
- if (interface_number == -1)
- interface_number = ifp->bInterfaceNumber;
-
- /* 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 < DESC_HEADER_LENGTH) {
- usbi_err(ctx,
- "invalid extra intf desc len (%d)",
- header.bLength);
- r = LIBUSB_ERROR_IO;
- goto err;
- } else if (header.bLength > size) {
- usbi_warn(ctx,
- "short extra intf desc read %d/%d",
- size, header.bLength);
- return parsed;
- }
-
- /* 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;
- }
-
- if (ifp->bNumEndpoints > 0) {
- struct libusb_endpoint_descriptor *endpoint;
- endpoint = calloc(ifp->bNumEndpoints, sizeof(struct libusb_endpoint_descriptor));
- ifp->endpoint = endpoint;
- if (!endpoint) {
- r = LIBUSB_ERROR_NO_MEM;
- goto err;
- }
-
- for (i = 0; i < ifp->bNumEndpoints; i++) {
- r = parse_endpoint(ctx, endpoint + i, buffer, size,
- host_endian);
- if (r < 0)
- goto err;
- if (r == 0) {
- ifp->bNumEndpoints = (uint8_t)i;
- break;;
- }
-
- 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->bInterfaceNumber != interface_number)
- return parsed;
- }
-
- return parsed;
-err:
- clear_interface(usb_interface);
- return r;
-}
-
-static void clear_configuration(struct libusb_config_descriptor *config)
-{
- int i;
- if (config->interface) {
- for (i = 0; i < config->bNumInterfaces; i++)
- clear_interface((struct libusb_interface *)
- config->interface + i);
- }
- free((void *) config->interface);
- free((void *) config->extra);
-}
-
-static int parse_configuration(struct libusb_context *ctx,
- struct libusb_config_descriptor *config, unsigned char *buffer,
- int size, int host_endian)
-{
- int i;
- int r;
- struct usb_descriptor_header header;
- struct libusb_interface *usb_interface;
-
- if (size < LIBUSB_DT_CONFIG_SIZE) {
- usbi_err(ctx, "short config descriptor read %d/%d",
- size, LIBUSB_DT_CONFIG_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian);
- if (config->bDescriptorType != LIBUSB_DT_CONFIG) {
- usbi_err(ctx, "unexpected descriptor %x (expected %x)",
- config->bDescriptorType, LIBUSB_DT_CONFIG);
- return LIBUSB_ERROR_IO;
- }
- if (config->bLength < LIBUSB_DT_CONFIG_SIZE) {
- usbi_err(ctx, "invalid config bLength (%d)", config->bLength);
- return LIBUSB_ERROR_IO;
- }
- if (config->bLength > size) {
- usbi_err(ctx, "short config descriptor read %d/%d",
- size, config->bLength);
- return LIBUSB_ERROR_IO;
- }
- if (config->bNumInterfaces > USB_MAXINTERFACES) {
- usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces);
- return LIBUSB_ERROR_IO;
- }
-
- usb_interface = calloc(config->bNumInterfaces, sizeof(struct libusb_interface));
- config->interface = usb_interface;
- if (!usb_interface)
- return LIBUSB_ERROR_NO_MEM;
-
- 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 < DESC_HEADER_LENGTH) {
- usbi_err(ctx,
- "invalid extra config desc len (%d)",
- header.bLength);
- r = LIBUSB_ERROR_IO;
- goto err;
- } else if (header.bLength > size) {
- usbi_warn(ctx,
- "short extra config desc read %d/%d",
- size, header.bLength);
- config->bNumInterfaces = (uint8_t)i;
- return size;
- }
-
- /* 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", 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;
- if (r == 0) {
- config->bNumInterfaces = (uint8_t)i;
- break;
- }
-
- buffer += r;
- size -= r;
- }
-
- return size;
-
-err:
- clear_configuration(config);
- return r;
-}
-
-static int raw_desc_to_config(struct libusb_context *ctx,
- unsigned char *buf, int size, int host_endian,
- struct libusb_config_descriptor **config)
-{
- struct libusb_config_descriptor *_config = malloc(sizeof(*_config));
- int r;
-
- if (!_config)
- return LIBUSB_ERROR_NO_MEM;
-
- r = parse_configuration(ctx, _config, buf, size, host_endian);
- if (r < 0) {
- usbi_err(ctx, "parse_configuration failed with error %d", r);
- free(_config);
- return r;
- } else if (r > 0) {
- usbi_warn(ctx, "still %d bytes of descriptor data left", r);
- }
-
- *config = _config;
- return LIBUSB_SUCCESS;
-}
-
-int usbi_device_cache_descriptor(libusb_device *dev)
-{
- int r, host_endian = 0;
-
- r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->device_descriptor,
- &host_endian);
- if (r < 0)
- return r;
-
- if (!host_endian) {
- dev->device_descriptor.bcdUSB = libusb_le16_to_cpu(dev->device_descriptor.bcdUSB);
- dev->device_descriptor.idVendor = libusb_le16_to_cpu(dev->device_descriptor.idVendor);
- dev->device_descriptor.idProduct = libusb_le16_to_cpu(dev->device_descriptor.idProduct);
- dev->device_descriptor.bcdDevice = libusb_le16_to_cpu(dev->device_descriptor.bcdDevice);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_desc
- * Get the USB device descriptor for a given device.
- *
- * This is a non-blocking function; the device descriptor is cached in memory.
- *
- * Note since libusb-1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102, this
- * function always succeeds.
- *
- * \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)
-{
- usbi_dbg("");
- memcpy((unsigned char *) desc, (unsigned char *) &dev->device_descriptor,
- sizeof (dev->device_descriptor));
- return 0;
-}
-
-/** \ingroup libusb_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;
- unsigned char tmp[LIBUSB_DT_CONFIG_SIZE];
- unsigned char *buf = NULL;
- int host_endian = 0;
- int r;
-
- r = usbi_backend->get_active_config_descriptor(dev, tmp,
- LIBUSB_DT_CONFIG_SIZE, &host_endian);
- if (r < 0)
- return r;
- if (r < LIBUSB_DT_CONFIG_SIZE) {
- usbi_err(dev->ctx, "short config descriptor read %d/%d",
- r, LIBUSB_DT_CONFIG_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(tmp, "bbw", &_config, host_endian);
- buf = malloc(_config.wTotalLength);
- if (!buf)
- return LIBUSB_ERROR_NO_MEM;
-
- r = usbi_backend->get_active_config_descriptor(dev, buf,
- _config.wTotalLength, &host_endian);
- if (r >= 0)
- r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
-
- free(buf);
- return r;
-}
-
-/** \ingroup libusb_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[LIBUSB_DT_CONFIG_SIZE];
- 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;
-
- r = usbi_backend->get_config_descriptor(dev, config_index, tmp,
- LIBUSB_DT_CONFIG_SIZE, &host_endian);
- if (r < 0)
- return r;
- if (r < LIBUSB_DT_CONFIG_SIZE) {
- usbi_err(dev->ctx, "short config descriptor read %d/%d",
- r, LIBUSB_DT_CONFIG_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(tmp, "bbw", &_config, host_endian);
- buf = malloc(_config.wTotalLength);
- if (!buf)
- return LIBUSB_ERROR_NO_MEM;
-
- r = usbi_backend->get_config_descriptor(dev, config_index, buf,
- _config.wTotalLength, &host_endian);
- if (r >= 0)
- r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
-
- 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 on success 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) {
- *idx = -1;
- return r;
- }
- if (tmp[5] == bConfigurationValue) {
- *idx = i;
- return 0;
- }
- }
-
- *idx = -1;
- return 0;
-}
-
-/** \ingroup libusb_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 r, idx, host_endian;
- unsigned char *buf = NULL;
-
- if (usbi_backend->get_config_descriptor_by_value) {
- r = usbi_backend->get_config_descriptor_by_value(dev,
- bConfigurationValue, &buf, &host_endian);
- if (r < 0)
- return r;
- return raw_desc_to_config(dev->ctx, buf, r, host_endian, config);
- }
-
- 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 libusb_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 libusb_desc
- * Get an endpoints superspeed endpoint companion descriptor (if any)
- *
- * \param ctx the context to operate on, or NULL for the default context
- * \param endpoint endpoint descriptor from which to get the superspeed
- * endpoint companion descriptor
- * \param ep_comp output location for the superspeed endpoint companion
- * descriptor. Only valid if 0 was returned. Must be freed with
- * libusb_free_ss_endpoint_companion_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
- */
-int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor(
- struct libusb_context *ctx,
- const struct libusb_endpoint_descriptor *endpoint,
- struct libusb_ss_endpoint_companion_descriptor **ep_comp)
-{
- struct usb_descriptor_header header;
- int size = endpoint->extra_length;
- const unsigned char *buffer = endpoint->extra;
-
- *ep_comp = NULL;
-
- while (size >= DESC_HEADER_LENGTH) {
- usbi_parse_descriptor(buffer, "bb", &header, 0);
- if (header.bLength < 2 || header.bLength > size) {
- usbi_err(ctx, "invalid descriptor length %d",
- header.bLength);
- return LIBUSB_ERROR_IO;
- }
- if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
- buffer += header.bLength;
- size -= header.bLength;
- continue;
- }
- if (header.bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) {
- usbi_err(ctx, "invalid ss-ep-comp-desc length %d",
- header.bLength);
- return LIBUSB_ERROR_IO;
- }
- *ep_comp = malloc(sizeof(**ep_comp));
- if (*ep_comp == NULL)
- return LIBUSB_ERROR_NO_MEM;
- usbi_parse_descriptor(buffer, "bbbbw", *ep_comp, 0);
- return LIBUSB_SUCCESS;
- }
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/** \ingroup libusb_desc
- * Free a superspeed endpoint companion descriptor obtained from
- * libusb_get_ss_endpoint_companion_descriptor().
- * It is safe to call this function with a NULL ep_comp parameter, in which
- * case the function simply returns.
- *
- * \param ep_comp the superspeed endpoint companion descriptor to free
- */
-void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor(
- struct libusb_ss_endpoint_companion_descriptor *ep_comp)
-{
- free(ep_comp);
-}
-
-static int parse_bos(struct libusb_context *ctx,
- struct libusb_bos_descriptor **bos,
- unsigned char *buffer, int size, int host_endian)
-{
- struct libusb_bos_descriptor bos_header, *_bos;
- struct libusb_bos_dev_capability_descriptor dev_cap;
- int i;
-
- if (size < LIBUSB_DT_BOS_SIZE) {
- usbi_err(ctx, "short bos descriptor read %d/%d",
- size, LIBUSB_DT_BOS_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(buffer, "bbwb", &bos_header, host_endian);
- if (bos_header.bDescriptorType != LIBUSB_DT_BOS) {
- usbi_err(ctx, "unexpected descriptor %x (expected %x)",
- bos_header.bDescriptorType, LIBUSB_DT_BOS);
- return LIBUSB_ERROR_IO;
- }
- if (bos_header.bLength < LIBUSB_DT_BOS_SIZE) {
- usbi_err(ctx, "invalid bos bLength (%d)", bos_header.bLength);
- return LIBUSB_ERROR_IO;
- }
- if (bos_header.bLength > size) {
- usbi_err(ctx, "short bos descriptor read %d/%d",
- size, bos_header.bLength);
- return LIBUSB_ERROR_IO;
- }
-
- _bos = calloc (1,
- sizeof(*_bos) + bos_header.bNumDeviceCaps * sizeof(void *));
- if (!_bos)
- return LIBUSB_ERROR_NO_MEM;
-
- usbi_parse_descriptor(buffer, "bbwb", _bos, host_endian);
- buffer += bos_header.bLength;
- size -= bos_header.bLength;
-
- /* Get the device capability descriptors */
- for (i = 0; i < bos_header.bNumDeviceCaps; i++) {
- if (size < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) {
- usbi_warn(ctx, "short dev-cap descriptor read %d/%d",
- size, LIBUSB_DT_DEVICE_CAPABILITY_SIZE);
- break;
- }
- usbi_parse_descriptor(buffer, "bbb", &dev_cap, host_endian);
- if (dev_cap.bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) {
- usbi_warn(ctx, "unexpected descriptor %x (expected %x)",
- dev_cap.bDescriptorType, LIBUSB_DT_DEVICE_CAPABILITY);
- break;
- }
- if (dev_cap.bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) {
- usbi_err(ctx, "invalid dev-cap bLength (%d)",
- dev_cap.bLength);
- libusb_free_bos_descriptor(_bos);
- return LIBUSB_ERROR_IO;
- }
- if (dev_cap.bLength > size) {
- usbi_warn(ctx, "short dev-cap descriptor read %d/%d",
- size, dev_cap.bLength);
- break;
- }
-
- _bos->dev_capability[i] = malloc(dev_cap.bLength);
- if (!_bos->dev_capability[i]) {
- libusb_free_bos_descriptor(_bos);
- return LIBUSB_ERROR_NO_MEM;
- }
- memcpy(_bos->dev_capability[i], buffer, dev_cap.bLength);
- buffer += dev_cap.bLength;
- size -= dev_cap.bLength;
- }
- _bos->bNumDeviceCaps = (uint8_t)i;
- *bos = _bos;
-
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_desc
- * Get a Binary Object Store (BOS) descriptor
- * This is a BLOCKING function, which will send requests to the device.
- *
- * \param dev_handle the handle of an open libusb device
- * \param bos output location for the BOS descriptor. Only valid if 0 was returned.
- * Must be freed with \ref libusb_free_bos_descriptor() after use.
- * \returns 0 on success
- * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor
- * \returns another LIBUSB_ERROR code on error
- */
-int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle,
- struct libusb_bos_descriptor **bos)
-{
- struct libusb_bos_descriptor _bos;
- uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0};
- unsigned char *bos_data = NULL;
- const int host_endian = 0;
- int r;
-
- /* Read the BOS. This generates 2 requests on the bus,
- * one for the header, and one for the full BOS */
- r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_header,
- LIBUSB_DT_BOS_SIZE);
- if (r < 0) {
- if (r != LIBUSB_ERROR_PIPE)
- usbi_err(HANDLE_CTX(dev_handle), "failed to read BOS (%d)", r);
- return r;
- }
- if (r < LIBUSB_DT_BOS_SIZE) {
- usbi_err(HANDLE_CTX(dev_handle), "short BOS read %d/%d",
- r, LIBUSB_DT_BOS_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(bos_header, "bbwb", &_bos, host_endian);
- usbi_dbg("found BOS descriptor: size %d bytes, %d capabilities",
- _bos.wTotalLength, _bos.bNumDeviceCaps);
- bos_data = calloc(_bos.wTotalLength, 1);
- if (bos_data == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_data,
- _bos.wTotalLength);
- if (r >= 0)
- r = parse_bos(HANDLE_CTX(dev_handle), bos, bos_data, r, host_endian);
- else
- usbi_err(HANDLE_CTX(dev_handle), "failed to read BOS (%d)", r);
-
- free(bos_data);
- return r;
-}
-
-/** \ingroup libusb_desc
- * Free a BOS descriptor obtained from libusb_get_bos_descriptor().
- * It is safe to call this function with a NULL bos parameter, in which
- * case the function simply returns.
- *
- * \param bos the BOS descriptor to free
- */
-void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
-{
- int i;
-
- if (!bos)
- return;
-
- for (i = 0; i < bos->bNumDeviceCaps; i++)
- free(bos->dev_capability[i]);
- free(bos);
-}
-
-/** \ingroup libusb_desc
- * Get an USB 2.0 Extension descriptor
- *
- * \param ctx the context to operate on, or NULL for the default context
- * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
- * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
- * LIBUSB_BT_USB_2_0_EXTENSION
- * \param usb_2_0_extension output location for the USB 2.0 Extension
- * descriptor. Only valid if 0 was returned. Must be freed with
- * libusb_free_usb_2_0_extension_descriptor() after use.
- * \returns 0 on success
- * \returns a LIBUSB_ERROR code on error
- */
-int API_EXPORTED libusb_get_usb_2_0_extension_descriptor(
- struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension)
-{
- struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension;
- const int host_endian = 0;
-
- if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) {
- usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
- dev_cap->bDevCapabilityType,
- LIBUSB_BT_USB_2_0_EXTENSION);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) {
- usbi_err(ctx, "short dev-cap descriptor read %d/%d",
- dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- _usb_2_0_extension = malloc(sizeof(*_usb_2_0_extension));
- if (!_usb_2_0_extension)
- return LIBUSB_ERROR_NO_MEM;
-
- usbi_parse_descriptor((unsigned char *)dev_cap, "bbbd",
- _usb_2_0_extension, host_endian);
-
- *usb_2_0_extension = _usb_2_0_extension;
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_desc
- * Free a USB 2.0 Extension descriptor obtained from
- * libusb_get_usb_2_0_extension_descriptor().
- * It is safe to call this function with a NULL usb_2_0_extension parameter,
- * in which case the function simply returns.
- *
- * \param usb_2_0_extension the USB 2.0 Extension descriptor to free
- */
-void API_EXPORTED libusb_free_usb_2_0_extension_descriptor(
- struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension)
-{
- free(usb_2_0_extension);
-}
-
-/** \ingroup libusb_desc
- * Get a SuperSpeed USB Device Capability descriptor
- *
- * \param ctx the context to operate on, or NULL for the default context
- * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
- * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
- * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
- * \param ss_usb_device_cap output location for the SuperSpeed USB Device
- * Capability descriptor. Only valid if 0 was returned. Must be freed with
- * libusb_free_ss_usb_device_capability_descriptor() after use.
- * \returns 0 on success
- * \returns a LIBUSB_ERROR code on error
- */
-int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
- struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap)
-{
- struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap;
- const int host_endian = 0;
-
- if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) {
- usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
- dev_cap->bDevCapabilityType,
- LIBUSB_BT_SS_USB_DEVICE_CAPABILITY);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) {
- usbi_err(ctx, "short dev-cap descriptor read %d/%d",
- dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- _ss_usb_device_cap = malloc(sizeof(*_ss_usb_device_cap));
- if (!_ss_usb_device_cap)
- return LIBUSB_ERROR_NO_MEM;
-
- usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbwbbw",
- _ss_usb_device_cap, host_endian);
-
- *ss_usb_device_cap = _ss_usb_device_cap;
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_desc
- * Free a SuperSpeed USB Device Capability descriptor obtained from
- * libusb_get_ss_usb_device_capability_descriptor().
- * It is safe to call this function with a NULL ss_usb_device_cap
- * parameter, in which case the function simply returns.
- *
- * \param ss_usb_device_cap the USB 2.0 Extension descriptor to free
- */
-void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor(
- struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap)
-{
- free(ss_usb_device_cap);
-}
-
-/** \ingroup libusb_desc
- * Get a Container ID descriptor
- *
- * \param ctx the context to operate on, or NULL for the default context
- * \param dev_cap Device Capability descriptor with a bDevCapabilityType of
- * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
- * LIBUSB_BT_CONTAINER_ID
- * \param container_id output location for the Container ID descriptor.
- * Only valid if 0 was returned. Must be freed with
- * libusb_free_container_id_descriptor() after use.
- * \returns 0 on success
- * \returns a LIBUSB_ERROR code on error
- */
-int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_container_id_descriptor **container_id)
-{
- struct libusb_container_id_descriptor *_container_id;
- const int host_endian = 0;
-
- if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) {
- usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)",
- dev_cap->bDevCapabilityType,
- LIBUSB_BT_CONTAINER_ID);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) {
- usbi_err(ctx, "short dev-cap descriptor read %d/%d",
- dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- _container_id = malloc(sizeof(*_container_id));
- if (!_container_id)
- return LIBUSB_ERROR_NO_MEM;
-
- usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbu",
- _container_id, host_endian);
-
- *container_id = _container_id;
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_desc
- * Free a Container ID descriptor obtained from
- * libusb_get_container_id_descriptor().
- * It is safe to call this function with a NULL container_id parameter,
- * in which case the function simply returns.
- *
- * \param container_id the USB 2.0 Extension descriptor to free
- */
-void API_EXPORTED libusb_free_container_id_descriptor(
- struct libusb_container_id_descriptor *container_id)
-{
- free(container_id);
-}
-
-/** \ingroup libusb_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_handle 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_handle,
- 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_handle, 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_handle, 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] & 0x80) || (tbuf[si + 1])) /* non-ASCII */
- data[di++] = '?';
- else
- data[di++] = tbuf[si];
- }
-
- data[di] = 0;
- return di;
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c b/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c
deleted file mode 100644
index bbfd6e7..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
-/*
- * Hotplug functions for libusb
- * Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright © 2012-2013 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
- */
-
-#include <config.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#include <assert.h>
-
-#include "libusbi.h"
-#include "hotplug.h"
-
-/**
- * @defgroup libusb_hotplug Device hotplug event notification
- * This page details how to use the libusb hotplug interface, where available.
- *
- * Be mindful that not all platforms currently implement hotplug notification and
- * that you should first call on \ref libusb_has_capability() with parameter
- * \ref LIBUSB_CAP_HAS_HOTPLUG to confirm that hotplug support is available.
- *
- * \page libusb_hotplug Device hotplug event notification
- *
- * \section hotplug_intro Introduction
- *
- * Version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102, has added support
- * for hotplug events on <b>some</b> platforms (you should test if your platform
- * supports hotplug notification by calling \ref libusb_has_capability() with
- * parameter \ref LIBUSB_CAP_HAS_HOTPLUG).
- *
- * This interface allows you to request notification for the arrival and departure
- * of matching USB devices.
- *
- * To receive hotplug notification you register a callback by calling
- * \ref libusb_hotplug_register_callback(). This function will optionally return
- * a callback handle that can be passed to \ref libusb_hotplug_deregister_callback().
- *
- * A callback function must return an int (0 or 1) indicating whether the callback is
- * expecting additional events. Returning 0 will rearm the callback and 1 will cause
- * the callback to be deregistered. Note that when callbacks are called from
- * libusb_hotplug_register_callback() because of the \ref LIBUSB_HOTPLUG_ENUMERATE
- * flag, the callback return value is ignored, iow you cannot cause a callback
- * to be deregistered by returning 1 when it is called from
- * libusb_hotplug_register_callback().
- *
- * Callbacks for a particular context are automatically deregistered by libusb_exit().
- *
- * As of 1.0.16 there are two supported hotplug events:
- * - LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: A device has arrived and is ready to use
- * - LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: A device has left and is no longer available
- *
- * A hotplug event can listen for either or both of these events.
- *
- * Note: If you receive notification that a device has left and you have any
- * a libusb_device_handles for the device it is up to you to call libusb_close()
- * on each device handle to free up any remaining resources associated with the device.
- * Once a device has left any libusb_device_handle associated with the device
- * are invalid and will remain so even if the device comes back.
- *
- * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered
- * safe to call any libusb function that takes a libusb_device. It also safe to
- * open a device and submit asynchronous transfers. However, most other functions
- * that take a libusb_device_handle are <b>not</b> safe to call. Examples of such
- * functions are any of the \ref libusb_syncio "synchronous API" functions or the blocking
- * functions that retrieve various \ref libusb_desc "USB descriptors". These functions must
- * be used outside of the context of the hotplug callback.
- *
- * When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT event the only safe function
- * is libusb_get_device_descriptor().
- *
- * The following code provides an example of the usage of the hotplug interface:
-\code
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <libusb.h>
-
-static int count = 0;
-
-int hotplug_callback(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event, void *user_data) {
- static libusb_device_handle *dev_handle = NULL;
- struct libusb_device_descriptor desc;
- int rc;
-
- (void)libusb_get_device_descriptor(dev, &desc);
-
- if (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event) {
- rc = libusb_open(dev, &dev_handle);
- if (LIBUSB_SUCCESS != rc) {
- printf("Could not open USB device\n");
- }
- } else if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == event) {
- if (dev_handle) {
- libusb_close(dev_handle);
- dev_handle = NULL;
- }
- } else {
- printf("Unhandled event %d\n", event);
- }
- count++;
-
- return 0;
-}
-
-int main (void) {
- libusb_hotplug_callback_handle callback_handle;
- int rc;
-
- libusb_init(NULL);
-
- rc = libusb_hotplug_register_callback(NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |
- LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, 0x045a, 0x5005,
- LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, NULL,
- &callback_handle);
- if (LIBUSB_SUCCESS != rc) {
- printf("Error creating a hotplug callback\n");
- libusb_exit(NULL);
- return EXIT_FAILURE;
- }
-
- while (count < 2) {
- libusb_handle_events_completed(NULL, NULL);
- nanosleep(&(struct timespec){0, 10000000UL}, NULL);
- }
-
- libusb_hotplug_deregister_callback(NULL, callback_handle);
- libusb_exit(NULL);
-
- return 0;
-}
-\endcode
- */
-
-static int usbi_hotplug_match_cb (struct libusb_context *ctx,
- struct libusb_device *dev, libusb_hotplug_event event,
- struct libusb_hotplug_callback *hotplug_cb)
-{
- /* Handle lazy deregistration of callback */
- if (hotplug_cb->needs_free) {
- /* Free callback */
- return 1;
- }
-
- if (!(hotplug_cb->events & event)) {
- return 0;
- }
-
- if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->vendor_id &&
- hotplug_cb->vendor_id != dev->device_descriptor.idVendor) {
- return 0;
- }
-
- if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->product_id &&
- hotplug_cb->product_id != dev->device_descriptor.idProduct) {
- return 0;
- }
-
- if (LIBUSB_HOTPLUG_MATCH_ANY != hotplug_cb->dev_class &&
- hotplug_cb->dev_class != dev->device_descriptor.bDeviceClass) {
- return 0;
- }
-
- return hotplug_cb->cb (ctx, dev, event, hotplug_cb->user_data);
-}
-
-void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event)
-{
- struct libusb_hotplug_callback *hotplug_cb, *next;
- int ret;
-
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-
- list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list, struct libusb_hotplug_callback) {
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
- ret = usbi_hotplug_match_cb (ctx, dev, event, hotplug_cb);
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-
- if (ret) {
- list_del(&hotplug_cb->list);
- free(hotplug_cb);
- }
- }
-
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-
- /* the backend is expected to call the callback for each active transfer */
-}
-
-void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event)
-{
- int pending_events;
- libusb_hotplug_message *message = calloc(1, sizeof(*message));
-
- if (!message) {
- usbi_err(ctx, "error allocating hotplug message");
- return;
- }
-
- message->event = event;
- message->device = dev;
-
- /* Take the event data lock and add this message to the list.
- * Only signal an event if there are no prior pending events. */
- usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
- list_add_tail(&message->list, &ctx->hotplug_msgs);
- if (!pending_events)
- usbi_signal_event(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
-}
-
-int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
- libusb_hotplug_event events, libusb_hotplug_flag flags,
- int vendor_id, int product_id, int dev_class,
- libusb_hotplug_callback_fn cb_fn, void *user_data,
- libusb_hotplug_callback_handle *callback_handle)
-{
- libusb_hotplug_callback *new_callback;
- static int handle_id = 1;
-
- /* check for hotplug support */
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- /* check for sane values */
- if ((LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
- (LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
- (LIBUSB_HOTPLUG_MATCH_ANY != dev_class && (~0xff & dev_class)) ||
- !cb_fn) {
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- USBI_GET_CONTEXT(ctx);
-
- new_callback = (libusb_hotplug_callback *)calloc(1, sizeof (*new_callback));
- if (!new_callback) {
- return LIBUSB_ERROR_NO_MEM;
- }
-
- new_callback->ctx = ctx;
- new_callback->vendor_id = vendor_id;
- new_callback->product_id = product_id;
- new_callback->dev_class = dev_class;
- new_callback->flags = flags;
- new_callback->events = events;
- new_callback->cb = cb_fn;
- new_callback->user_data = user_data;
- new_callback->needs_free = 0;
-
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
-
- /* protect the handle by the context hotplug lock. it doesn't matter if the same handle
- * is used for different contexts only that the handle is unique for this context */
- new_callback->handle = handle_id++;
-
- list_add(&new_callback->list, &ctx->hotplug_cbs);
-
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-
-
- if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
- int i, len;
- struct libusb_device **devs;
-
- len = (int) libusb_get_device_list(ctx, &devs);
- if (len < 0) {
- libusb_hotplug_deregister_callback(ctx,
- new_callback->handle);
- return len;
- }
-
- for (i = 0; i < len; i++) {
- usbi_hotplug_match_cb(ctx, devs[i],
- LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
- new_callback);
- }
-
- libusb_free_device_list(devs, 1);
- }
-
-
- if (callback_handle)
- *callback_handle = new_callback->handle;
-
- return LIBUSB_SUCCESS;
-}
-
-void API_EXPORTED libusb_hotplug_deregister_callback (struct libusb_context *ctx,
- libusb_hotplug_callback_handle callback_handle)
-{
- struct libusb_hotplug_callback *hotplug_cb;
-
- /* check for hotplug support */
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- return;
- }
-
- USBI_GET_CONTEXT(ctx);
-
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- list_for_each_entry(hotplug_cb, &ctx->hotplug_cbs, list,
- struct libusb_hotplug_callback) {
- if (callback_handle == hotplug_cb->handle) {
- /* Mark this callback for deregistration */
- hotplug_cb->needs_free = 1;
- }
- }
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-
- usbi_hotplug_notification(ctx, NULL, 0);
-}
-
-void usbi_hotplug_deregister_all(struct libusb_context *ctx) {
- struct libusb_hotplug_callback *hotplug_cb, *next;
-
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- list_for_each_entry_safe(hotplug_cb, next, &ctx->hotplug_cbs, list,
- struct libusb_hotplug_callback) {
- list_del(&hotplug_cb->list);
- free(hotplug_cb);
- }
-
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h b/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h
deleted file mode 100644
index 2bec81b..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/hotplug.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
-/*
- * Hotplug support for libusb
- * Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright © 2012-2013 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
- */
-
-#if !defined(USBI_HOTPLUG_H)
-#define USBI_HOTPLUG_H
-
-#ifndef LIBUSBI_H
-#include "libusbi.h"
-#endif
-
-/** \ingroup hotplug
- * The hotplug callback structure. The user populates this structure with
- * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback()
- * to receive notification of hotplug events.
- */
-struct libusb_hotplug_callback {
- /** Context this callback is associated with */
- struct libusb_context *ctx;
-
- /** Vendor ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
- int vendor_id;
-
- /** Product ID to match or LIBUSB_HOTPLUG_MATCH_ANY */
- int product_id;
-
- /** Device class to match or LIBUSB_HOTPLUG_MATCH_ANY */
- int dev_class;
-
- /** Hotplug callback flags */
- libusb_hotplug_flag flags;
-
- /** Event(s) that will trigger this callback */
- libusb_hotplug_event events;
-
- /** Callback function to invoke for matching event/device */
- libusb_hotplug_callback_fn cb;
-
- /** Handle for this callback (used to match on deregister) */
- libusb_hotplug_callback_handle handle;
-
- /** User data that will be passed to the callback function */
- void *user_data;
-
- /** Callback is marked for deletion */
- int needs_free;
-
- /** List this callback is registered in (ctx->hotplug_cbs) */
- struct list_head list;
-};
-
-typedef struct libusb_hotplug_callback libusb_hotplug_callback;
-
-struct libusb_hotplug_message {
- /** The hotplug event that occurred */
- libusb_hotplug_event event;
-
- /** The device for which this hotplug event occurred */
- struct libusb_device *device;
-
- /** List this message is contained in (ctx->hotplug_msgs) */
- struct list_head list;
-};
-
-typedef struct libusb_hotplug_message libusb_hotplug_message;
-
-void usbi_hotplug_deregister_all(struct libusb_context *ctx);
-void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event);
-void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event);
-
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/io.c b/vendor/github.com/karalabe/hid/libusb/libusb/io.c
deleted file mode 100644
index eb1eabf..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/io.c
+++ /dev/null
@@ -1,2819 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
-/*
- * I/O functions for libusb
- * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright © 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 <assert.h>
-#include <errno.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"
-#include "hotplug.h"
-
-/**
- * \page libusb_io Synchronous and asynchronous device I/O
- *
- * \section io_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 libusb_syncio
- * - \ref libusb_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(dev_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 libusb_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 libusb_asyncio "asynchronous I/O API" documentation pages.
- */
-
-
-/**
- * \page libusb_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 libusb_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 libusb_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.
- *
- * <b>Important Note</b>: The user-specified callback is called from an event
- * handling context. It is therefore important that no calls are made into
- * libusb that will attempt to perform any event handling. Examples of such
- * functions are any listed in the \ref libusb_syncio "synchronous API" and any of
- * the blocking functions that retrieve \ref libusb_desc "USB descriptors".
- *
- * \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 libusb_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.
- *
- * <b>Note</b>: Some operating systems (e.g. Linux) may impose limits on the
- * length of individual isochronous packets and/or the total length of the
- * isochronous transfer. Such limits can be difficult for libusb to detect,
- * so the library will simply try and submit the transfer as set up by you.
- * If the transfer fails to submit because it is too large,
- * libusb_submit_transfer() will return
- * \ref libusb_error::LIBUSB_ERROR_INVALID_PARAM "LIBUSB_ERROR_INVALID_PARAM".
- *
- * \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
- *
- * 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.
- *
- * There are 2 different approaches to dealing with libusb_handle_events:
- *
- * -# Repeatedly call libusb_handle_events() in blocking mode from a dedicated
- * thread.
- * -# Integrate libusb with your application's main event loop. libusb
- * exposes a set of file descriptors which allow you to do this.
- *
- * The first approach has the big advantage that it will also work on Windows
- * were libusb' poll API for select / poll integration is not available. So
- * if you want to support Windows and use the async API, you must use this
- * approach, see the \ref eventthread "Using an event handling thread" section
- * below for details.
- *
- * If you prefer a single threaded approach with a single central event loop,
- * see the \ref libusb_poll "polling and timing" section for how to integrate libusb
- * into your application's main event loop.
- *
- * \section eventthread Using an event handling thread
- *
- * Lets begin with stating the obvious: If you're going to use a separate
- * thread for libusb event handling, your callback functions MUST be
- * threadsafe.
- *
- * Other then that doing event handling from a separate thread, is mostly
- * simple. You can use an event thread function as follows:
-\code
-void *event_thread_func(void *ctx)
-{
- while (event_thread_run)
- libusb_handle_events(ctx);
-
- return NULL;
-}
-\endcode
- *
- * There is one caveat though, stopping this thread requires setting the
- * event_thread_run variable to 0, and after that libusb_handle_events() needs
- * to return control to event_thread_func. But unless some event happens,
- * libusb_handle_events() will not return.
- *
- * There are 2 different ways of dealing with this, depending on if your
- * application uses libusb' \ref libusb_hotplug "hotplug" support or not.
- *
- * Applications which do not use hotplug support, should not start the event
- * thread until after their first call to libusb_open(), and should stop the
- * thread when closing the last open device as follows:
-\code
-void my_close_handle(libusb_device_handle *dev_handle)
-{
- if (open_devs == 1)
- event_thread_run = 0;
-
- libusb_close(dev_handle); // This wakes up libusb_handle_events()
-
- if (open_devs == 1)
- pthread_join(event_thread);
-
- open_devs--;
-}
-\endcode
- *
- * Applications using hotplug support should start the thread at program init,
- * after having successfully called libusb_hotplug_register_callback(), and
- * should stop the thread at program exit as follows:
-\code
-void my_libusb_exit(void)
-{
- event_thread_run = 0;
- libusb_hotplug_deregister_callback(ctx, hotplug_cb_handle); // This wakes up libusb_handle_events()
- pthread_join(event_thread);
- libusb_exit(ctx);
-}
-\endcode
- */
-
-/**
- * @defgroup libusb_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 libusb_asyncio "asynchronous API". If you are only using the simpler
- * \ref libusb_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.
- *
- * 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.
- *
- * On some platforms a timerfd is used, so the timeout handling is just another
- * fd, on other platforms this requires that libusb is called into at or after
- * the timeout to handle it. 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, see \ref polltime details.
- *
- * 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 libusb_pollmain The more advanced option
- *
- * \note This functionality is currently only available on Unix-like platforms.
- * On Windows, libusb_get_pollfds() simply returns NULL. Applications which
- * want to support Windows are advised to use an \ref eventthread
- * "event handling thread" instead.
- *
- * 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 libusb_mtasync
- */
-
-/** \page libusb_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 libusb_asyncio "asynchronous interface" but it is important to note that the
- * \ref libusb_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] __attribute__ ((aligned (2)));
- 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 event 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 event 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 occurring. 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);
- usbi_mutex_init(&ctx->events_lock);
- usbi_mutex_init(&ctx->event_waiters_lock);
- usbi_cond_init(&ctx->event_waiters_cond);
- usbi_mutex_init(&ctx->event_data_lock);
- usbi_tls_key_create(&ctx->event_handling_key);
- list_init(&ctx->flying_transfers);
- list_init(&ctx->ipollfds);
- list_init(&ctx->hotplug_msgs);
- list_init(&ctx->completed_transfers);
-
- /* FIXME should use an eventfd on kernels that support it */
- r = usbi_pipe(ctx->event_pipe);
- if (r < 0) {
- r = LIBUSB_ERROR_OTHER;
- goto err;
- }
-
- r = usbi_add_pollfd(ctx, ctx->event_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)
- goto err_close_timerfd;
- } else {
- usbi_dbg("timerfd not available (code %d error %d)", ctx->timerfd, errno);
- ctx->timerfd = -1;
- }
-#endif
-
- return 0;
-
-#ifdef USBI_TIMERFD_AVAILABLE
-err_close_timerfd:
- close(ctx->timerfd);
- usbi_remove_pollfd(ctx, ctx->event_pipe[0]);
-#endif
-err_close_pipe:
- usbi_close(ctx->event_pipe[0]);
- usbi_close(ctx->event_pipe[1]);
-err:
- usbi_mutex_destroy(&ctx->flying_transfers_lock);
- usbi_mutex_destroy(&ctx->events_lock);
- usbi_mutex_destroy(&ctx->event_waiters_lock);
- usbi_cond_destroy(&ctx->event_waiters_cond);
- usbi_mutex_destroy(&ctx->event_data_lock);
- usbi_tls_key_delete(ctx->event_handling_key);
- return r;
-}
-
-void usbi_io_exit(struct libusb_context *ctx)
-{
- usbi_remove_pollfd(ctx, ctx->event_pipe[0]);
- usbi_close(ctx->event_pipe[0]);
- usbi_close(ctx->event_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->events_lock);
- usbi_mutex_destroy(&ctx->event_waiters_lock);
- usbi_cond_destroy(&ctx->event_waiters_cond);
- usbi_mutex_destroy(&ctx->event_data_lock);
- usbi_tls_key_delete(ctx->event_handling_key);
- if (ctx->pollfds)
- free(ctx->pollfds);
-}
-
-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, &current_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;
-
- while (current_time.tv_nsec >= 1000000000) {
- current_time.tv_nsec -= 1000000000;
- current_time.tv_sec++;
- }
-
- TIMESPEC_TO_TIMEVAL(&transfer->timeout, &current_time);
- return 0;
-}
-
-/** \ingroup libusb_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)
-{
- struct libusb_transfer *transfer;
- size_t os_alloc_size = usbi_backend->transfer_priv_size;
- 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 = calloc(1, alloc_size);
- if (!itransfer)
- return NULL;
-
- itransfer->num_iso_packets = iso_packets;
- usbi_mutex_init(&itransfer->lock);
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- usbi_dbg("transfer %p", transfer);
- return transfer;
-}
-
-/** \ingroup libusb_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;
-
- usbi_dbg("transfer %p", transfer);
- 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);
-}
-
-#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 on success 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))
- goto disarm;
-
- /* act on first transfer that has not already been handled */
- if (!(transfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))) {
- 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 0;
- }
- }
-
-disarm:
- return disarm_timerfd(ctx);
-}
-#else
-static int arm_timerfd_for_next_timeout(struct libusb_context *ctx)
-{
- UNUSED(ctx);
- return 0;
-}
-#endif
-
-/* add a transfer to the (timeout-sorted) active transfers list.
- * This function will return non 0 if fails to update the timer,
- * in which case the transfer is *not* on the flying_transfers list. */
-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;
- int first = 1;
-
- r = calculate_timeout(transfer);
- if (r)
- return r;
-
- /* 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);
- goto out;
- }
-
- /* if we have infinite timeout, append to end of list */
- if (!timerisset(timeout)) {
- list_add_tail(&transfer->list, &ctx->flying_transfers);
- /* first is irrelevant in this case */
- 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);
- goto out;
- }
- first = 0;
- }
- /* first is 0 at this stage (list not empty) */
-
- /* otherwise we need to be inserted at the end */
- list_add_tail(&transfer->list, &ctx->flying_transfers);
-out:
-#ifdef USBI_TIMERFD_AVAILABLE
- if (first && usbi_using_timerfd(ctx) && timerisset(timeout)) {
- /* 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},
- { timeout->tv_sec, timeout->tv_usec * 1000 } };
- usbi_dbg("arm timerfd for timeout in %dms (first in line)",
- USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer)->timeout);
- r = timerfd_settime(ctx->timerfd, TFD_TIMER_ABSTIME, &it, NULL);
- if (r < 0) {
- usbi_warn(ctx, "failed to arm first timerfd (errno %d)", errno);
- r = LIBUSB_ERROR_OTHER;
- }
- }
-#else
- UNUSED(first);
-#endif
-
- if (r)
- list_del(&transfer->list);
-
- return r;
-}
-
-/* remove a transfer from the active transfers list.
- * This function will *always* remove the transfer from the
- * flying_transfers list. It will return a LIBUSB_ERROR code
- * if it fails to update the timer for the next timeout. */
-static int remove_from_flying_list(struct usbi_transfer *transfer)
-{
- struct libusb_context *ctx = ITRANSFER_CTX(transfer);
- int rearm_timerfd;
- int r = 0;
-
- usbi_mutex_lock(&ctx->flying_transfers_lock);
- rearm_timerfd = (timerisset(&transfer->timeout) &&
- list_first_entry(&ctx->flying_transfers, struct usbi_transfer, list) == transfer);
- list_del(&transfer->list);
- if (usbi_using_timerfd(ctx) && rearm_timerfd)
- r = arm_timerfd_for_next_timeout(ctx);
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
-
- return r;
-}
-
-/** \ingroup libusb_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 LIBUSB_ERROR_NOT_SUPPORTED if the transfer flags are not supported
- * by the operating system.
- * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than
- * the operating system and/or hardware can support
- * \returns another LIBUSB_ERROR code on other failure
- */
-int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
-{
- struct usbi_transfer *itransfer =
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
- struct libusb_context *ctx = TRANSFER_CTX(transfer);
- int r;
-
- usbi_dbg("transfer %p", transfer);
-
- /*
- * Important note on locking, this function takes / releases locks
- * in the following order:
- * take flying_transfers_lock
- * take itransfer->lock
- * clear transfer
- * add to flying_transfers list
- * release flying_transfers_lock
- * submit transfer
- * release itransfer->lock
- * if submit failed:
- * take flying_transfers_lock
- * remove from flying_transfers list
- * release flying_transfers_lock
- *
- * Note that it takes locks in the order a-b and then releases them
- * in the same order a-b. This is somewhat unusual but not wrong,
- * release order is not important as long as *all* locks are released
- * before re-acquiring any locks.
- *
- * This means that the ordering of first releasing itransfer->lock
- * and then re-acquiring the flying_transfers_list on error is
- * important and must not be changed!
- *
- * This is done this way because when we take both locks we must always
- * take flying_transfers_lock first to avoid ab-ba style deadlocks with
- * the timeout handling and usbi_handle_disconnect paths.
- *
- * And we cannot release itransfer->lock before the submission is
- * complete otherwise timeout handling for transfers with short
- * timeouts may run before submission.
- */
- usbi_mutex_lock(&ctx->flying_transfers_lock);
- usbi_mutex_lock(&itransfer->lock);
- if (itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT) {
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
- usbi_mutex_unlock(&itransfer->lock);
- return LIBUSB_ERROR_BUSY;
- }
- itransfer->transferred = 0;
- itransfer->state_flags = 0;
- itransfer->timeout_flags = 0;
- r = add_to_flying_list(itransfer);
- if (r) {
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
- usbi_mutex_unlock(&itransfer->lock);
- return r;
- }
- /*
- * We must release the flying transfers lock here, because with
- * some backends the submit_transfer method is synchroneous.
- */
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
-
- r = usbi_backend->submit_transfer(itransfer);
- if (r == LIBUSB_SUCCESS) {
- itransfer->state_flags |= USBI_TRANSFER_IN_FLIGHT;
- /* keep a reference to this device */
- libusb_ref_device(transfer->dev_handle->dev);
- }
- usbi_mutex_unlock(&itransfer->lock);
-
- if (r != LIBUSB_SUCCESS)
- remove_from_flying_list(itransfer);
-
- return r;
-}
-
-/** \ingroup libusb_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 not in progress,
- * already complete, or already 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("transfer %p", transfer );
- usbi_mutex_lock(&itransfer->lock);
- if (!(itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT)
- || (itransfer->state_flags & USBI_TRANSFER_CANCELLING)) {
- r = LIBUSB_ERROR_NOT_FOUND;
- goto out;
- }
- r = usbi_backend->cancel_transfer(itransfer);
- if (r < 0) {
- if (r != LIBUSB_ERROR_NOT_FOUND &&
- r != LIBUSB_ERROR_NO_DEVICE)
- usbi_err(TRANSFER_CTX(transfer),
- "cancel transfer failed error %d", r);
- else
- usbi_dbg("cancel transfer failed error %d", r);
-
- if (r == LIBUSB_ERROR_NO_DEVICE)
- itransfer->state_flags |= USBI_TRANSFER_DEVICE_DISAPPEARED;
- }
-
- itransfer->state_flags |= USBI_TRANSFER_CANCELLING;
-
-out:
- usbi_mutex_unlock(&itransfer->lock);
- return r;
-}
-
-/** \ingroup libusb_asyncio
- * Set a transfers bulk stream id. Note users are advised to use
- * libusb_fill_bulk_stream_transfer() instead of calling this function
- * directly.
- *
- * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
- *
- * \param transfer the transfer to set the stream id for
- * \param stream_id the stream id to set
- * \see libusb_alloc_streams()
- */
-void API_EXPORTED libusb_transfer_set_stream_id(
- struct libusb_transfer *transfer, uint32_t stream_id)
-{
- struct usbi_transfer *itransfer =
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
-
- itransfer->stream_id = stream_id;
-}
-
-/** \ingroup libusb_asyncio
- * Get a transfers bulk stream id.
- *
- * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
- *
- * \param transfer the transfer to get the stream id for
- * \returns the stream id for the transfer
- */
-uint32_t API_EXPORTED libusb_transfer_get_stream_id(
- struct libusb_transfer *transfer)
-{
- struct usbi_transfer *itransfer =
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
-
- return itransfer->stream_id;
-}
-
-/* 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_device_handle *dev_handle = transfer->dev_handle;
- uint8_t flags;
- int r;
-
- r = remove_from_flying_list(itransfer);
- if (r < 0)
- usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout, errno=%d", errno);
-
- usbi_mutex_lock(&itransfer->lock);
- itransfer->state_flags &= ~USBI_TRANSFER_IN_FLIGHT;
- usbi_mutex_unlock(&itransfer->lock);
-
- 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;
- usbi_dbg("transfer %p has callback %p", transfer, transfer->callback);
- 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);
- libusb_unref_device(dev_handle->dev);
- return r;
-}
-
-/* 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)
-{
- struct libusb_context *ctx = ITRANSFER_CTX(transfer);
- uint8_t timed_out;
-
- usbi_mutex_lock(&ctx->flying_transfers_lock);
- timed_out = transfer->timeout_flags & USBI_TRANSFER_TIMED_OUT;
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
-
- /* if the URB was cancelled due to timeout, report timeout to the user */
- if (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);
-}
-
-/* Add a completed transfer to the completed_transfers list of the
- * context and signal the event. The backend's handle_transfer_completion()
- * function will be called the next time an event handler runs. */
-void usbi_signal_transfer_completion(struct usbi_transfer *transfer)
-{
- struct libusb_context *ctx = ITRANSFER_CTX(transfer);
- int pending_events;
-
- usbi_mutex_lock(&ctx->event_data_lock);
- pending_events = usbi_pending_events(ctx);
- list_add_tail(&transfer->completed_list, &ctx->completed_transfers);
- if (!pending_events)
- usbi_signal_event(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
-}
-
-/** \ingroup libusb_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)
- * \ref libusb_mtasync
- */
-int API_EXPORTED libusb_try_lock_events(libusb_context *ctx)
-{
- int r;
- unsigned int ru;
- USBI_GET_CONTEXT(ctx);
-
- /* is someone else waiting to close a device? if so, don't let this thread
- * start event handling */
- usbi_mutex_lock(&ctx->event_data_lock);
- ru = ctx->device_close;
- usbi_mutex_unlock(&ctx->event_data_lock);
- if (ru) {
- usbi_dbg("someone else is closing a device");
- return 1;
- }
-
- r = usbi_mutex_trylock(&ctx->events_lock);
- if (r)
- return 1;
-
- ctx->event_handler_active = 1;
- return 0;
-}
-
-/** \ingroup libusb_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
- * \ref libusb_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 libusb_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
- * \ref libusb_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->device_close)? */
- usbi_mutex_lock(&ctx->event_waiters_lock);
- usbi_cond_broadcast(&ctx->event_waiters_cond);
- usbi_mutex_unlock(&ctx->event_waiters_lock);
-}
-
-/** \ingroup libusb_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 libusb_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
- * \ref fullstory "Multi-threaded I/O: the full story"
- */
-int API_EXPORTED libusb_event_handling_ok(libusb_context *ctx)
-{
- unsigned int r;
- USBI_GET_CONTEXT(ctx);
-
- /* is someone else waiting to close a device? if so, don't let this thread
- * continue event handling */
- usbi_mutex_lock(&ctx->event_data_lock);
- r = ctx->device_close;
- usbi_mutex_unlock(&ctx->event_data_lock);
- if (r) {
- usbi_dbg("someone else is closing a device");
- return 0;
- }
-
- return 1;
-}
-
-
-/** \ingroup libusb_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
- * \ref libusb_mtasync
- */
-int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
-{
- unsigned int r;
- USBI_GET_CONTEXT(ctx);
-
- /* is someone else waiting to close a device? if so, don't let this thread
- * start event handling -- indicate that event handling is happening */
- usbi_mutex_lock(&ctx->event_data_lock);
- r = ctx->device_close;
- usbi_mutex_unlock(&ctx->event_data_lock);
- if (r) {
- usbi_dbg("someone else is closing a device");
- return 1;
- }
-
- return ctx->event_handler_active;
-}
-
-/** \ingroup libusb_poll
- * Interrupt any active thread that is handling events. This is mainly useful
- * for interrupting a dedicated event handling thread when an application
- * wishes to call libusb_exit().
- *
- * Since version 1.0.21, \ref LIBUSB_API_VERSION >= 0x01000105
- *
- * \param ctx the context to operate on, or NULL for the default context
- * \ref libusb_mtasync
- */
-void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
-{
- int pending_events;
- USBI_GET_CONTEXT(ctx);
-
- usbi_dbg("");
- usbi_mutex_lock(&ctx->event_data_lock);
-
- pending_events = usbi_pending_events(ctx);
- ctx->event_flags |= USBI_EVENT_USER_INTERRUPT;
- if (!pending_events)
- usbi_signal_event(ctx);
-
- usbi_mutex_unlock(&ctx->event_data_lock);
-}
-
-/** \ingroup libusb_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
- * \ref libusb_mtasync
- */
-void API_EXPORTED libusb_lock_event_waiters(libusb_context *ctx)
-{
- USBI_GET_CONTEXT(ctx);
- usbi_mutex_lock(&ctx->event_waiters_lock);
-}
-
-/** \ingroup libusb_poll
- * Release the event waiters lock.
- * \param ctx the context to operate on, or NULL for the default context
- * \ref libusb_mtasync
- */
-void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx)
-{
- USBI_GET_CONTEXT(ctx);
- usbi_mutex_unlock(&ctx->event_waiters_lock);
-}
-
-/** \ingroup libusb_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
- * \ref libusb_mtasync
- */
-int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
-{
- int r;
-
- USBI_GET_CONTEXT(ctx);
- if (tv == NULL) {
- usbi_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock);
- return 0;
- }
-
- r = usbi_cond_timedwait(&ctx->event_waiters_cond,
- &ctx->event_waiters_lock, tv);
-
- if (r < 0)
- return r;
- else
- return (r == ETIMEDOUT);
-}
-
-static void handle_timeout(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer =
- USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- int r;
-
- itransfer->timeout_flags |= USBI_TRANSFER_TIMEOUT_HANDLED;
- r = libusb_cancel_transfer(transfer);
- if (r == LIBUSB_SUCCESS)
- itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
- else
- 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->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | 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;
-
- 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;
- POLL_NFDS_TYPE internal_nfds;
- struct pollfd *fds = NULL;
- int i = -1;
- int timeout_ms;
- int special_event;
-
- /* prevent attempts to recursively handle events (e.g. calling into
- * libusb_handle_events() from within a hotplug or transfer callback) */
- if (usbi_handling_events(ctx))
- return LIBUSB_ERROR_BUSY;
- usbi_start_event_handling(ctx);
-
- /* there are certain fds that libusb uses internally, currently:
- *
- * 1) event pipe
- * 2) timerfd
- *
- * the backend will never need to attempt to handle events on these fds, so
- * we determine how many fds are in use internally for this context and when
- * handle_events() is called in the backend, the pollfd list and count will
- * be adjusted to skip over these internal fds */
- if (usbi_using_timerfd(ctx))
- internal_nfds = 2;
- else
- internal_nfds = 1;
-
- /* only reallocate the poll fds when the list of poll fds has been modified
- * since the last poll, otherwise reuse them to save the additional overhead */
- usbi_mutex_lock(&ctx->event_data_lock);
- if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED) {
- usbi_dbg("poll fds modified, reallocating");
-
- if (ctx->pollfds) {
- free(ctx->pollfds);
- ctx->pollfds = NULL;
- }
-
- /* sanity check - it is invalid for a context to have fewer than the
- * required internal fds (memory corruption?) */
- assert(ctx->pollfds_cnt >= internal_nfds);
-
- ctx->pollfds = calloc(ctx->pollfds_cnt, sizeof(*ctx->pollfds));
- if (!ctx->pollfds) {
- usbi_mutex_unlock(&ctx->event_data_lock);
- r = LIBUSB_ERROR_NO_MEM;
- goto done;
- }
-
- list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd) {
- struct libusb_pollfd *pollfd = &ipollfd->pollfd;
- i++;
- ctx->pollfds[i].fd = pollfd->fd;
- ctx->pollfds[i].events = pollfd->events;
- }
-
- /* reset the flag now that we have the updated list */
- ctx->event_flags &= ~USBI_EVENT_POLLFDS_MODIFIED;
-
- /* if no further pending events, clear the event pipe so that we do
- * not immediately return from poll */
- if (!usbi_pending_events(ctx))
- usbi_clear_event(ctx);
- }
- fds = ctx->pollfds;
- nfds = ctx->pollfds_cnt;
- usbi_mutex_unlock(&ctx->event_data_lock);
-
- timeout_ms = (int)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
-
- /* round up to next millisecond */
- if (tv->tv_usec % 1000)
- timeout_ms++;
-
-redo_poll:
- 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) {
- r = handle_timeouts(ctx);
- goto done;
- }
- else if (r == -1 && errno == EINTR) {
- r = LIBUSB_ERROR_INTERRUPTED;
- goto done;
- }
- else if (r < 0) {
- usbi_err(ctx, "poll failed %d err=%d", r, errno);
- r = LIBUSB_ERROR_IO;
- goto done;
- }
-
- special_event = 0;
-
- /* fds[0] is always the event pipe */
- if (fds[0].revents) {
- libusb_hotplug_message *message = NULL;
- struct usbi_transfer *itransfer;
- int ret = 0;
-
- usbi_dbg("caught a fish on the event pipe");
-
- /* take the the event data lock while processing events */
- usbi_mutex_lock(&ctx->event_data_lock);
-
- /* check if someone added a new poll fd */
- if (ctx->event_flags & USBI_EVENT_POLLFDS_MODIFIED)
- usbi_dbg("someone updated the poll fds");
-
- if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) {
- usbi_dbg("someone purposely interrupted");
- ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
- }
-
- /* check if someone is closing a device */
- if (ctx->device_close)
- usbi_dbg("someone is closing a device");
-
- /* check for any pending hotplug messages */
- if (!list_empty(&ctx->hotplug_msgs)) {
- usbi_dbg("hotplug message received");
- special_event = 1;
- message = list_first_entry(&ctx->hotplug_msgs, libusb_hotplug_message, list);
- list_del(&message->list);
- }
-
- /* complete any pending transfers */
- while (ret == 0 && !list_empty(&ctx->completed_transfers)) {
- itransfer = list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
- list_del(&itransfer->completed_list);
- usbi_mutex_unlock(&ctx->event_data_lock);
- ret = usbi_backend->handle_transfer_completion(itransfer);
- if (ret)
- usbi_err(ctx, "backend handle_transfer_completion failed with error %d", ret);
- usbi_mutex_lock(&ctx->event_data_lock);
- }
-
- /* if no further pending events, clear the event pipe */
- if (!usbi_pending_events(ctx))
- usbi_clear_event(ctx);
-
- usbi_mutex_unlock(&ctx->event_data_lock);
-
- /* process the hotplug message, if any */
- if (message) {
- usbi_hotplug_match(ctx, message->device, message->event);
-
- /* the device left, dereference the device */
- if (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT == message->event)
- libusb_unref_device(message->device);
-
- free(message);
- }
-
- if (ret) {
- /* return error code */
- r = ret;
- goto done;
- }
-
- if (0 == --r)
- goto handled;
- }
-
-#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");
- special_event = 1;
-
- ret = handle_timerfd_trigger(ctx);
- if (ret < 0) {
- /* return error code */
- r = ret;
- goto done;
- }
-
- if (0 == --r)
- goto handled;
- }
-#endif
-
- r = usbi_backend->handle_events(ctx, fds + internal_nfds, nfds - internal_nfds, r);
- if (r)
- usbi_err(ctx, "backend handle_events failed with error %d", r);
-
-handled:
- if (r == 0 && special_event) {
- timeout_ms = 0;
- goto redo_poll;
- }
-
-done:
- usbi_end_event_handling(ctx);
- 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 libusb_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
- * \ref libusb_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 thread 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 libusb_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 libusb_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 libusb_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
- * \ref libusb_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 libusb_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
- * \ref libusb_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 libusb_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 libusb_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.
- * \ref libusb_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
- UNUSED(ctx);
- return 0;
-#endif
-}
-
-/** \ingroup libusb_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 = { 0, 0 };
- int r;
-
- 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->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
- continue;
-
- /* if we've reached transfers of infinte timeout, we're done looking */
- if (!timerisset(&transfer->timeout))
- break;
-
- next_timeout = transfer->timeout;
- break;
- }
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
-
- if (!timerisset(&next_timeout)) {
- usbi_dbg("no URB with timeout or all handled by OS; no timeout!");
- return 0;
- }
-
- 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 0;
- }
- 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 libusb_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;
-}
-
-/*
- * Interrupt the iteration of the event handling thread, so that it picks
- * up the fd change. Callers of this function must hold the event_data_lock.
- */
-static void usbi_fd_notification(struct libusb_context *ctx)
-{
- int pending_events;
-
- /* Record that there is a new poll fd.
- * Only signal an event if there are no prior pending events. */
- pending_events = usbi_pending_events(ctx);
- ctx->event_flags |= USBI_EVENT_POLLFDS_MODIFIED;
- if (!pending_events)
- usbi_signal_event(ctx);
-}
-
-/* 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->event_data_lock);
- list_add_tail(&ipollfd->list, &ctx->ipollfds);
- ctx->pollfds_cnt++;
- usbi_fd_notification(ctx);
- usbi_mutex_unlock(&ctx->event_data_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->event_data_lock);
- list_for_each_entry(ipollfd, &ctx->ipollfds, 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->event_data_lock);
- return;
- }
-
- list_del(&ipollfd->list);
- ctx->pollfds_cnt--;
- usbi_fd_notification(ctx);
- usbi_mutex_unlock(&ctx->event_data_lock);
- free(ipollfd);
- if (ctx->fd_removed_cb)
- ctx->fd_removed_cb(fd, ctx->fd_cb_user_data);
-}
-
-/** \ingroup libusb_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 libusb_free_pollfds()
- * 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;
- USBI_GET_CONTEXT(ctx);
-
- usbi_mutex_lock(&ctx->event_data_lock);
-
- ret = calloc(ctx->pollfds_cnt + 1, sizeof(struct libusb_pollfd *));
- if (!ret)
- goto out;
-
- list_for_each_entry(ipollfd, &ctx->ipollfds, list, struct usbi_pollfd)
- ret[i++] = (struct libusb_pollfd *) ipollfd;
- ret[ctx->pollfds_cnt] = NULL;
-
-out:
- usbi_mutex_unlock(&ctx->event_data_lock);
- return (const struct libusb_pollfd **) ret;
-#else
- usbi_err(ctx, "external polling of libusb's internal descriptors "\
- "is not yet supported on Windows platforms");
- return NULL;
-#endif
-}
-
-/** \ingroup libusb_poll
- * Free a list of libusb_pollfd structures. This should be called for all
- * pollfd lists allocated with libusb_get_pollfds().
- *
- * Since version 1.0.20, \ref LIBUSB_API_VERSION >= 0x01000104
- *
- * It is legal to call this function with a NULL pollfd list. In this case,
- * the function will simply return safely.
- *
- * \param pollfds the list of libusb_pollfd structures to free
- */
-void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds)
-{
- if (!pollfds)
- return;
-
- free((void *)pollfds);
-}
-
-/* Backends may call this from handle_events to report disconnection of a
- * device. This function ensures transfers get cancelled appropriately.
- * Callers of this function must hold the events_lock.
- */
-void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
-{
- struct usbi_transfer *cur;
- struct usbi_transfer *to_cancel;
-
- usbi_dbg("device %d.%d",
- dev_handle->dev->bus_number, dev_handle->dev->device_address);
-
- /* terminate all pending transfers with the LIBUSB_TRANSFER_NO_DEVICE
- * status code.
- *
- * when we find a transfer for this device on the list, there are two
- * possible scenarios:
- * 1. the transfer is currently in-flight, in which case we terminate the
- * transfer here
- * 2. the transfer has been added to the flying transfer list by
- * libusb_submit_transfer, has failed to submit and
- * libusb_submit_transfer is waiting for us to release the
- * flying_transfers_lock to remove it, so we ignore it
- */
-
- while (1) {
- to_cancel = NULL;
- usbi_mutex_lock(&HANDLE_CTX(dev_handle)->flying_transfers_lock);
- list_for_each_entry(cur, &HANDLE_CTX(dev_handle)->flying_transfers, list, struct usbi_transfer)
- if (USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == dev_handle) {
- usbi_mutex_lock(&cur->lock);
- if (cur->state_flags & USBI_TRANSFER_IN_FLIGHT)
- to_cancel = cur;
- usbi_mutex_unlock(&cur->lock);
-
- if (to_cancel)
- break;
- }
- usbi_mutex_unlock(&HANDLE_CTX(dev_handle)->flying_transfers_lock);
-
- if (!to_cancel)
- break;
-
- usbi_dbg("cancelling transfer %p from disconnect",
- USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel));
-
- usbi_mutex_lock(&to_cancel->lock);
- usbi_backend->clear_transfer_priv(to_cancel);
- usbi_mutex_unlock(&to_cancel->lock);
- usbi_handle_transfer_completion(to_cancel, LIBUSB_TRANSFER_NO_DEVICE);
- }
-
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h b/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h
deleted file mode 100644
index c562690..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/libusb.h
+++ /dev/null
@@ -1,2008 +0,0 @@
-/*
- * Public libusb header file
- * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
- * Copyright © 2007-2008 Daniel Drake <dsd@gentoo.org>
- * Copyright © 2012 Pete Batard <pete@akeo.ie>
- * Copyright © 2012 Nathan Hjelm <hjelmn@cs.unm.edu>
- * For more information, please visit: http://libusb.info
- *
- * 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 */
-#if !defined(__cplusplus)
-#define inline __inline
-#endif
-/* 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 not available on older MSVC */
-#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
-
-#if !defined(_WIN32_WCE)
-#include <sys/types.h>
-#endif
-
-#if defined(__linux) || defined(__APPLE__) || defined(__CYGWIN__) || defined(__HAIKU__)
-#include <sys/time.h>
-#endif
-
-#include <time.h>
-#include <limits.h>
-
-/* '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__) || defined(_WIN32_WCE)
-#include <windows.h>
-#if defined(interface)
-#undef interface
-#endif
-#if !defined(__CYGWIN__)
-#include <winsock.h>
-#endif
-#endif
-
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
-#define LIBUSB_DEPRECATED_FOR(f) \
- __attribute__((deprecated("Use " #f " instead")))
-#else
-#define LIBUSB_DEPRECATED_FOR(f)
-#endif /* __GNUC__ */
-
-/** \def LIBUSB_CALL
- * \ingroup libusb_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 functions 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__) || defined(_WIN32_WCE)
-#define LIBUSB_CALL WINAPI
-#else
-#define LIBUSB_CALL
-#endif
-
-/** \def LIBUSB_API_VERSION
- * \ingroup libusb_misc
- * libusb's API version.
- *
- * Since version 1.0.13, to help with feature detection, libusb defines
- * a LIBUSB_API_VERSION macro that gets increased every time there is a
- * significant change to the API, such as the introduction of a new call,
- * the definition of a new macro/enum member, or any other element that
- * libusb applications may want to detect at compilation time.
- *
- * The macro is typically used in an application as follows:
- * \code
- * #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01001234)
- * // Use one of the newer features from the libusb API
- * #endif
- * \endcode
- *
- * Internally, LIBUSB_API_VERSION is defined as follows:
- * (libusb major << 24) | (libusb minor << 16) | (16 bit incremental)
- */
-#define LIBUSB_API_VERSION 0x01000105
-
-/* The following is kept for compatibility, but will be deprecated in the future */
-#define LIBUSBX_API_VERSION LIBUSB_API_VERSION
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \ingroup libusb_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] = (uint8_t) (x >> 8);
- _tmp.b8[0] = (uint8_t) (x & 0xff);
- return _tmp.b16;
-}
-
-/** \def libusb_le16_to_cpu
- * \ingroup libusb_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 libusb_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 libusb_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,
-
- /** BOS descriptor */
- LIBUSB_DT_BOS = 0x0f,
-
- /** Device Capability descriptor */
- LIBUSB_DT_DEVICE_CAPABILITY = 0x10,
-
- /** 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,
-
- /** SuperSpeed Hub descriptor */
- LIBUSB_DT_SUPERSPEED_HUB = 0x2a,
-
- /** SuperSpeed Endpoint Companion descriptor */
- LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30
-};
-
-/* 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_DT_SS_ENDPOINT_COMPANION_SIZE 6
-#define LIBUSB_DT_BOS_SIZE 5
-#define LIBUSB_DT_DEVICE_CAPABILITY_SIZE 3
-
-/* BOS descriptor sizes */
-#define LIBUSB_BT_USB_2_0_EXTENSION_SIZE 7
-#define LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE 10
-#define LIBUSB_BT_CONTAINER_ID_SIZE 20
-
-/* We unwrap the BOS => define its max size */
-#define LIBUSB_DT_BOS_MAX_SIZE ((LIBUSB_DT_BOS_SIZE) +\
- (LIBUSB_BT_USB_2_0_EXTENSION_SIZE) +\
- (LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) +\
- (LIBUSB_BT_CONTAINER_ID_SIZE))
-
-#define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */
-#define LIBUSB_ENDPOINT_DIR_MASK 0x80
-
-/** \ingroup libusb_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 libusb_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,
-
- /** Stream endpoint */
- LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
-};
-
-/** \ingroup libusb_misc
- * Standard requests, as defined in table 9-5 of the USB 3.0 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,
-
- /** Sets both the U1 and U2 Exit Latency */
- LIBUSB_REQUEST_SET_SEL = 0x30,
-
- /** Delay from the time a host transmits a packet to the time it is
- * received by the device. */
- LIBUSB_SET_ISOCH_DELAY = 0x31,
-};
-
-/** \ingroup libusb_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 libusb_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 libusb_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 libusb_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 libusb_desc
- * A structure representing the standard USB device descriptor. This
- * descriptor is documented in section 9.6.1 of the USB 3.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 libusb_desc
- * A structure representing the standard USB endpoint descriptor. This
- * descriptor is documented in section 9.6.6 of the USB 3.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 libusb_desc
- * A structure representing the standard USB interface descriptor. This
- * descriptor is documented in section 9.6.5 of the USB 3.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 libusb_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 libusb_desc
- * A structure representing the standard USB configuration descriptor. This
- * descriptor is documented in section 9.6.3 of the USB 3.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 operation. Expressed in units
- * of 2 mA when the device is operating in high-speed mode and in units
- * of 8 mA when the device is operating in super-speed mode. */
- 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 libusb_desc
- * A structure representing the superspeed endpoint companion
- * descriptor. This descriptor is documented in section 9.6.7 of
- * the USB 3.0 specification. All multiple-byte fields are represented in
- * host-endian format.
- */
-struct libusb_ss_endpoint_companion_descriptor {
-
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_SS_ENDPOINT_COMPANION in
- * this context. */
- uint8_t bDescriptorType;
-
-
- /** The maximum number of packets the endpoint can send or
- * receive as part of a burst. */
- uint8_t bMaxBurst;
-
- /** In bulk EP: bits 4:0 represents the maximum number of
- * streams the EP supports. In isochronous EP: bits 1:0
- * represents the Mult - a zero based value that determines
- * the maximum number of packets within a service interval */
- uint8_t bmAttributes;
-
- /** The total number of bytes this EP will transfer every
- * service interval. valid only for periodic EPs. */
- uint16_t wBytesPerInterval;
-};
-
-/** \ingroup libusb_desc
- * A generic representation of a BOS Device Capability descriptor. It is
- * advised to check bDevCapabilityType and call the matching
- * libusb_get_*_descriptor function to get a structure fully matching the type.
- */
-struct libusb_bos_dev_capability_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
- /** Device Capability type */
- uint8_t bDevCapabilityType;
- /** Device Capability data (bLength - 3 bytes) */
- uint8_t dev_capability_data
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
-};
-
-/** \ingroup libusb_desc
- * A structure representing the Binary Device Object Store (BOS) descriptor.
- * This descriptor is documented in section 9.6.2 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_bos_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_BOS LIBUSB_DT_BOS
- * in this context. */
- uint8_t bDescriptorType;
-
- /** Length of this descriptor and all of its sub descriptors */
- uint16_t wTotalLength;
-
- /** The number of separate device capability descriptors in
- * the BOS */
- uint8_t bNumDeviceCaps;
-
- /** bNumDeviceCap Device Capability Descriptors */
- struct libusb_bos_dev_capability_descriptor *dev_capability
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
-};
-
-/** \ingroup libusb_desc
- * A structure representing the USB 2.0 Extension descriptor
- * This descriptor is documented in section 9.6.2.1 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_usb_2_0_extension_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
-
- /** Capability type. Will have value
- * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION
- * LIBUSB_BT_USB_2_0_EXTENSION in this context. */
- uint8_t bDevCapabilityType;
-
- /** Bitmap encoding of supported device level features.
- * A value of one in a bit location indicates a feature is
- * supported; a value of zero indicates it is not supported.
- * See \ref libusb_usb_2_0_extension_attributes. */
- uint32_t bmAttributes;
-};
-
-/** \ingroup libusb_desc
- * A structure representing the SuperSpeed USB Device Capability descriptor
- * This descriptor is documented in section 9.6.2.2 of the USB 3.0 specification.
- * All multiple-byte fields are represented in host-endian format.
- */
-struct libusb_ss_usb_device_capability_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
-
- /** Capability type. Will have value
- * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
- * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY in this context. */
- uint8_t bDevCapabilityType;
-
- /** Bitmap encoding of supported device level features.
- * A value of one in a bit location indicates a feature is
- * supported; a value of zero indicates it is not supported.
- * See \ref libusb_ss_usb_device_capability_attributes. */
- uint8_t bmAttributes;
-
- /** Bitmap encoding of the speed supported by this device when
- * operating in SuperSpeed mode. See \ref libusb_supported_speed. */
- uint16_t wSpeedSupported;
-
- /** The lowest speed at which all the functionality supported
- * by the device is available to the user. For example if the
- * device supports all its functionality when connected at
- * full speed and above then it sets this value to 1. */
- uint8_t bFunctionalitySupport;
-
- /** U1 Device Exit Latency. */
- uint8_t bU1DevExitLat;
-
- /** U2 Device Exit Latency. */
- uint16_t bU2DevExitLat;
-};
-
-/** \ingroup libusb_desc
- * A structure representing the Container ID descriptor.
- * This descriptor is documented in section 9.6.2.3 of the USB 3.0 specification.
- * All multiple-byte fields, except UUIDs, are represented in host-endian format.
- */
-struct libusb_container_id_descriptor {
- /** Size of this descriptor (in bytes) */
- uint8_t bLength;
-
- /** Descriptor type. Will have value
- * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE_CAPABILITY
- * LIBUSB_DT_DEVICE_CAPABILITY in this context. */
- uint8_t bDescriptorType;
-
- /** Capability type. Will have value
- * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID
- * LIBUSB_BT_CONTAINER_ID in this context. */
- uint8_t bDevCapabilityType;
-
- /** Reserved field */
- uint8_t bReserved;
-
- /** 128 bit UUID */
- uint8_t ContainerID[16];
-};
-
-/** \ingroup libusb_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 libusb_lib
- * Structure providing the version of the libusb runtime
- */
-struct libusb_version {
- /** Library major version. */
- const uint16_t major;
-
- /** Library minor version. */
- const uint16_t minor;
-
- /** Library micro version. */
- const uint16_t micro;
-
- /** Library nano version. */
- const uint16_t nano;
-
- /** Library release candidate suffix string, e.g. "-rc4". */
- const char *rc;
-
- /** For ABI compatibility only. */
- const char* describe;
-};
-
-/** \ingroup libusb_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 libusb_contexts.
- */
-typedef struct libusb_context libusb_context;
-
-/** \ingroup libusb_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_ref_device() and
- * libusb_unref_device(), 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 libusb_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 libusb_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 libusb_dev
- * Supported speeds (wSpeedSupported) bitfield. Indicates what
- * speeds the device supports.
- */
-enum libusb_supported_speed {
- /** Low speed operation supported (1.5MBit/s). */
- LIBUSB_LOW_SPEED_OPERATION = 1,
-
- /** Full speed operation supported (12MBit/s). */
- LIBUSB_FULL_SPEED_OPERATION = 2,
-
- /** High speed operation supported (480MBit/s). */
- LIBUSB_HIGH_SPEED_OPERATION = 4,
-
- /** Superspeed operation supported (5000MBit/s). */
- LIBUSB_SUPER_SPEED_OPERATION = 8,
-};
-
-/** \ingroup libusb_dev
- * Masks for the bits of the
- * \ref libusb_usb_2_0_extension_descriptor::bmAttributes "bmAttributes" field
- * of the USB 2.0 Extension descriptor.
- */
-enum libusb_usb_2_0_extension_attributes {
- /** Supports Link Power Management (LPM) */
- LIBUSB_BM_LPM_SUPPORT = 2,
-};
-
-/** \ingroup libusb_dev
- * Masks for the bits of the
- * \ref libusb_ss_usb_device_capability_descriptor::bmAttributes "bmAttributes" field
- * field of the SuperSpeed USB Device Capability descriptor.
- */
-enum libusb_ss_usb_device_capability_attributes {
- /** Supports Latency Tolerance Messages (LTM) */
- LIBUSB_BM_LTM_SUPPORT = 2,
-};
-
-/** \ingroup libusb_dev
- * USB capability types
- */
-enum libusb_bos_type {
- /** Wireless USB device capability */
- LIBUSB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1,
-
- /** USB 2.0 extensions */
- LIBUSB_BT_USB_2_0_EXTENSION = 2,
-
- /** SuperSpeed USB device capability */
- LIBUSB_BT_SS_USB_DEVICE_CAPABILITY = 3,
-
- /** Container ID type */
- LIBUSB_BT_CONTAINER_ID = 4,
-};
-
-/** \ingroup libusb_misc
- * Error codes. Most libusb functions return 0 on success or one of these
- * codes on failure.
- * You can call libusb_error_name() to retrieve a string representation of an
- * error code or libusb_strerror() to get an end-user suitable description 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_COUNT below as well as the
- message strings in strerror.c when adding new error codes here. */
-
- /** Other error */
- LIBUSB_ERROR_OTHER = -99,
-};
-
-/* Total number of error codes in enum libusb_error */
-#define LIBUSB_ERROR_COUNT 14
-
-/** \ingroup libusb_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,
-
- /* NB! Remember to update libusb_error_name()
- when adding new status codes here. */
-};
-
-/** \ingroup libusb_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().
- * Note that buffers allocated with libusb_dev_mem_alloc() should not
- * be attempted freed in this way, since free() is not an appropriate
- * way to release such memory. */
- 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,
-
- /** Terminate transfers that are a multiple of the endpoint's
- * wMaxPacketSize with an extra zero length packet. This is useful
- * when a device protocol mandates that each logical request is
- * terminated by an incomplete packet (i.e. the logical requests are
- * not separated by other means).
- *
- * This flag only affects host-to-device transfers to bulk and interrupt
- * endpoints. In other situations, it is ignored.
- *
- * This flag only affects transfers with a length that is a multiple of
- * the endpoint's wMaxPacketSize. On transfers of other lengths, this
- * flag has no effect. Therefore, if you are working with a device that
- * needs a ZLP whenever the end of the logical request falls on a packet
- * boundary, then it is sensible to set this flag on <em>every</em>
- * transfer (you do not have to worry about only setting it on transfers
- * that end on the boundary).
- *
- * This flag is currently only supported on Linux.
- * On other systems, libusb_submit_transfer() will return
- * LIBUSB_ERROR_NOT_SUPPORTED for every transfer where this flag is set.
- *
- * Available since libusb-1.0.9.
- */
- LIBUSB_TRANSFER_ADD_ZERO_PACKET = 1 << 3,
-};
-
-/** \ingroup libusb_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 libusb_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 libusb_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 libusb_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 milliseconds. 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 libusb_misc
- * Capabilities supported by an instance of libusb on the current running
- * platform. Test if the loaded library supports a given capability by calling
- * \ref libusb_has_capability().
- */
-enum libusb_capability {
- /** The libusb_has_capability() API is available. */
- LIBUSB_CAP_HAS_CAPABILITY = 0x0000,
- /** Hotplug support is available on this platform. */
- LIBUSB_CAP_HAS_HOTPLUG = 0x0001,
- /** The library can access HID devices without requiring user intervention.
- * Note that before being able to actually access an HID device, you may
- * still have to call additional libusb functions such as
- * \ref libusb_detach_kernel_driver(). */
- LIBUSB_CAP_HAS_HID_ACCESS = 0x0100,
- /** The library supports detaching of the default USB driver, using
- * \ref libusb_detach_kernel_driver(), if one is set by the OS kernel */
- LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER = 0x0101
-};
-
-/** \ingroup libusb_lib
- * Log message levels.
- * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library (default)
- * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to stdout, warning
- * and error messages are printed to stderr
- * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are printed to stdout,
- * warnings and errors to stderr
- */
-enum libusb_log_level {
- LIBUSB_LOG_LEVEL_NONE = 0,
- LIBUSB_LOG_LEVEL_ERROR,
- LIBUSB_LOG_LEVEL_WARNING,
- LIBUSB_LOG_LEVEL_INFO,
- LIBUSB_LOG_LEVEL_DEBUG,
-};
-
-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);
-const struct libusb_version * LIBUSB_CALL libusb_get_version(void);
-int LIBUSB_CALL libusb_has_capability(uint32_t capability);
-const char * LIBUSB_CALL libusb_error_name(int errcode);
-int LIBUSB_CALL libusb_setlocale(const char *locale);
-const char * LIBUSB_CALL libusb_strerror(enum libusb_error 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);
-int LIBUSB_CALL libusb_get_ss_endpoint_companion_descriptor(
- struct libusb_context *ctx,
- const struct libusb_endpoint_descriptor *endpoint,
- struct libusb_ss_endpoint_companion_descriptor **ep_comp);
-void LIBUSB_CALL libusb_free_ss_endpoint_companion_descriptor(
- struct libusb_ss_endpoint_companion_descriptor *ep_comp);
-int LIBUSB_CALL libusb_get_bos_descriptor(libusb_device_handle *dev_handle,
- struct libusb_bos_descriptor **bos);
-void LIBUSB_CALL libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos);
-int LIBUSB_CALL libusb_get_usb_2_0_extension_descriptor(
- struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension);
-void LIBUSB_CALL libusb_free_usb_2_0_extension_descriptor(
- struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension);
-int LIBUSB_CALL libusb_get_ss_usb_device_capability_descriptor(
- struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap);
-void LIBUSB_CALL libusb_free_ss_usb_device_capability_descriptor(
- struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap);
-int LIBUSB_CALL libusb_get_container_id_descriptor(struct libusb_context *ctx,
- struct libusb_bos_dev_capability_descriptor *dev_cap,
- struct libusb_container_id_descriptor **container_id);
-void LIBUSB_CALL libusb_free_container_id_descriptor(
- struct libusb_container_id_descriptor *container_id);
-uint8_t LIBUSB_CALL libusb_get_bus_number(libusb_device *dev);
-uint8_t LIBUSB_CALL libusb_get_port_number(libusb_device *dev);
-int LIBUSB_CALL libusb_get_port_numbers(libusb_device *dev, uint8_t* port_numbers, int port_numbers_len);
-LIBUSB_DEPRECATED_FOR(libusb_get_port_numbers)
-int LIBUSB_CALL libusb_get_port_path(libusb_context *ctx, libusb_device *dev, uint8_t* path, uint8_t path_length);
-libusb_device * LIBUSB_CALL libusb_get_parent(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 **dev_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_handle,
- int configuration);
-int LIBUSB_CALL libusb_claim_interface(libusb_device_handle *dev_handle,
- int interface_number);
-int LIBUSB_CALL libusb_release_interface(libusb_device_handle *dev_handle,
- 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_handle,
- int interface_number, int alternate_setting);
-int LIBUSB_CALL libusb_clear_halt(libusb_device_handle *dev_handle,
- unsigned char endpoint);
-int LIBUSB_CALL libusb_reset_device(libusb_device_handle *dev_handle);
-
-int LIBUSB_CALL libusb_alloc_streams(libusb_device_handle *dev_handle,
- uint32_t num_streams, unsigned char *endpoints, int num_endpoints);
-int LIBUSB_CALL libusb_free_streams(libusb_device_handle *dev_handle,
- unsigned char *endpoints, int num_endpoints);
-
-unsigned char * LIBUSB_CALL libusb_dev_mem_alloc(libusb_device_handle *dev_handle,
- size_t length);
-int LIBUSB_CALL libusb_dev_mem_free(libusb_device_handle *dev_handle,
- unsigned char *buffer, size_t length);
-
-int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle *dev_handle,
- int interface_number);
-int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle *dev_handle,
- int interface_number);
-int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle *dev_handle,
- int interface_number);
-int LIBUSB_CALL libusb_set_auto_detach_kernel_driver(
- libusb_device_handle *dev_handle, int enable);
-
-/* async I/O */
-
-/** \ingroup libusb_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 libusb_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 *)(void *) transfer->buffer;
-}
-
-/** \ingroup libusb_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
- * This pointer must be aligned to at least 2 bytes boundary.
- * \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 *)(void *) 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);
-void LIBUSB_CALL libusb_transfer_set_stream_id(
- struct libusb_transfer *transfer, uint32_t stream_id);
-uint32_t LIBUSB_CALL libusb_transfer_get_stream_id(
- struct libusb_transfer *transfer);
-
-/** \ingroup libusb_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.
- * This pointer must be aligned to at least 2 bytes boundary.
- * \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 *)(void *) 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 = (int) (LIBUSB_CONTROL_SETUP_SIZE
- + libusb_le16_to_cpu(setup->wLength));
- transfer->user_data = user_data;
- transfer->callback = callback;
-}
-
-/** \ingroup libusb_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 libusb_asyncio
- * Helper function to populate the required \ref libusb_transfer fields
- * for a bulk transfer using bulk streams.
- *
- * Since version 1.0.19, \ref LIBUSB_API_VERSION >= 0x01000103
- *
- * \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 stream_id bulk stream id for this transfer
- * \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_stream_transfer(
- struct libusb_transfer *transfer, libusb_device_handle *dev_handle,
- unsigned char endpoint, uint32_t stream_id,
- unsigned char *buffer, int length, libusb_transfer_cb_fn callback,
- void *user_data, unsigned int timeout)
-{
- libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer,
- length, callback, user_data, timeout);
- transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
- libusb_transfer_set_stream_id(transfer, stream_id);
-}
-
-/** \ingroup libusb_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 libusb_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 libusb_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 libusb_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 = (int) 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 libusb_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 = (int) packet;
-
- if (_packet >= transfer->num_iso_packets)
- return NULL;
-
- return transfer->buffer + ((int) 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 libusb_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_handle 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_handle,
- uint8_t desc_type, uint8_t desc_index, unsigned char *data, int length)
-{
- return libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN,
- LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t) ((desc_type << 8) | desc_index),
- 0, data, (uint16_t) length, 1000);
-}
-
-/** \ingroup libusb_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_handle 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_handle,
- uint8_t desc_index, uint16_t langid, unsigned char *data, int length)
-{
- return libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_IN,
- LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | desc_index),
- langid, data, (uint16_t) length, 1000);
-}
-
-int LIBUSB_CALL libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle,
- 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_interrupt_event_handler(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 libusb_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 libusb_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 libusb_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_free_pollfds(const struct libusb_pollfd **pollfds);
-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);
-
-/** \ingroup libusb_hotplug
- * Callback handle.
- *
- * Callbacks handles are generated by libusb_hotplug_register_callback()
- * and can be used to deregister callbacks. Callback handles are unique
- * per libusb_context and it is safe to call libusb_hotplug_deregister_callback()
- * on an already deregisted callback.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * For more information, see \ref libusb_hotplug.
- */
-typedef int libusb_hotplug_callback_handle;
-
-/** \ingroup libusb_hotplug
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * Flags for hotplug events */
-typedef enum {
- /** Default value when not using any flags. */
- LIBUSB_HOTPLUG_NO_FLAGS = 0,
-
- /** Arm the callback and fire it for all matching currently attached devices. */
- LIBUSB_HOTPLUG_ENUMERATE = 1<<0,
-} libusb_hotplug_flag;
-
-/** \ingroup libusb_hotplug
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * Hotplug events */
-typedef enum {
- /** A device has been plugged in and is ready to use */
- LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED = 0x01,
-
- /** A device has left and is no longer available.
- * It is the user's responsibility to call libusb_close on any handle associated with a disconnected device.
- * It is safe to call libusb_get_device_descriptor on a device that has left */
- LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT = 0x02,
-} libusb_hotplug_event;
-
-/** \ingroup libusb_hotplug
- * Wildcard matching for hotplug events */
-#define LIBUSB_HOTPLUG_MATCH_ANY -1
-
-/** \ingroup libusb_hotplug
- * Hotplug callback function type. When requesting hotplug event notifications,
- * you pass a pointer to a callback function of this type.
- *
- * This callback may be called by an internal event thread and as such it is
- * recommended the callback do minimal processing before returning.
- *
- * libusb will call this function later, when a matching event had happened on
- * a matching device. See \ref libusb_hotplug for more information.
- *
- * It is safe to call either libusb_hotplug_register_callback() or
- * libusb_hotplug_deregister_callback() from within a callback function.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * \param ctx context of this notification
- * \param device libusb_device this event occurred on
- * \param event event that occurred
- * \param user_data user data provided when this callback was registered
- * \returns bool whether this callback is finished processing events.
- * returning 1 will cause this callback to be deregistered
- */
-typedef int (LIBUSB_CALL *libusb_hotplug_callback_fn)(libusb_context *ctx,
- libusb_device *device,
- libusb_hotplug_event event,
- void *user_data);
-
-/** \ingroup libusb_hotplug
- * Register a hotplug callback function
- *
- * Register a callback with the libusb_context. The callback will fire
- * when a matching event occurs on a matching device. The callback is
- * armed until either it is deregistered with libusb_hotplug_deregister_callback()
- * or the supplied callback returns 1 to indicate it is finished processing events.
- *
- * If the \ref LIBUSB_HOTPLUG_ENUMERATE is passed the callback will be
- * called with a \ref LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED for all devices
- * already plugged into the machine. Note that libusb modifies its internal
- * device list from a separate thread, while calling hotplug callbacks from
- * libusb_handle_events(), so it is possible for a device to already be present
- * on, or removed from, its internal device list, while the hotplug callbacks
- * still need to be dispatched. This means that when using \ref
- * LIBUSB_HOTPLUG_ENUMERATE, your callback may be called twice for the arrival
- * of the same device, once from libusb_hotplug_register_callback() and once
- * from libusb_handle_events(); and/or your callback may be called for the
- * removal of a device for which an arrived call was never made.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * \param[in] ctx context to register this callback with
- * \param[in] events bitwise or of events that will trigger this callback. See \ref
- * libusb_hotplug_event
- * \param[in] flags hotplug callback flags. See \ref libusb_hotplug_flag
- * \param[in] vendor_id the vendor id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
- * \param[in] product_id the product id to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
- * \param[in] dev_class the device class to match or \ref LIBUSB_HOTPLUG_MATCH_ANY
- * \param[in] cb_fn the function to be invoked on a matching event/device
- * \param[in] user_data user data to pass to the callback function
- * \param[out] callback_handle pointer to store the handle of the allocated callback (can be NULL)
- * \returns LIBUSB_SUCCESS on success LIBUSB_ERROR code on failure
- */
-int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context *ctx,
- libusb_hotplug_event events,
- libusb_hotplug_flag flags,
- int vendor_id, int product_id,
- int dev_class,
- libusb_hotplug_callback_fn cb_fn,
- void *user_data,
- libusb_hotplug_callback_handle *callback_handle);
-
-/** \ingroup libusb_hotplug
- * Deregisters a hotplug callback.
- *
- * Deregister a callback from a libusb_context. This function is safe to call from within
- * a hotplug callback.
- *
- * Since version 1.0.16, \ref LIBUSB_API_VERSION >= 0x01000102
- *
- * \param[in] ctx context this callback is registered with
- * \param[in] callback_handle the handle of the callback to deregister
- */
-void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context *ctx,
- libusb_hotplug_callback_handle callback_handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h b/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h
deleted file mode 100644
index 752e398..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/libusbi.h
+++ /dev/null
@@ -1,1149 +0,0 @@
-/*
- * Internal header for libusb
- * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright © 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 <stdlib.h>
-
-#include <stddef.h>
-#include <stdint.h>
-#include <time.h>
-#include <stdarg.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
-#ifdef HAVE_MISSING_H
-#include <missing.h>
-#endif
-
-#include "libusb.h"
-#include "version.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
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DEVICE_DESC_LENGTH 18
-
-#define USB_MAXENDPOINTS 32
-#define USB_MAXINTERFACES 32
-#define USB_MAXCONFIG 8
-
-/* Backend specific capabilities */
-#define USBI_CAP_HAS_HID_ACCESS 0x00010000
-#define USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER 0x00020000
-
-/* Maximum number of bytes in a log line */
-#define USBI_MAX_LOG_LEN 1024
-/* Terminator for log lines */
-#define USBI_LOG_LINE_END "\n"
-
-/* The following is used to silence warnings for unused variables */
-#define UNUSED(var) do { (void)(var); } while(0)
-
-#if !defined(ARRAYSIZE)
-#define ARRAYSIZE(array) (sizeof(array) / sizeof(array[0]))
-#endif
-
-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)offsetof(type, member)))
-
-#define list_first_entry(ptr, type, member) \
- list_entry((ptr)->next, type, 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;
- entry->next = entry->prev = NULL;
-}
-
-static inline void *usbi_reallocf(void *ptr, size_t size)
-{
- void *ret = realloc(ptr, size);
- if (!ret)
- free(ptr);
- return ret;
-}
-
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *mptr = (ptr); \
- (type *)( (char *)mptr - offsetof(type,member) );})
-
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
-#ifndef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#endif
-
-#define TIMESPEC_IS_SET(ts) ((ts)->tv_sec != 0 || (ts)->tv_nsec != 0)
-
-#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
-#define TIMEVAL_TV_SEC_TYPE long
-#else
-#define TIMEVAL_TV_SEC_TYPE time_t
-#endif
-
-/* Some platforms don't have this define */
-#ifndef TIMESPEC_TO_TIMEVAL
-#define TIMESPEC_TO_TIMEVAL(tv, ts) \
- do { \
- (tv)->tv_sec = (TIMEVAL_TV_SEC_TYPE) (ts)->tv_sec; \
- (tv)->tv_usec = (ts)->tv_nsec / 1000; \
- } while (0)
-#endif
-
-void usbi_log(struct libusb_context *ctx, enum libusb_log_level level,
- const char *function, const char *format, ...);
-
-void usbi_log_v(struct libusb_context *ctx, enum libusb_log_level level,
- const char *function, const char *format, va_list args);
-
-#if !defined(_MSC_VER) || _MSC_VER >= 1400
-
-#ifdef ENABLE_LOGGING
-#define _usbi_log(ctx, level, ...) usbi_log(ctx, level, __FUNCTION__, __VA_ARGS__)
-#define usbi_dbg(...) _usbi_log(NULL, LIBUSB_LOG_LEVEL_DEBUG, __VA_ARGS__)
-#else
-#define _usbi_log(ctx, level, ...) do { (void)(ctx); } while(0)
-#define usbi_dbg(...) do {} while(0)
-#endif
-
-#define usbi_info(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_INFO, __VA_ARGS__)
-#define usbi_warn(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_WARNING, __VA_ARGS__)
-#define usbi_err(ctx, ...) _usbi_log(ctx, LIBUSB_LOG_LEVEL_ERROR, __VA_ARGS__)
-
-#else /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
-
-#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) \
-{ \
- (void)(ctxt); \
-}
-#endif
-
-static inline void usbi_info(struct libusb_context *ctx, const char *format, ...)
- LOG_BODY(ctx, LIBUSB_LOG_LEVEL_INFO)
-static inline void usbi_warn(struct libusb_context *ctx, const char *format, ...)
- LOG_BODY(ctx, LIBUSB_LOG_LEVEL_WARNING)
-static inline void usbi_err(struct libusb_context *ctx, const char *format, ...)
- LOG_BODY(ctx, LIBUSB_LOG_LEVEL_ERROR)
-
-static inline void usbi_dbg(const char *format, ...)
- LOG_BODY(NULL, LIBUSB_LOG_LEVEL_DEBUG)
-
-#endif /* !defined(_MSC_VER) || _MSC_VER >= 1400 */
-
-#define USBI_GET_CONTEXT(ctx) \
- do { \
- if (!(ctx)) \
- (ctx) = usbi_default_context; \
- } while(0)
-
-#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)))
-
-#define IS_EPIN(ep) (0 != ((ep) & LIBUSB_ENDPOINT_IN))
-#define IS_EPOUT(ep) (!IS_EPIN(ep))
-#define IS_XFERIN(xfer) (0 != ((xfer)->endpoint & LIBUSB_ENDPOINT_IN))
-#define IS_XFEROUT(xfer) (!IS_XFERIN(xfer))
-
-/* Internal abstraction for thread synchronization */
-#if defined(THREADS_POSIX)
-#include "os/threads_posix.h"
-#elif defined(OS_WINDOWS) || defined(OS_WINCE)
-#include "os/threads_windows.h"
-#endif
-
-extern struct libusb_context *usbi_default_context;
-
-/* Forward declaration for use in context (fully defined inside poll abstraction) */
-struct pollfd;
-
-struct libusb_context {
- int debug;
- int debug_fixed;
-
- /* internal event pipe, used for signalling occurrence of an internal event. */
- int event_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;
-
- /* A list of registered hotplug callbacks */
- struct list_head hotplug_cbs;
- usbi_mutex_t hotplug_cbs_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;
- /* Note paths taking both this and usbi_transfer->lock must always
- * take this lock first */
- usbi_mutex_t flying_transfers_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;
-
- /* A thread-local storage key to track which thread is performing event
- * handling */
- usbi_tls_key_t event_handling_key;
-
- /* 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;
-
- /* A lock to protect internal context event data. */
- usbi_mutex_t event_data_lock;
-
- /* A bitmask of flags that are set to indicate specific events that need to
- * be handled. Protected by event_data_lock. */
- unsigned int event_flags;
-
- /* A counter that is set when we want to interrupt and prevent event handling,
- * in order to safely close a device. Protected by event_data_lock. */
- unsigned int device_close;
-
- /* list and count of poll fds and an array of poll fd structures that is
- * (re)allocated as necessary prior to polling. Protected by event_data_lock. */
- struct list_head ipollfds;
- struct pollfd *pollfds;
- POLL_NFDS_TYPE pollfds_cnt;
-
- /* A list of pending hotplug messages. Protected by event_data_lock. */
- struct list_head hotplug_msgs;
-
- /* A list of pending completed transfers. Protected by event_data_lock. */
- struct list_head completed_transfers;
-
-#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
-
- struct list_head list;
-};
-
-enum usbi_event_flags {
- /* The list of pollfds has been modified */
- USBI_EVENT_POLLFDS_MODIFIED = 1 << 0,
-
- /* The user has interrupted the event handler */
- USBI_EVENT_USER_INTERRUPT = 1 << 1,
-};
-
-/* Macros for managing event handling state */
-#define usbi_handling_events(ctx) \
- (usbi_tls_key_get((ctx)->event_handling_key) != NULL)
-
-#define usbi_start_event_handling(ctx) \
- usbi_tls_key_set((ctx)->event_handling_key, ctx)
-
-#define usbi_end_event_handling(ctx) \
- usbi_tls_key_set((ctx)->event_handling_key, NULL)
-
-/* Update the following macro if new event sources are added */
-#define usbi_pending_events(ctx) \
- ((ctx)->event_flags || (ctx)->device_close \
- || !list_empty(&(ctx)->hotplug_msgs) || !list_empty(&(ctx)->completed_transfers))
-
-#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 port_number;
- struct libusb_device* parent_dev;
- uint8_t device_address;
- uint8_t num_configurations;
- enum libusb_speed speed;
-
- struct list_head list;
- unsigned long session_data;
-
- struct libusb_device_descriptor device_descriptor;
- int attached;
-
- unsigned char os_priv
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
-#if defined(OS_SUNOS)
- __attribute__ ((aligned (8)));
-#else
- ;
-#endif
-};
-
-struct libusb_device_handle {
- /* lock protects claimed_interfaces */
- usbi_mutex_t lock;
- unsigned long claimed_interfaces;
-
- struct list_head list;
- struct libusb_device *dev;
- int auto_detach_kernel_driver;
- unsigned char os_priv
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
-#if defined(OS_SUNOS)
- __attribute__ ((aligned (8)));
-#else
- ;
-#endif
-};
-
-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 list_head completed_list;
- struct timeval timeout;
- int transferred;
- uint32_t stream_id;
- uint8_t state_flags; /* Protected by usbi_transfer->lock */
- uint8_t timeout_flags; /* Protected by the flying_stransfers_lock */
-
- /* 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).
- * Note paths taking both this and the flying_transfers_lock must
- * always take the flying_transfers_lock first */
- usbi_mutex_t lock;
-};
-
-enum usbi_transfer_state_flags {
- /* Transfer successfully submitted by backend */
- USBI_TRANSFER_IN_FLIGHT = 1 << 0,
-
- /* Cancellation was requested via libusb_cancel_transfer() */
- USBI_TRANSFER_CANCELLING = 1 << 1,
-
- /* Operation on the transfer failed because the device disappeared */
- USBI_TRANSFER_DEVICE_DISAPPEARED = 1 << 2,
-};
-
-enum usbi_transfer_timeout_flags {
- /* Set by backend submit_transfer() if the OS handles timeout */
- USBI_TRANSFER_OS_HANDLES_TIMEOUT = 1 << 0,
-
- /* The transfer timeout has been handled */
- USBI_TRANSFER_TIMEOUT_HANDLED = 1 << 1,
-
- /* The transfer timeout was successfully processed */
- USBI_TRANSFER_TIMED_OUT = 1 << 2,
-};
-
-#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 *dev_handle);
-
-int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
- enum libusb_transfer_status status);
-int usbi_handle_transfer_cancellation(struct usbi_transfer *transfer);
-void usbi_signal_transfer_completion(struct usbi_transfer *transfer);
-
-int usbi_parse_descriptor(const unsigned char *source, const char *descriptor,
- void *dest, int host_endian);
-int usbi_device_cache_descriptor(libusb_device *dev);
-int usbi_get_config_index_by_value(struct libusb_device *dev,
- uint8_t bConfigurationValue, int *idx);
-
-void usbi_connect_device (struct libusb_device *dev);
-void usbi_disconnect_device (struct libusb_device *dev);
-
-int usbi_signal_event(struct libusb_context *ctx);
-int usbi_clear_event(struct libusb_context *ctx);
-
-/* Internal abstraction for poll (needs struct usbi_transfer on Windows) */
-#if defined(OS_LINUX) || defined(OS_DARWIN) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
- defined(OS_HAIKU) || defined(OS_SUNOS)
-#include <unistd.h>
-#include "os/poll_posix.h"
-#elif defined(OS_WINDOWS) || defined(OS_WINCE)
-#include "os/poll_windows.h"
-#endif
-
-#if defined(_MSC_VER) && (_MSC_VER < 1900)
-#define snprintf usbi_snprintf
-#define vsnprintf usbi_vsnprintf
-int usbi_snprintf(char *dst, size_t size, const char *format, ...);
-int usbi_vsnprintf(char *dst, size_t size, const char *format, va_list ap);
-#define LIBUSB_PRINTF_WIN32
-#endif
-
-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);
-
-/* 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
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
- [] /* valid C99 code */
-#else
- [0] /* non-standard, but usually working code */
-#endif
- ;
-};
-
-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;
-
- /* Binary mask for backend specific capabilities */
- uint32_t caps;
-
- /* 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 reference
- * to 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.
- *
- * If the backend has hotplug support, this function is not used!
- *
- * Return 0 on success, or a LIBUSB_ERROR code on failure.
- */
- int (*get_device_list)(struct libusb_context *ctx,
- struct discovered_devs **discdevs);
-
- /* Apps which were written before hotplug support, may listen for
- * hotplug events on their own and call libusb_get_device_list on
- * device addition. In this case libusb_get_device_list will likely
- * return a list without the new device in there, as the hotplug
- * event thread will still be busy enumerating the device, which may
- * take a while, or may not even have seen the event yet.
- *
- * To avoid this libusb_get_device_list will call this optional
- * function for backends with hotplug support before copying
- * ctx->usb_devs to the user. In this function the backend should
- * ensure any pending hotplug events are fully processed before
- * returning.
- *
- * Optional, should be implemented by backends with hotplug support.
- */
- void (*hotplug_poll)(void);
-
- /* 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 *dev_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 *dev_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 the length read 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);
-
- /* Like get_config_descriptor but then by bConfigurationValue instead
- * of by index.
- *
- * Optional, if not present the core will call get_config_descriptor
- * for all configs until it finds the desired bConfigurationValue.
- *
- * Returns a pointer to the raw-descriptor in *buffer, this memory
- * is valid as long as device is valid.
- *
- * Returns the length of the returned raw-descriptor on success,
- * or a LIBUSB_ERROR code on failure.
- */
- int (*get_config_descriptor_by_value)(struct libusb_device *device,
- uint8_t bConfigurationValue, unsigned char **buffer,
- 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 *dev_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 *dev_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/applications 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 *dev_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 *dev_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 *dev_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 *dev_handle,
- unsigned char endpoint);
-
- /* Perform a USB port reset to reinitialize a device.
- *
- * If possible, the device 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 *dev_handle);
-
- /* Alloc num_streams usb3 bulk streams on the passed in endpoints */
- int (*alloc_streams)(struct libusb_device_handle *dev_handle,
- uint32_t num_streams, unsigned char *endpoints, int num_endpoints);
-
- /* Free usb3 bulk streams allocated with alloc_streams */
- int (*free_streams)(struct libusb_device_handle *dev_handle,
- unsigned char *endpoints, int num_endpoints);
-
- /* Allocate persistent DMA memory for the given device, suitable for
- * zerocopy. May return NULL on failure. Optional to implement.
- */
- unsigned char *(*dev_mem_alloc)(struct libusb_device_handle *handle,
- size_t len);
-
- /* Free memory allocated by dev_mem_alloc. */
- int (*dev_mem_free)(struct libusb_device_handle *handle,
- unsigned char *buffer, size_t len);
-
- /* 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 *dev_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 *dev_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 *dev_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.
- *
- * This function gets called with the flying_transfers_lock locked!
- *
- * 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 on file descriptors. Optional.
- *
- * Provide this function when file descriptors directly indicate device
- * or transfer activity. If your backend does not have such file descriptors,
- * implement the handle_transfer_completion function below.
- *
- * 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);
-
- /* Handle transfer completion. Optional.
- *
- * Provide this function when there are no file descriptors available
- * that directly indicate device or transfer activity. If your backend does
- * have such file descriptors, implement the handle_events function above.
- *
- * Your backend must tell the library when a transfer has completed by
- * calling usbi_signal_transfer_completion(). You should store any private
- * information about the transfer and its completion status in the transfer's
- * private backend data.
- *
- * During event handling, this function will be called on each transfer for
- * which usbi_signal_transfer_completion() was called.
- *
- * 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.
- *
- * Return 0 on success, or a LIBUSB_ERROR code on failure.
- */
- int (*handle_transfer_completion)(struct usbi_transfer *itransfer);
-
- /* 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;
-};
-
-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 openbsd_backend;
-extern const struct usbi_os_backend netbsd_backend;
-extern const struct usbi_os_backend windows_backend;
-extern const struct usbi_os_backend usbdk_backend;
-extern const struct usbi_os_backend wince_backend;
-extern const struct usbi_os_backend haiku_usb_raw_backend;
-extern const struct usbi_os_backend sunos_backend;
-
-extern struct list_head active_contexts_list;
-extern usbi_mutex_static_t active_contexts_lock;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c
deleted file mode 100644
index b0219d1..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.c
+++ /dev/null
@@ -1,2094 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:nil -*- */
-/*
- * darwin backend for libusb 1.0
- * Copyright © 2008-2016 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 <time.h>
-#include <ctype.h>
-#include <errno.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/sysctl.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 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200
- #include <objc/objc-auto.h>
-#endif
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
-/* Apple deprecated the darwin atomics in 10.12 in favor of C11 atomics */
-#include <stdatomic.h>
-#define libusb_darwin_atomic_fetch_add(x, y) atomic_fetch_add(x, y)
-
-_Atomic int32_t initCount = ATOMIC_VAR_INIT(0);
-#else
-/* use darwin atomics if the target is older than 10.12 */
-#include <libkern/OSAtomic.h>
-
-/* OSAtomicAdd32Barrier returns the new value */
-#define libusb_darwin_atomic_fetch_add(x, y) (OSAtomicAdd32Barrier(y, x) - y)
-
-static volatile int32_t initCount = 0;
-#endif
-
-#include "darwin_usb.h"
-
-/* async event thread */
-static pthread_mutex_t libusb_darwin_at_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t libusb_darwin_at_cond = PTHREAD_COND_INITIALIZER;
-
-static pthread_once_t darwin_init_once = PTHREAD_ONCE_INIT;
-
-static clock_serv_t clock_realtime;
-static clock_serv_t clock_monotonic;
-
-static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
-static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
-
-static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
-static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices};
-static char *darwin_device_class = kIOUSBDeviceClassName;
-
-#define DARWIN_CACHED_DEVICE(a) ((struct darwin_cached_device *) (((struct darwin_device_priv *)((a)->os_priv))->dev))
-
-/* 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 int darwin_scan_devices(struct libusb_context *ctx);
-static int process_new_device (struct libusb_context *ctx, io_service_t service);
-
-#if defined(ENABLE_LOGGING)
-static const char *darwin_error_str (int result) {
- static char string_buffer[50];
- 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";
- case kIOReturnNoResources:
- return "out of resources";
- case kIOUSBHighSpeedSplitError:
- return "high speed split error";
- default:
- snprintf(string_buffer, sizeof(string_buffer), "unknown error (0x%x)", result);
- return string_buffer;
- }
-}
-#endif
-
-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;
- }
-}
-
-/* this function must be called with the darwin_cached_devices_lock held */
-static void darwin_deref_cached_device(struct darwin_cached_device *cached_dev) {
- cached_dev->refcount--;
- /* free the device and remove it from the cache */
- if (0 == cached_dev->refcount) {
- list_del(&cached_dev->list);
-
- (*(cached_dev->device))->Release(cached_dev->device);
- free (cached_dev);
- }
-}
-
-static void darwin_ref_cached_device(struct darwin_cached_device *cached_dev) {
- cached_dev->refcount++;
-}
-
-static int ep_to_pipeRef(struct libusb_device_handle *dev_handle, uint8_t ep, uint8_t *pipep, uint8_t *ifcp, struct darwin_interface **interface_out) {
- 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_dbg ("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;
-
- if (ifcp)
- *ifcp = iface;
-
- if (interface_out)
- *interface_out = cInterface;
-
- usbi_dbg ("pipe %d on interface %d matches", *pipep, iface);
- 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 LIBUSB_ERROR_NOT_FOUND;
-}
-
-static int usb_setup_device_iterator (io_iterator_t *deviceIterator, UInt32 location) {
- CFMutableDictionaryRef matchingDict = IOServiceMatching(darwin_device_class);
-
- if (!matchingDict)
- return kIOReturnError;
-
- if (location) {
- CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- if (propertyMatchDict) {
- /* there are no unsigned CFNumber types so treat the value as signed. the os seems to do this
- internally (CFNumberType of locationID is 3) */
- CFTypeRef locationCF = CFNumberCreate (NULL, kCFNumberSInt32Type, &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);
-}
-
-/* Returns 1 on success, 0 on failure. */
-static int get_ioregistry_value_number (io_service_t service, CFStringRef property, CFNumberType type, void *p) {
- CFTypeRef cfNumber = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0);
- int ret = 0;
-
- if (cfNumber) {
- if (CFGetTypeID(cfNumber) == CFNumberGetTypeID()) {
- ret = CFNumberGetValue(cfNumber, type, p);
- }
-
- CFRelease (cfNumber);
- }
-
- return ret;
-}
-
-static int get_ioregistry_value_data (io_service_t service, CFStringRef property, ssize_t size, void *p) {
- CFTypeRef cfData = IORegistryEntryCreateCFProperty (service, property, kCFAllocatorDefault, 0);
- int ret = 0;
-
- if (cfData) {
- if (CFGetTypeID (cfData) == CFDataGetTypeID ()) {
- CFIndex length = CFDataGetLength (cfData);
- if (length < size) {
- size = length;
- }
-
- CFDataGetBytes (cfData, CFRangeMake(0, size), p);
- ret = 1;
- }
-
- CFRelease (cfData);
- }
-
- return ret;
-}
-
-static usb_device_t **darwin_device_from_service (io_service_t service)
-{
- io_cf_plugin_ref_t *plugInInterface = NULL;
- usb_device_t **device;
- kern_return_t result;
- SInt32 score;
-
- result = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID,
- kIOCFPlugInInterfaceID, &plugInInterface,
- &score);
-
- if (kIOReturnSuccess != result || !plugInInterface) {
- usbi_dbg ("could not set up plugin for service: %s", darwin_error_str (result));
- return NULL;
- }
-
- (void)(*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(DeviceInterfaceID),
- (LPVOID)&device);
- /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
- (*plugInInterface)->Release (plugInInterface);
-
- return device;
-}
-
-static void darwin_devices_attached (void *ptr, io_iterator_t add_devices) {
- struct libusb_context *ctx;
- io_service_t service;
-
- usbi_mutex_lock(&active_contexts_lock);
-
- while ((service = IOIteratorNext(add_devices))) {
- /* add this device to each active context's device list */
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- process_new_device (ctx, service);;
- }
-
- IOObjectRelease(service);
- }
-
- usbi_mutex_unlock(&active_contexts_lock);
-}
-
-static void darwin_devices_detached (void *ptr, io_iterator_t rem_devices) {
- struct libusb_device *dev = NULL;
- struct libusb_context *ctx;
- struct darwin_cached_device *old_device;
-
- io_service_t device;
- UInt64 session;
- int ret;
-
- usbi_mutex_lock(&active_contexts_lock);
-
- while ((device = IOIteratorNext (rem_devices)) != 0) {
- /* get the location from the i/o registry */
- ret = get_ioregistry_value_number (device, CFSTR("sessionID"), kCFNumberSInt64Type, &session);
- IOObjectRelease (device);
- if (!ret)
- continue;
-
- /* we need to match darwin_ref_cached_device call made in darwin_get_cached_device function
- otherwise no cached device will ever get freed */
- usbi_mutex_lock(&darwin_cached_devices_lock);
- list_for_each_entry(old_device, &darwin_cached_devices, list, struct darwin_cached_device) {
- if (old_device->session == session) {
- darwin_deref_cached_device (old_device);
- break;
- }
- }
- usbi_mutex_unlock(&darwin_cached_devices_lock);
-
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- usbi_dbg ("notifying context %p of device disconnect", ctx);
-
- dev = usbi_get_device_by_session_id(ctx, (unsigned long) session);
- if (dev) {
- /* signal the core that this device has been disconnected. the core will tear down this device
- when the reference count reaches 0 */
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- }
- }
- }
-
- usbi_mutex_unlock(&active_contexts_lock);
-}
-
-static void darwin_hotplug_poll (void)
-{
- /* not sure if 5 seconds will be too long/short but it should work ok */
- mach_timespec_t timeout = {.tv_sec = 5, .tv_nsec = 0};
-
- /* since a kernel thread may nodify the IOInterators used for
- * hotplug notidication we can't just clear the iterators.
- * instead just wait until all IOService providers are quiet */
- (void) IOKitWaitQuiet (kIOMasterPortDefault, &timeout);
-}
-
-static void darwin_clear_iterator (io_iterator_t iter) {
- io_service_t device;
-
- while ((device = IOIteratorNext (iter)) != 0)
- IOObjectRelease (device);
-}
-
-static void *darwin_event_thread_main (void *arg0) {
- IOReturn kresult;
- struct libusb_context *ctx = (struct libusb_context *)arg0;
- CFRunLoopRef runloop;
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
- /* Set this thread's name, so it can be seen in the debugger
- and crash reports. */
- pthread_setname_np ("org.libusb.device-hotplug");
-#endif
-
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 && MAC_OS_X_VERSION_MIN_REQUIRED < 101200
- /* 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.
- Garbage collection support was entirely removed in 10.12,
- so don't bother there. */
- objc_registerThreadWithCollector();
-#endif
-
- /* hotplug (device arrival/removal) sources */
- CFRunLoopSourceContext libusb_shutdown_cfsourcectx;
- CFRunLoopSourceRef libusb_notification_cfsource;
- io_notification_port_t libusb_notification_port;
- io_iterator_t libusb_rem_device_iterator;
- io_iterator_t libusb_add_device_iterator;
-
- usbi_dbg ("creating hotplug event source");
-
- runloop = CFRunLoopGetCurrent ();
- CFRetain (runloop);
-
- /* add the shutdown cfsource to the run loop */
- memset(&libusb_shutdown_cfsourcectx, 0, sizeof(libusb_shutdown_cfsourcectx));
- libusb_shutdown_cfsourcectx.info = runloop;
- libusb_shutdown_cfsourcectx.perform = (void (*)(void *))CFRunLoopStop;
- libusb_darwin_acfls = CFRunLoopSourceCreate(NULL, 0, &libusb_shutdown_cfsourcectx);
- CFRunLoopAddSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode);
-
- /* add the notification port to the run loop */
- libusb_notification_port = IONotificationPortCreate (kIOMasterPortDefault);
- libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
- CFRunLoopAddSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
-
- /* create notifications for removed devices */
- kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification,
- IOServiceMatching(darwin_device_class),
- darwin_devices_detached,
- 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);
- }
-
- /* create notifications for attached devices */
- kresult = IOServiceAddMatchingNotification(libusb_notification_port, kIOFirstMatchNotification,
- IOServiceMatching(darwin_device_class),
- darwin_devices_attached,
- ctx, &libusb_add_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);
- darwin_clear_iterator (libusb_add_device_iterator);
-
- usbi_dbg ("darwin event thread ready to receive events");
-
- /* signal the main thread that the hotplug runloop has been created. */
- pthread_mutex_lock (&libusb_darwin_at_mutex);
- libusb_darwin_acfl = runloop;
- pthread_cond_signal (&libusb_darwin_at_cond);
- pthread_mutex_unlock (&libusb_darwin_at_mutex);
-
- /* run the runloop */
- CFRunLoopRun();
-
- usbi_dbg ("darwin event thread exiting");
-
- /* remove the notification cfsource */
- CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
-
- /* remove the shutdown cfsource */
- CFRunLoopRemoveSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode);
-
- /* delete notification port */
- IONotificationPortDestroy (libusb_notification_port);
-
- /* delete iterators */
- IOObjectRelease (libusb_rem_device_iterator);
- IOObjectRelease (libusb_add_device_iterator);
-
- CFRelease (libusb_darwin_acfls);
- CFRelease (runloop);
-
- libusb_darwin_acfls = NULL;
- libusb_darwin_acfl = NULL;
-
- pthread_exit (NULL);
-}
-
-/* cleanup function to destroy cached devices */
-static void __attribute__((destructor)) _darwin_finalize(void) {
- struct darwin_cached_device *dev, *next;
-
- usbi_mutex_lock(&darwin_cached_devices_lock);
- list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) {
- darwin_deref_cached_device(dev);
- }
- usbi_mutex_unlock(&darwin_cached_devices_lock);
-}
-
-static void darwin_check_version (void) {
- /* adjust for changes in the USB stack in xnu 15 */
- int sysctl_args[] = {CTL_KERN, KERN_OSRELEASE};
- long version;
- char version_string[256] = {'\0',};
- size_t length = 256;
-
- sysctl(sysctl_args, 2, version_string, &length, NULL, 0);
-
- errno = 0;
- version = strtol (version_string, NULL, 10);
- if (0 == errno && version >= 15) {
- darwin_device_class = "IOUSBHostDevice";
- }
-}
-
-static int darwin_init(struct libusb_context *ctx) {
- host_name_port_t host_self;
- int rc;
-
- rc = pthread_once (&darwin_init_once, darwin_check_version);
- if (rc) {
- return LIBUSB_ERROR_OTHER;
- }
-
- rc = darwin_scan_devices (ctx);
- if (LIBUSB_SUCCESS != rc) {
- return rc;
- }
-
- if (libusb_darwin_atomic_fetch_add (&initCount, 1) == 0) {
- /* 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_create (&libusb_darwin_at, NULL, darwin_event_thread_main, 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 rc;
-}
-
-static void darwin_exit (void) {
- if (libusb_darwin_atomic_fetch_add (&initCount, -1) == 1) {
- mach_port_deallocate(mach_task_self(), clock_realtime);
- mach_port_deallocate(mach_task_self(), clock_monotonic);
-
- /* stop the event runloop and wait for the thread to terminate. */
- CFRunLoopSourceSignal(libusb_darwin_acfls);
- CFRunLoopWakeUp (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_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
-
- /* 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_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
- 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_NOT_FOUND;
-}
-
-static int darwin_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian) {
- struct darwin_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
- int config_index;
-
- if (0 == priv->active_config)
- return LIBUSB_ERROR_NOT_FOUND;
-
- 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_cached_device *priv = DARWIN_CACHED_DEVICE(dev);
- IOUSBConfigurationDescriptorPtr desc;
- IOReturn kresult;
- int ret;
-
- if (!priv || !priv->device)
- return LIBUSB_ERROR_OTHER;
-
- kresult = (*priv->device)->GetConfigurationDescriptorPtr (priv->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;
- }
-
- ret = darwin_to_libusb (kresult);
- if (ret != LIBUSB_SUCCESS)
- return ret;
-
- return (int) len;
-}
-
-/* check whether the os has configured the device */
-static int darwin_check_configuration (struct libusb_context *ctx, struct darwin_cached_device *dev) {
- usb_device_t **darwin_device = dev->device;
-
- IOUSBConfigurationDescriptorPtr configDesc;
- IOUSBFindInterfaceRequest request;
- kern_return_t kresult;
- io_iterator_t interface_iterator;
- io_service_t firstInterface;
-
- if (dev->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 */
- }
-
- /* checking the configuration of a root hub simulation takes ~1 s in 10.11. the device is
- not usable anyway */
- if (0x05ac == dev->dev_descriptor.idVendor && 0x8005 == dev->dev_descriptor.idProduct) {
- usbi_dbg ("ignoring configuration on root hub simulation");
- dev->active_config = 0;
- return 0;
- }
-
- /* find the first configuration */
- kresult = (*darwin_device)->GetConfigurationDescriptorPtr (darwin_device, 0, &configDesc);
- dev->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 (dev->dev_descriptor.bNumConfigurations == 1)
- /* to avoid problems with some devices get the configurations value from the configuration descriptor */
- dev->active_config = dev->first_config;
- else
- /* devices with more than one configuration should work with GetConfiguration */
- (*darwin_device)->GetConfiguration (darwin_device, &dev->active_config);
- } else
- /* not configured */
- dev->active_config = 0;
-
- usbi_dbg ("active config: %u, first config: %u", dev->active_config, dev->first_config);
-
- return 0;
-}
-
-static int darwin_request_descriptor (usb_device_t **device, UInt8 desc, UInt8 desc_index, void *buffer, size_t buffer_size) {
- IOUSBDevRequestTO req;
-
- memset (buffer, 0, buffer_size);
-
- /* Set up request for descriptor/ */
- req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- req.bRequest = kUSBRqGetDescriptor;
- req.wValue = desc << 8;
- req.wIndex = desc_index;
- req.wLength = buffer_size;
- req.pData = buffer;
- req.noDataTimeout = 20;
- req.completionTimeout = 100;
-
- return (*device)->DeviceRequestTO (device, &req);
-}
-
-static int darwin_cache_device_descriptor (struct libusb_context *ctx, struct darwin_cached_device *dev) {
- usb_device_t **device = dev->device;
- int retries = 1, delay = 30000;
- int unsuspended = 0, try_unsuspend = 1, try_reconfigure = 1;
- int is_open = 0;
- int ret = 0, ret2;
- UInt8 bDeviceClass;
- UInt16 idProduct, idVendor;
-
- dev->can_enumerate = 0;
-
- (*device)->GetDeviceClass (device, &bDeviceClass);
- (*device)->GetDeviceProduct (device, &idProduct);
- (*device)->GetDeviceVendor (device, &idVendor);
-
- /* 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 */
- is_open = ((*device)->USBDeviceOpenSeize(device) == kIOReturnSuccess);
-
- do {
- /**** retrieve device descriptor ****/
- ret = darwin_request_descriptor (device, kUSBDeviceDesc, 0, &dev->dev_descriptor, sizeof(dev->dev_descriptor));
-
- if (kIOReturnOverrun == ret && kUSBDeviceDesc == dev->dev_descriptor.bDescriptorType)
- /* received an overrun error but we still received a device descriptor */
- ret = kIOReturnSuccess;
-
- if (kIOUSBVendorIDAppleComputer == idVendor) {
- /* NTH: don't bother retrying or unsuspending Apple devices */
- break;
- }
-
- if (kIOReturnSuccess == ret && (0 == dev->dev_descriptor.bNumConfigurations ||
- 0 == dev->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 = 0;
-
- /* IOUSBFamily 320+ provides a way to detect device suspension but earlier versions do not */
- (void)(*device)->GetUSBDeviceInformation (device, &info);
-
- /* note that the device was suspended */
- if (info & (1 << kUSBInformationDeviceIsSuspendedBit) || 0 == info)
- try_unsuspend = 1;
-#endif
-
- if (try_unsuspend) {
- /* try to unsuspend 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 */
- nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL);
- }
- } 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 (%x). skipping device",
- idVendor, idProduct, darwin_error_str (ret), ret);
- else
- usbi_warn (ctx, "could not retrieve device descriptor %.4x:%.4x: %s (%x). skipping device",
- idVendor, idProduct, darwin_error_str (ret), ret);
- return darwin_to_libusb (ret);
- }
-
- /* catch buggy hubs (which appear to be virtual). Apple's own USB prober has problems with these devices. */
- if (libusb_le16_to_cpu (dev->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 (dev->dev_descriptor.idProduct));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- usbi_dbg ("cached device descriptor:");
- usbi_dbg (" bDescriptorType: 0x%02x", dev->dev_descriptor.bDescriptorType);
- usbi_dbg (" bcdUSB: 0x%04x", dev->dev_descriptor.bcdUSB);
- usbi_dbg (" bDeviceClass: 0x%02x", dev->dev_descriptor.bDeviceClass);
- usbi_dbg (" bDeviceSubClass: 0x%02x", dev->dev_descriptor.bDeviceSubClass);
- usbi_dbg (" bDeviceProtocol: 0x%02x", dev->dev_descriptor.bDeviceProtocol);
- usbi_dbg (" bMaxPacketSize0: 0x%02x", dev->dev_descriptor.bMaxPacketSize0);
- usbi_dbg (" idVendor: 0x%04x", dev->dev_descriptor.idVendor);
- usbi_dbg (" idProduct: 0x%04x", dev->dev_descriptor.idProduct);
- usbi_dbg (" bcdDevice: 0x%04x", dev->dev_descriptor.bcdDevice);
- usbi_dbg (" iManufacturer: 0x%02x", dev->dev_descriptor.iManufacturer);
- usbi_dbg (" iProduct: 0x%02x", dev->dev_descriptor.iProduct);
- usbi_dbg (" iSerialNumber: 0x%02x", dev->dev_descriptor.iSerialNumber);
- usbi_dbg (" bNumConfigurations: 0x%02x", dev->dev_descriptor.bNumConfigurations);
-
- dev->can_enumerate = 1;
-
- return LIBUSB_SUCCESS;
-}
-
-static int get_device_port (io_service_t service, UInt8 *port) {
- kern_return_t result;
- io_service_t parent;
- int ret = 0;
-
- if (get_ioregistry_value_number (service, CFSTR("PortNum"), kCFNumberSInt8Type, port)) {
- return 1;
- }
-
- result = IORegistryEntryGetParentEntry (service, kIOServicePlane, &parent);
- if (kIOReturnSuccess == result) {
- ret = get_ioregistry_value_data (parent, CFSTR("port"), 1, port);
- IOObjectRelease (parent);
- }
-
- return ret;
-}
-
-static int darwin_get_cached_device(struct libusb_context *ctx, io_service_t service,
- struct darwin_cached_device **cached_out) {
- struct darwin_cached_device *new_device;
- UInt64 sessionID = 0, parent_sessionID = 0;
- int ret = LIBUSB_SUCCESS;
- usb_device_t **device;
- io_service_t parent;
- kern_return_t result;
- UInt8 port = 0;
-
- /* get some info from the io registry */
- (void) get_ioregistry_value_number (service, CFSTR("sessionID"), kCFNumberSInt64Type, &sessionID);
- if (!get_device_port (service, &port)) {
- usbi_dbg("could not get connected port number");
- }
-
- usbi_dbg("finding cached device for sessionID 0x%" PRIx64, sessionID);
-
- result = IORegistryEntryGetParentEntry (service, kIOUSBPlane, &parent);
-
- if (kIOReturnSuccess == result) {
- (void) get_ioregistry_value_number (parent, CFSTR("sessionID"), kCFNumberSInt64Type, &parent_sessionID);
- IOObjectRelease(parent);
- }
-
- usbi_mutex_lock(&darwin_cached_devices_lock);
- do {
- *cached_out = NULL;
-
- list_for_each_entry(new_device, &darwin_cached_devices, list, struct darwin_cached_device) {
- usbi_dbg("matching sessionID 0x%" PRIx64 " against cached device with sessionID 0x%" PRIx64, sessionID, new_device->session);
- if (new_device->session == sessionID) {
- usbi_dbg("using cached device for device");
- *cached_out = new_device;
- break;
- }
- }
-
- if (*cached_out)
- break;
-
- usbi_dbg("caching new device with sessionID 0x%" PRIx64, sessionID);
-
- device = darwin_device_from_service (service);
- if (!device) {
- ret = LIBUSB_ERROR_NO_DEVICE;
- break;
- }
-
- new_device = calloc (1, sizeof (*new_device));
- if (!new_device) {
- ret = LIBUSB_ERROR_NO_MEM;
- break;
- }
-
- /* add this device to the cached device list */
- list_add(&new_device->list, &darwin_cached_devices);
-
- (*device)->GetDeviceAddress (device, (USBDeviceAddress *)&new_device->address);
-
- /* keep a reference to this device */
- darwin_ref_cached_device(new_device);
-
- new_device->device = device;
- new_device->session = sessionID;
- (*device)->GetLocationID (device, &new_device->location);
- new_device->port = port;
- new_device->parent_session = parent_sessionID;
-
- /* cache the device descriptor */
- ret = darwin_cache_device_descriptor(ctx, new_device);
- if (ret)
- break;
-
- if (new_device->can_enumerate) {
- snprintf(new_device->sys_path, 20, "%03i-%04x-%04x-%02x-%02x", new_device->address,
- new_device->dev_descriptor.idVendor, new_device->dev_descriptor.idProduct,
- new_device->dev_descriptor.bDeviceClass, new_device->dev_descriptor.bDeviceSubClass);
- }
- } while (0);
-
- usbi_mutex_unlock(&darwin_cached_devices_lock);
-
- /* keep track of devices regardless of if we successfully enumerate them to
- prevent them from being enumerated multiple times */
-
- *cached_out = new_device;
-
- return ret;
-}
-
-static int process_new_device (struct libusb_context *ctx, io_service_t service) {
- struct darwin_device_priv *priv;
- struct libusb_device *dev = NULL;
- struct darwin_cached_device *cached_device;
- UInt8 devSpeed;
- int ret = 0;
-
- do {
- ret = darwin_get_cached_device (ctx, service, &cached_device);
-
- if (ret < 0 || !cached_device->can_enumerate) {
- return ret;
- }
-
- /* check current active configuration (and cache the first configuration value--
- which may be used by claim_interface) */
- ret = darwin_check_configuration (ctx, cached_device);
- if (ret)
- break;
-
- usbi_dbg ("allocating new device in context %p for with session 0x%" PRIx64,
- ctx, cached_device->session);
-
- dev = usbi_alloc_device(ctx, (unsigned long) cached_device->session);
- if (!dev) {
- return LIBUSB_ERROR_NO_MEM;
- }
-
- priv = (struct darwin_device_priv *)dev->os_priv;
-
- priv->dev = cached_device;
- darwin_ref_cached_device (priv->dev);
-
- if (cached_device->parent_session > 0) {
- dev->parent_dev = usbi_get_device_by_session_id (ctx, (unsigned long) cached_device->parent_session);
- } else {
- dev->parent_dev = NULL;
- }
- dev->port_number = cached_device->port;
- dev->bus_number = cached_device->location >> 24;
- dev->device_address = cached_device->address;
-
- (*(priv->dev->device))->GetDeviceSpeed (priv->dev->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;
-#if DeviceVersion >= 500
- case kUSBDeviceSpeedSuper: dev->speed = LIBUSB_SPEED_SUPER; break;
-#endif
- default:
- usbi_warn (ctx, "Got unknown device speed %d", devSpeed);
- }
-
- ret = usbi_sanitize_device (dev);
- if (ret < 0)
- break;
-
- usbi_dbg ("found device with address %d port = %d parent = %p at %p", dev->device_address,
- dev->port_number, (void *) dev->parent_dev, priv->dev->sys_path);
- } while (0);
-
- if (0 == ret) {
- usbi_connect_device (dev);
- } else {
- libusb_unref_device (dev);
- }
-
- return ret;
-}
-
-static int darwin_scan_devices(struct libusb_context *ctx) {
- io_iterator_t deviceIterator;
- io_service_t service;
- kern_return_t kresult;
-
- kresult = usb_setup_device_iterator (&deviceIterator, 0);
- if (kresult != kIOReturnSuccess)
- return darwin_to_libusb (kresult);
-
- while ((service = IOIteratorNext (deviceIterator))) {
- (void) process_new_device (ctx, service);
-
- IOObjectRelease(service);
- }
-
- 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_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- IOReturn kresult;
-
- if (0 == dpriv->open_count) {
- /* try to open the device */
- kresult = (*(dpriv->device))->USBDeviceOpenSeize (dpriv->device);
- if (kresult != kIOReturnSuccess) {
- usbi_warn (HANDLE_CTX (dev_handle), "USBDeviceOpen: %s", darwin_error_str(kresult));
-
- if (kIOReturnExclusiveAccess != kresult) {
- return darwin_to_libusb (kresult);
- }
-
- /* it is possible to perform some actions on a device that is not open so do not return an error */
- priv->is_open = 0;
- } else {
- priv->is_open = 1;
- }
-
- /* 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));
-
- if (priv->is_open) {
- (*(dpriv->device))->USBDeviceClose (dpriv->device);
- }
-
- priv->is_open = 0;
-
- return darwin_to_libusb (kresult);
- }
-
- 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++;
-
- usbi_dbg ("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_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- 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!");
- 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) {
- /* delete the device's async event source */
- if (priv->cfSource) {
- CFRunLoopRemoveSource (libusb_darwin_acfl, priv->cfSource, kCFRunLoopDefaultMode);
- CFRelease (priv->cfSource);
- priv->cfSource = NULL;
- CFRelease (libusb_darwin_acfl);
- }
-
- if (priv->is_open) {
- /* 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_warn (HANDLE_CTX (dev_handle), "USBDeviceClose: %s", darwin_error_str(kresult));
- }
- }
- }
-}
-
-static int darwin_get_configuration(struct libusb_device_handle *dev_handle, int *config) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
-
- *config = (int) dpriv->active_config;
-
- return 0;
-}
-
-static int darwin_set_configuration(struct libusb_device_handle *dev_handle, int config) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- 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;
- kern_return_t kresult;
- io_iterator_t interface_iterator;
- UInt8 bInterfaceNumber;
- int ret;
-
- *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;
-
- while ((*usbInterfacep = IOIteratorNext(interface_iterator))) {
- /* find the interface number */
- ret = get_ioregistry_value_number (*usbInterfacep, CFSTR("bInterfaceNumber"), kCFNumberSInt8Type,
- &bInterfaceNumber);
-
- if (ret && bInterfaceNumber == ifc) {
- break;
- }
-
- (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 rc;
-
- usbi_dbg ("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 (int i = 1 ; i <= numep ; i++) {
- kresult = (*(cInterface->interface))->GetPipeProperties(cInterface->interface, i, &direction, &number, &dont_care1,
- &dont_care2, &dont_care3);
-
- if (kresult != kIOReturnSuccess) {
- /* probably a buggy device. try to get the endpoint address from the descriptors */
- struct libusb_config_descriptor *config;
- const struct libusb_endpoint_descriptor *endpoint_desc;
- UInt8 alt_setting;
-
- kresult = (*(cInterface->interface))->GetAlternateSetting (cInterface->interface, &alt_setting);
- if (kresult) {
- usbi_err (HANDLE_CTX (dev_handle), "can't get alternate setting for interface");
- return darwin_to_libusb (kresult);
- }
-
- rc = libusb_get_active_config_descriptor (dev_handle->dev, &config);
- if (LIBUSB_SUCCESS != rc) {
- return rc;
- }
-
- endpoint_desc = config->interface[iface].altsetting[alt_setting].endpoint + i - 1;
-
- cInterface->endpoint_addrs[i - 1] = endpoint_desc->bEndpointAddress;
- } else {
- cInterface->endpoint_addrs[i - 1] = (((kUSBIn == direction) << kUSBRqDirnShift) | (number & LIBUSB_ENDPOINT_ADDRESS_MASK));
- }
-
- usbi_dbg ("interface: %i pipe %i: dir: %i number: %i", iface, i, cInterface->endpoint_addrs[i - 1] >> kUSBRqDirnShift,
- cInterface->endpoint_addrs[i - 1] & 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_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- 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 */
- /* Use release instead of IODestroyPlugInInterface to avoid stopping IOServices associated with this device */
- (*plugInInterface)->Release (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_dbg ("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_warn (HANDLE_CTX (dev_handle), "USBInterfaceClose: %s", darwin_error_str(kresult));
-
- kresult = (*(cInterface->interface))->Release(cInterface->interface);
- if (kresult != kIOReturnSuccess)
- usbi_warn (HANDLE_CTX (dev_handle), "Release: %s", darwin_error_str(kresult));
-
- cInterface->interface = (usb_interface_t **) 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) {
- /* current interface */
- struct darwin_interface *cInterface;
- IOReturn kresult;
- uint8_t pipeRef;
-
- /* determine the interface/endpoint to use */
- if (ep_to_pipeRef (dev_handle, endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (HANDLE_CTX (dev_handle), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- /* newer versions of darwin support clearing additional bits on the device's endpoint */
- kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
- if (kresult)
- usbi_warn (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_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- IOUSBDeviceDescriptor descriptor;
- IOUSBConfigurationDescriptorPtr cached_configuration;
- IOUSBConfigurationDescriptor configuration;
- bool reenumerate = false;
- IOReturn kresult;
- int i;
-
- 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);
- }
-
- do {
- usbi_dbg ("darwin/reset_device: checking if device descriptor changed");
-
- /* ignore return code. if we can't get a descriptor it might be worthwhile re-enumerating anway */
- (void) darwin_request_descriptor (dpriv->device, kUSBDeviceDesc, 0, &descriptor, sizeof (descriptor));
-
- /* check if the device descriptor has changed */
- if (0 != memcmp (&dpriv->dev_descriptor, &descriptor, sizeof (descriptor))) {
- reenumerate = true;
- break;
- }
-
- /* check if any configuration descriptor has changed */
- for (i = 0 ; i < descriptor.bNumConfigurations ; ++i) {
- usbi_dbg ("darwin/reset_device: checking if configuration descriptor %d changed", i);
-
- (void) darwin_request_descriptor (dpriv->device, kUSBConfDesc, i, &configuration, sizeof (configuration));
- (*(dpriv->device))->GetConfigurationDescriptorPtr (dpriv->device, i, &cached_configuration);
-
- if (!cached_configuration || 0 != memcmp (cached_configuration, &configuration, sizeof (configuration))) {
- reenumerate = true;
- break;
- }
- }
- } while (0);
-
- if (reenumerate) {
- usbi_dbg ("darwin/reset_device: device requires reenumeration");
- (void) (*(dpriv->device))->USBDeviceReEnumerate (dpriv->device, 0);
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg ("darwin/reset_device: device reset complete");
-
- return LIBUSB_SUCCESS;
-}
-
-static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle, int interface) {
- struct darwin_cached_device *dpriv = DARWIN_CACHED_DEVICE(dev_handle->dev);
- 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) {
- UNUSED(dev_handle);
- UNUSED(interface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
- UNUSED(dev_handle);
- UNUSED(interface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static void darwin_destroy_device(struct libusb_device *dev) {
- struct darwin_device_priv *dpriv = (struct darwin_device_priv *) dev->os_priv;
-
- if (dpriv->dev) {
- /* need to hold the lock in case this is the last reference to the device */
- usbi_mutex_lock(&darwin_cached_devices_lock);
- darwin_deref_cached_device (dpriv->dev);
- dpriv->dev = NULL;
- usbi_mutex_unlock(&darwin_cached_devices_lock);
- }
-}
-
-static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- IOReturn ret;
- uint8_t transferType;
- /* None of the values below are used in libusbx for bulk transfers */
- uint8_t direction, number, interval, pipeRef;
- uint16_t maxPacketSize;
-
- struct darwin_interface *cInterface;
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- ret = (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
- &transferType, &maxPacketSize, &interval);
-
- if (ret) {
- usbi_err (TRANSFER_CTX (transfer), "bulk transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
- darwin_error_str(ret), ret);
- return darwin_to_libusb (ret);
- }
-
- if (0 != (transfer->length % maxPacketSize)) {
- /* do not need a zero packet */
- transfer->flags &= ~LIBUSB_TRANSFER_ADD_ZERO_PACKET;
- }
-
- /* submit the request */
- /* timeouts are unavailable on interrupt endpoints */
- if (transferType == kUSBInterrupt) {
- if (IS_XFERIN(transfer))
- 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->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
-
- if (IS_XFERIN(transfer))
- 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_XFERIN(transfer) ? "In" : "Out",
- darwin_error_str(ret), ret);
-
- return darwin_to_libusb (ret);
-}
-
-#if InterfaceVersion >= 550
-static int submit_stream_transfer(struct usbi_transfer *itransfer) {
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct darwin_interface *cInterface;
- uint8_t pipeRef;
- IOReturn ret;
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- itransfer->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
-
- if (IS_XFERIN(transfer))
- ret = (*(cInterface->interface))->ReadStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
- transfer->buffer, transfer->length, transfer->timeout,
- transfer->timeout, darwin_async_io_callback, (void *)itransfer);
- else
- ret = (*(cInterface->interface))->WriteStreamsPipeAsyncTO(cInterface->interface, pipeRef, itransfer->stream_id,
- transfer->buffer, transfer->length, transfer->timeout,
- transfer->timeout, darwin_async_io_callback, (void *)itransfer);
-
- if (ret)
- usbi_err (TRANSFER_CTX (transfer), "bulk stream transfer failed (dir = %s): %s (code = 0x%08x)", IS_XFERIN(transfer) ? "In" : "Out",
- darwin_error_str(ret), ret);
-
- return darwin_to_libusb (ret);
-}
-#endif
-
-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);
-
- IOReturn kresult;
- uint8_t direction, number, interval, pipeRef, transferType;
- uint16_t maxPacketSize;
- UInt64 frame;
- AbsoluteTime atTime;
- int i;
-
- struct darwin_interface *cInterface;
-
- /* 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, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- /* determine the properties of this endpoint and the speed of the device */
- (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
- &transferType, &maxPacketSize, &interval);
-
- /* 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);
- }
-
- (*(cInterface->interface))->GetPipeProperties (cInterface->interface, pipeRef, &direction, &number,
- &transferType, &maxPacketSize, &interval);
-
- /* 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_XFERIN(transfer))
- 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);
-
- if (LIBUSB_SPEED_FULL == transfer->dev_handle->dev->speed)
- /* Full speed */
- cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1));
- else
- /* High/super speed */
- cInterface->frames[transfer->endpoint] = frame + transfer->num_iso_packets * (1 << (interval - 1)) / 8;
-
- if (kresult != kIOReturnSuccess) {
- usbi_err (TRANSFER_CTX (transfer), "isochronous transfer failed (dir: %s): %s", IS_XFERIN(transfer) ? "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_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
- struct darwin_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
-
- IOReturn kresult;
-
- memset(&tpriv->req, 0, sizeof(tpriv->req));
-
- /* IOUSBDeviceInterface expects the request in cpu endianness */
- 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->timeout_flags |= USBI_TRANSFER_OS_HANDLES_TIMEOUT;
-
- /* all transfers in libusb-1.0 are async */
-
- if (transfer->endpoint) {
- struct darwin_interface *cInterface;
- uint8_t pipeRef;
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- 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);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
-#if InterfaceVersion >= 550
- return submit_stream_transfer(itransfer);
-#else
- usbi_err (TRANSFER_CTX(transfer), "IOUSBFamily version does not support bulk stream transfers");
- return LIBUSB_ERROR_NOT_SUPPORTED;
-#endif
- 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_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
- IOReturn kresult;
-
- usbi_warn (ITRANSFER_CTX (itransfer), "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_cached_device *dpriv = DARWIN_CACHED_DEVICE(transfer->dev_handle->dev);
- struct darwin_interface *cInterface;
- uint8_t pipeRef, iface;
- IOReturn kresult;
-
- if (ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, &iface, &cInterface) != 0) {
- usbi_err (TRANSFER_CTX (transfer), "endpoint not found on any open interface");
-
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (!dpriv->device)
- return LIBUSB_ERROR_NO_DEVICE;
-
- usbi_warn (ITRANSFER_CTX (itransfer), "aborting all transactions on interface %d pipe %d", iface, pipeRef);
-
- /* abort transactions */
-#if InterfaceVersion >= 550
- if (LIBUSB_TRANSFER_TYPE_BULK_STREAM == transfer->type)
- (*(cInterface->interface))->AbortStreamsPipe (cInterface->interface, pipeRef, itransfer->stream_id);
- else
-#endif
- (*(cInterface->interface))->AbortPipe (cInterface->interface, pipeRef);
-
- usbi_dbg ("calling clear pipe stall to clear the data toggle bit");
-
- /* newer versions of darwin support clearing additional bits on the device's endpoint */
- kresult = (*(cInterface->interface))->ClearPipeStallBothEnds(cInterface->interface, pipeRef);
-
- 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_transfer_priv *tpriv = usbi_transfer_get_os_priv(itransfer);
-
- usbi_dbg ("an async io operation has completed");
-
- /* if requested write a zero packet */
- if (kIOReturnSuccess == result && IS_XFEROUT(transfer) && transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
- struct darwin_interface *cInterface;
- uint8_t pipeRef;
-
- (void) ep_to_pipeRef (transfer->dev_handle, transfer->endpoint, &pipeRef, NULL, &cInterface);
-
- (*(cInterface->interface))->WritePipe (cInterface->interface, pipeRef, transfer->buffer, 0);
- }
-
- tpriv->result = result;
- tpriv->size = (UInt32) (uintptr_t) arg0;
-
- /* signal the core that this transfer is complete */
- usbi_signal_transfer_completion(itransfer);
-}
-
-static int darwin_transfer_status (struct usbi_transfer *itransfer, kern_return_t result) {
- if (itransfer->timeout_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_dbg ("transfer error: pipe is stalled");
- return LIBUSB_TRANSFER_STALL;
- case kIOReturnOverrun:
- usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: data overrun");
- return LIBUSB_TRANSFER_OVERFLOW;
- case kIOUSBTransactionTimeout:
- usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: timed out");
- itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
- return LIBUSB_TRANSFER_TIMED_OUT;
- default:
- usbi_warn (ITRANSFER_CTX (itransfer), "transfer error: %s (value = 0x%08x)", darwin_error_str (result), result);
- return LIBUSB_TRANSFER_ERROR;
- }
-}
-
-static int darwin_handle_transfer_completion (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);
- 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 LIBUSB_ERROR_INVALID_PARAM;
- }
-
- usbi_dbg ("handling %s completion with kernel status %d",
- isControl ? "control" : isBulk ? "bulk" : isIsoc ? "isoc" : "interrupt", tpriv->result);
-
- if (kIOReturnSuccess == tpriv->result || kIOReturnUnderrun == tpriv->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 += tpriv->size;
- }
-
- /* it is ok to handle cancelled transfers without calling usbi_handle_transfer_cancellation (we catch timeout transfers) */
- return usbi_handle_transfer_completion (itransfer, darwin_transfer_status (itransfer, tpriv->result));
-}
-
-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;
-}
-
-#if InterfaceVersion >= 550
-static int darwin_alloc_streams (struct libusb_device_handle *dev_handle, uint32_t num_streams, unsigned char *endpoints,
- int num_endpoints) {
- struct darwin_interface *cInterface;
- UInt32 supportsStreams;
- uint8_t pipeRef;
- int rc, i;
-
- /* find the mimimum number of supported streams on the endpoint list */
- for (i = 0 ; i < num_endpoints ; ++i) {
- if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface))) {
- return rc;
- }
-
- (*(cInterface->interface))->SupportsStreams (cInterface->interface, pipeRef, &supportsStreams);
- if (num_streams > supportsStreams)
- num_streams = supportsStreams;
- }
-
- /* it is an error if any endpoint in endpoints does not support streams */
- if (0 == num_streams)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- /* create the streams */
- for (i = 0 ; i < num_endpoints ; ++i) {
- (void) ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface);
-
- rc = (*(cInterface->interface))->CreateStreams (cInterface->interface, pipeRef, num_streams);
- if (kIOReturnSuccess != rc)
- return darwin_to_libusb(rc);
- }
-
- return num_streams;
-}
-
-static int darwin_free_streams (struct libusb_device_handle *dev_handle, unsigned char *endpoints, int num_endpoints) {
- struct darwin_interface *cInterface;
- UInt32 supportsStreams;
- uint8_t pipeRef;
- int rc;
-
- for (int i = 0 ; i < num_endpoints ; ++i) {
- if (0 != (rc = ep_to_pipeRef (dev_handle, endpoints[i], &pipeRef, NULL, &cInterface)))
- return rc;
-
- (*(cInterface->interface))->SupportsStreams (cInterface->interface, pipeRef, &supportsStreams);
- if (0 == supportsStreams)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- rc = (*(cInterface->interface))->CreateStreams (cInterface->interface, pipeRef, 0);
- if (kIOReturnSuccess != rc)
- return darwin_to_libusb(rc);
- }
-
- return LIBUSB_SUCCESS;
-}
-#endif
-
-const struct usbi_os_backend darwin_backend = {
- .name = "Darwin",
- .caps = 0,
- .init = darwin_init,
- .exit = darwin_exit,
- .get_device_list = NULL, /* not needed */
- .get_device_descriptor = darwin_get_device_descriptor,
- .get_active_config_descriptor = darwin_get_active_config_descriptor,
- .get_config_descriptor = darwin_get_config_descriptor,
- .hotplug_poll = darwin_hotplug_poll,
-
- .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,
-
-#if InterfaceVersion >= 550
- .alloc_streams = darwin_alloc_streams,
- .free_streams = darwin_free_streams,
-#endif
-
- .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_transfer_completion = darwin_handle_transfer_completion,
-
- .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),
-};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h
deleted file mode 100644
index 1180434..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/darwin_usb.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * darwin backend for libusb 1.0
- * Copyright © 2008-2015 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 (kIOUSBInterfaceInterfaceID700) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
-
-#define usb_interface_t IOUSBInterfaceInterface700
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID700
-#define InterfaceVersion 700
-
-#elif defined (kIOUSBInterfaceInterfaceID550) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
-
-#define usb_interface_t IOUSBInterfaceInterface550
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID550
-#define InterfaceVersion 550
-
-#elif defined (kIOUSBInterfaceInterfaceID500)
-
-#define usb_interface_t IOUSBInterfaceInterface500
-#define InterfaceInterfaceID kIOUSBInterfaceInterfaceID500
-#define InterfaceVersion 500
-
-#elif 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
-
-#else
-
-#error "IOUSBFamily is too old. Please upgrade your OS"
-
-#endif
-
-/* IOUSBDeviceInterface */
-#if defined (kIOUSBDeviceInterfaceID500) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
-
-#define usb_device_t IOUSBDeviceInterface500
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID500
-#define DeviceVersion 500
-
-#elif 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 (kIOUSBDeviceInterfaceID220)
-#define usb_device_t IOUSBDeviceInterface197
-#define DeviceInterfaceID kIOUSBDeviceInterfaceID197
-#define DeviceVersion 197
-
-#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_cached_device {
- struct list_head list;
- IOUSBDeviceDescriptor dev_descriptor;
- UInt32 location;
- UInt64 parent_session;
- UInt64 session;
- UInt16 address;
- char sys_path[21];
- usb_device_t **device;
- int open_count;
- UInt8 first_config, active_config, port;
- int can_enumerate;
- int refcount;
-};
-
-struct darwin_device_priv {
- struct darwin_cached_device *dev;
-};
-
-struct darwin_device_handle_priv {
- int is_open;
- CFRunLoopSourceRef cfSource;
-
- 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;
- int num_iso_packets;
-
- /* Control */
- IOUSBDevRequestTO req;
-
- /* Bulk */
-
- /* Completion status */
- IOReturn result;
- UInt32 size;
-};
-
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp b/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp
deleted file mode 100644
index e0c7713..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_pollfs.cpp
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright 2007-2008, Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- * Michael Lotz <mmlr@mlotz.ch>
- */
-
-#include "haiku_usb.h"
-#include <cstdio>
-#include <Directory.h>
-#include <Entry.h>
-#include <Looper.h>
-#include <Messenger.h>
-#include <Node.h>
-#include <NodeMonitor.h>
-#include <Path.h>
-#include <cstring>
-
-class WatchedEntry {
-public:
- WatchedEntry(BMessenger *, entry_ref *);
- ~WatchedEntry();
- bool EntryCreated(entry_ref *ref);
- bool EntryRemoved(ino_t node);
- bool InitCheck();
-
-private:
- BMessenger* fMessenger;
- node_ref fNode;
- bool fIsDirectory;
- USBDevice* fDevice;
- WatchedEntry* fEntries;
- WatchedEntry* fLink;
- bool fInitCheck;
-};
-
-
-class RosterLooper : public BLooper {
-public:
- RosterLooper(USBRoster *);
- void Stop();
- virtual void MessageReceived(BMessage *);
- bool InitCheck();
-
-private:
- USBRoster* fRoster;
- WatchedEntry* fRoot;
- BMessenger* fMessenger;
- bool fInitCheck;
-};
-
-
-WatchedEntry::WatchedEntry(BMessenger *messenger, entry_ref *ref)
- : fMessenger(messenger),
- fIsDirectory(false),
- fDevice(NULL),
- fEntries(NULL),
- fLink(NULL),
- fInitCheck(false)
-{
- BEntry entry(ref);
- entry.GetNodeRef(&fNode);
-
- BDirectory directory;
- if (entry.IsDirectory() && directory.SetTo(ref) >= B_OK) {
- fIsDirectory = true;
-
- while (directory.GetNextEntry(&entry) >= B_OK) {
- if (entry.GetRef(ref) < B_OK)
- continue;
-
- WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
- if (child == NULL)
- continue;
- if (child->InitCheck() == false) {
- delete child;
- continue;
- }
-
- child->fLink = fEntries;
- fEntries = child;
- }
-
- watch_node(&fNode, B_WATCH_DIRECTORY, *fMessenger);
- }
- else {
- if (strncmp(ref->name, "raw", 3) == 0)
- return;
-
- BPath path, parent_path;
- entry.GetPath(&path);
- fDevice = new(std::nothrow) USBDevice(path.Path());
- if (fDevice != NULL && fDevice->InitCheck() == true) {
- // Add this new device to each active context's device list
- struct libusb_context *ctx;
- unsigned long session_id = (unsigned long)&fDevice;
-
- usbi_mutex_lock(&active_contexts_lock);
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- struct libusb_device *dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev) {
- usbi_dbg("using previously allocated device with location %lu", session_id);
- libusb_unref_device(dev);
- continue;
- }
- usbi_dbg("allocating new device with location %lu", session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (!dev) {
- usbi_dbg("device allocation failed");
- continue;
- }
- *((USBDevice **)dev->os_priv) = fDevice;
-
- // Calculate pseudo-device-address
- int addr, tmp;
- if (strcmp(path.Leaf(), "hub") == 0)
- tmp = 100; //Random Number
- else
- sscanf(path.Leaf(), "%d", &tmp);
- addr = tmp + 1;
- path.GetParent(&parent_path);
- while (strcmp(parent_path.Leaf(), "usb") != 0) {
- sscanf(parent_path.Leaf(), "%d", &tmp);
- addr += tmp + 1;
- parent_path.GetParent(&parent_path);
- }
- sscanf(path.Path(), "/dev/bus/usb/%d", &dev->bus_number);
- dev->device_address = addr - (dev->bus_number + 1);
-
- if (usbi_sanitize_device(dev) < 0) {
- usbi_dbg("device sanitization failed");
- libusb_unref_device(dev);
- continue;
- }
- usbi_connect_device(dev);
- }
- usbi_mutex_unlock(&active_contexts_lock);
- }
- else if (fDevice) {
- delete fDevice;
- fDevice = NULL;
- return;
- }
- }
- fInitCheck = true;
-}
-
-
-WatchedEntry::~WatchedEntry()
-{
- if (fIsDirectory) {
- watch_node(&fNode, B_STOP_WATCHING, *fMessenger);
-
- WatchedEntry *child = fEntries;
- while (child) {
- WatchedEntry *next = child->fLink;
- delete child;
- child = next;
- }
- }
-
- if (fDevice) {
- // Remove this device from each active context's device list
- struct libusb_context *ctx;
- struct libusb_device *dev;
- unsigned long session_id = (unsigned long)&fDevice;
-
- usbi_mutex_lock(&active_contexts_lock);
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev != NULL) {
- usbi_disconnect_device(dev);
- libusb_unref_device(dev);
- } else {
- usbi_dbg("device with location %lu not found", session_id);
- }
- }
- usbi_mutex_static_unlock(&active_contexts_lock);
- delete fDevice;
- }
-}
-
-
-bool
-WatchedEntry::EntryCreated(entry_ref *ref)
-{
- if (!fIsDirectory)
- return false;
-
- if (ref->directory != fNode.node) {
- WatchedEntry *child = fEntries;
- while (child) {
- if (child->EntryCreated(ref))
- return true;
- child = child->fLink;
- }
- return false;
- }
-
- WatchedEntry *child = new(std::nothrow) WatchedEntry(fMessenger, ref);
- if (child == NULL)
- return false;
- child->fLink = fEntries;
- fEntries = child;
- return true;
-}
-
-
-bool
-WatchedEntry::EntryRemoved(ino_t node)
-{
- if (!fIsDirectory)
- return false;
-
- WatchedEntry *child = fEntries;
- WatchedEntry *lastChild = NULL;
- while (child) {
- if (child->fNode.node == node) {
- if (lastChild)
- lastChild->fLink = child->fLink;
- else
- fEntries = child->fLink;
- delete child;
- return true;
- }
-
- if (child->EntryRemoved(node))
- return true;
-
- lastChild = child;
- child = child->fLink;
- }
- return false;
-}
-
-
-bool
-WatchedEntry::InitCheck()
-{
- return fInitCheck;
-}
-
-
-RosterLooper::RosterLooper(USBRoster *roster)
- : BLooper("LibusbRoster Looper"),
- fRoster(roster),
- fRoot(NULL),
- fMessenger(NULL),
- fInitCheck(false)
-{
- BEntry entry("/dev/bus/usb");
- if (!entry.Exists()) {
- usbi_err(NULL, "usb_raw not published");
- return;
- }
-
- Run();
- fMessenger = new(std::nothrow) BMessenger(this);
- if (fMessenger == NULL) {
- usbi_err(NULL, "error creating BMessenger object");
- return;
- }
-
- if (Lock()) {
- entry_ref ref;
- entry.GetRef(&ref);
- fRoot = new(std::nothrow) WatchedEntry(fMessenger, &ref);
- Unlock();
- if (fRoot == NULL)
- return;
- if (fRoot->InitCheck() == false) {
- delete fRoot;
- fRoot = NULL;
- return;
- }
- }
- fInitCheck = true;
-}
-
-
-void
-RosterLooper::Stop()
-{
- Lock();
- delete fRoot;
- delete fMessenger;
- Quit();
-}
-
-
-void
-RosterLooper::MessageReceived(BMessage *message)
-{
- int32 opcode;
- if (message->FindInt32("opcode", &opcode) < B_OK)
- return;
-
- switch (opcode) {
- case B_ENTRY_CREATED:
- {
- dev_t device;
- ino_t directory;
- const char *name;
- if (message->FindInt32("device", &device) < B_OK ||
- message->FindInt64("directory", &directory) < B_OK ||
- message->FindString("name", &name) < B_OK)
- break;
-
- entry_ref ref(device, directory, name);
- fRoot->EntryCreated(&ref);
- break;
- }
- case B_ENTRY_REMOVED:
- {
- ino_t node;
- if (message->FindInt64("node", &node) < B_OK)
- break;
- fRoot->EntryRemoved(node);
- break;
- }
- }
-}
-
-
-bool
-RosterLooper::InitCheck()
-{
- return fInitCheck;
-}
-
-
-USBRoster::USBRoster()
- : fLooper(NULL)
-{
-}
-
-
-USBRoster::~USBRoster()
-{
- Stop();
-}
-
-
-int
-USBRoster::Start()
-{
- if (fLooper == NULL) {
- fLooper = new(std::nothrow) RosterLooper(this);
- if (fLooper == NULL || ((RosterLooper *)fLooper)->InitCheck() == false) {
- if (fLooper)
- fLooper = NULL;
- return LIBUSB_ERROR_OTHER;
- }
- }
- return LIBUSB_SUCCESS;
-}
-
-
-void
-USBRoster::Stop()
-{
- if (fLooper) {
- ((RosterLooper *)fLooper)->Stop();
- fLooper = NULL;
- }
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h
deleted file mode 100644
index d51ae9e..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <List.h>
-#include <Locker.h>
-#include <Autolock.h>
-#include <USBKit.h>
-#include <map>
-#include "libusbi.h"
-#include "haiku_usb_raw.h"
-
-using namespace std;
-
-class USBDevice;
-class USBDeviceHandle;
-class USBTransfer;
-
-class USBDevice {
-public:
- USBDevice(const char *);
- virtual ~USBDevice();
- const char* Location() const;
- uint8 CountConfigurations() const;
- const usb_device_descriptor* Descriptor() const;
- const usb_configuration_descriptor* ConfigurationDescriptor(uint32) const;
- const usb_configuration_descriptor* ActiveConfiguration() const;
- uint8 EndpointToIndex(uint8) const;
- uint8 EndpointToInterface(uint8) const;
- int ClaimInterface(int);
- int ReleaseInterface(int);
- int CheckInterfacesFree(int);
- int SetActiveConfiguration(int);
- int ActiveConfigurationIndex() const;
- bool InitCheck();
-private:
- int Initialise();
- unsigned int fClaimedInterfaces; // Max Interfaces can be 32. Using a bitmask
- usb_device_descriptor fDeviceDescriptor;
- unsigned char** fConfigurationDescriptors;
- int fActiveConfiguration;
- char* fPath;
- map<uint8,uint8> fConfigToIndex;
- map<uint8,uint8>* fEndpointToIndex;
- map<uint8,uint8>* fEndpointToInterface;
- bool fInitCheck;
-};
-
-class USBDeviceHandle {
-public:
- USBDeviceHandle(USBDevice *dev);
- virtual ~USBDeviceHandle();
- int ClaimInterface(int);
- int ReleaseInterface(int);
- int SetConfiguration(int);
- int SetAltSetting(int, int);
- status_t SubmitTransfer(struct usbi_transfer *);
- status_t CancelTransfer(USBTransfer *);
- bool InitCheck();
-private:
- int fRawFD;
- static status_t TransfersThread(void *);
- void TransfersWorker();
- USBDevice* fUSBDevice;
- unsigned int fClaimedInterfaces;
- BList fTransfers;
- BLocker fTransfersLock;
- sem_id fTransfersSem;
- thread_id fTransfersThread;
- bool fInitCheck;
-};
-
-class USBTransfer {
-public:
- USBTransfer(struct usbi_transfer *, USBDevice *);
- virtual ~USBTransfer();
- void Do(int);
- struct usbi_transfer* UsbiTransfer();
- void SetCancelled();
- bool IsCancelled();
-private:
- struct usbi_transfer* fUsbiTransfer;
- struct libusb_transfer* fLibusbTransfer;
- USBDevice* fUSBDevice;
- BLocker fStatusLock;
- bool fCancelled;
-};
-
-class USBRoster {
-public:
- USBRoster();
- virtual ~USBRoster();
- int Start();
- void Stop();
-private:
- void* fLooper;
-};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp b/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp
deleted file mode 100644
index d3de8cc..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_backend.cpp
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <new>
-#include <vector>
-
-#include "haiku_usb.h"
-
-int _errno_to_libusb(int status)
-{
- return status;
-}
-
-USBTransfer::USBTransfer(struct usbi_transfer *itransfer, USBDevice *device)
-{
- fUsbiTransfer = itransfer;
- fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- fUSBDevice = device;
- fCancelled = false;
-}
-
-USBTransfer::~USBTransfer()
-{
-}
-
-struct usbi_transfer *
-USBTransfer::UsbiTransfer()
-{
- return fUsbiTransfer;
-}
-
-void
-USBTransfer::SetCancelled()
-{
- fCancelled = true;
-}
-
-bool
-USBTransfer::IsCancelled()
-{
- return fCancelled;
-}
-
-void
-USBTransfer::Do(int fRawFD)
-{
- switch (fLibusbTransfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- {
- struct libusb_control_setup *setup = (struct libusb_control_setup *)fLibusbTransfer->buffer;
- usb_raw_command command;
- command.control.request_type = setup->bmRequestType;
- command.control.request = setup->bRequest;
- command.control.value = setup->wValue;
- command.control.index = setup->wIndex;
- command.control.length = setup->wLength;
- command.control.data = fLibusbTransfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
- if (fCancelled)
- break;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
- command.control.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed control transfer");
- break;
- }
- fUsbiTransfer->transferred = command.control.length;
- }
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- {
- usb_raw_command command;
- command.transfer.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
- command.transfer.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
- command.transfer.data = fLibusbTransfer->buffer;
- command.transfer.length = fLibusbTransfer->length;
- if (fCancelled)
- break;
- if (fLibusbTransfer->type == LIBUSB_TRANSFER_TYPE_BULK) {
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command, sizeof(command)) ||
- command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed bulk transfer");
- break;
- }
- }
- else {
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command, sizeof(command)) ||
- command.transfer.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed interrupt transfer");
- break;
- }
- }
- fUsbiTransfer->transferred = command.transfer.length;
- }
- break;
- // IsochronousTransfers not tested
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- {
- usb_raw_command command;
- command.isochronous.interface = fUSBDevice->EndpointToInterface(fLibusbTransfer->endpoint);
- command.isochronous.endpoint = fUSBDevice->EndpointToIndex(fLibusbTransfer->endpoint);
- command.isochronous.data = fLibusbTransfer->buffer;
- command.isochronous.length = fLibusbTransfer->length;
- command.isochronous.packet_count = fLibusbTransfer->num_iso_packets;
- int i;
- usb_iso_packet_descriptor *packetDescriptors = new usb_iso_packet_descriptor[fLibusbTransfer->num_iso_packets];
- for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
- if ((int16)(fLibusbTransfer->iso_packet_desc[i]).length != (fLibusbTransfer->iso_packet_desc[i]).length) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
- break;
- }
- packetDescriptors[i].request_length = (int16)(fLibusbTransfer->iso_packet_desc[i]).length;
- }
- if (i < fLibusbTransfer->num_iso_packets)
- break; // TODO Handle this error
- command.isochronous.packet_descriptors = packetDescriptors;
- if (fCancelled)
- break;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command, sizeof(command)) ||
- command.isochronous.status != B_USB_RAW_STATUS_SUCCESS) {
- fUsbiTransfer->transferred = -1;
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "failed isochronous transfer");
- break;
- }
- for (i = 0; i < fLibusbTransfer->num_iso_packets; i++) {
- (fLibusbTransfer->iso_packet_desc[i]).actual_length = packetDescriptors[i].actual_length;
- switch (packetDescriptors[i].status) {
- case B_OK:
- (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_COMPLETED;
- break;
- default:
- (fLibusbTransfer->iso_packet_desc[i]).status = LIBUSB_TRANSFER_ERROR;
- break;
- }
- }
- delete[] packetDescriptors;
- // Do we put the length of transfer here, for isochronous transfers?
- fUsbiTransfer->transferred = command.transfer.length;
- }
- break;
- default:
- usbi_err(TRANSFER_CTX(fLibusbTransfer), "Unknown type of transfer");
- }
-}
-
-bool
-USBDeviceHandle::InitCheck()
-{
- return fInitCheck;
-}
-
-status_t
-USBDeviceHandle::TransfersThread(void *self)
-{
- USBDeviceHandle *handle = (USBDeviceHandle *)self;
- handle->TransfersWorker();
- return B_OK;
-}
-
-void
-USBDeviceHandle::TransfersWorker()
-{
- while (true) {
- status_t status = acquire_sem(fTransfersSem);
- if (status == B_BAD_SEM_ID)
- break;
- if (status == B_INTERRUPTED)
- continue;
- fTransfersLock.Lock();
- USBTransfer *fPendingTransfer = (USBTransfer *) fTransfers.RemoveItem((int32)0);
- fTransfersLock.Unlock();
- fPendingTransfer->Do(fRawFD);
- usbi_signal_transfer_completion(fPendingTransfer->UsbiTransfer());
- }
-}
-
-status_t
-USBDeviceHandle::SubmitTransfer(struct usbi_transfer *itransfer)
-{
- USBTransfer *transfer = new USBTransfer(itransfer, fUSBDevice);
- *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = transfer;
- BAutolock locker(fTransfersLock);
- fTransfers.AddItem(transfer);
- release_sem(fTransfersSem);
- return LIBUSB_SUCCESS;
-}
-
-status_t
-USBDeviceHandle::CancelTransfer(USBTransfer *transfer)
-{
- transfer->SetCancelled();
- fTransfersLock.Lock();
- bool removed = fTransfers.RemoveItem(transfer);
- fTransfersLock.Unlock();
- if(removed)
- usbi_signal_transfer_completion(transfer->UsbiTransfer());
- return LIBUSB_SUCCESS;
-}
-
-USBDeviceHandle::USBDeviceHandle(USBDevice *dev)
- :
- fTransfersThread(-1),
- fUSBDevice(dev),
- fClaimedInterfaces(0),
- fInitCheck(false)
-{
- fRawFD = open(dev->Location(), O_RDWR | O_CLOEXEC);
- if (fRawFD < 0) {
- usbi_err(NULL,"failed to open device");
- return;
- }
- fTransfersSem = create_sem(0, "Transfers Queue Sem");
- fTransfersThread = spawn_thread(TransfersThread, "Transfer Worker", B_NORMAL_PRIORITY, this);
- resume_thread(fTransfersThread);
- fInitCheck = true;
-}
-
-USBDeviceHandle::~USBDeviceHandle()
-{
- if (fRawFD > 0)
- close(fRawFD);
- for(int i = 0; i < 32; i++) {
- if (fClaimedInterfaces & (1 << i))
- ReleaseInterface(i);
- }
- delete_sem(fTransfersSem);
- if (fTransfersThread > 0)
- wait_for_thread(fTransfersThread, NULL);
-}
-
-int
-USBDeviceHandle::ClaimInterface(int inumber)
-{
- int status = fUSBDevice->ClaimInterface(inumber);
- if (status == LIBUSB_SUCCESS)
- fClaimedInterfaces |= (1 << inumber);
- return status;
-}
-
-int
-USBDeviceHandle::ReleaseInterface(int inumber)
-{
- fUSBDevice->ReleaseInterface(inumber);
- fClaimedInterfaces &= ~(1 << inumber);
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDeviceHandle::SetConfiguration(int config)
-{
- int config_index = fUSBDevice->CheckInterfacesFree(config);
- if(config_index == LIBUSB_ERROR_BUSY || config_index == LIBUSB_ERROR_NOT_FOUND)
- return config_index;
- usb_raw_command command;
- command.config.config_index = config_index;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_CONFIGURATION, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- return _errno_to_libusb(command.config.status);
- }
- fUSBDevice->SetActiveConfiguration(config_index);
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDeviceHandle::SetAltSetting(int inumber, int alt)
-{
- usb_raw_command command;
- command.alternate.config_index = fUSBDevice->ActiveConfigurationIndex();
- command.alternate.interface_index = inumber;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command, sizeof(command)) ||
- command.alternate.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "Error retrieving active alternate interface");
- return _errno_to_libusb(command.alternate.status);
- }
- if (command.alternate.alternate_info == alt) {
- usbi_dbg("Setting alternate interface successful");
- return LIBUSB_SUCCESS;
- }
- command.alternate.alternate_info = alt;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command, sizeof(command)) ||
- command.alternate.status != B_USB_RAW_STATUS_SUCCESS) { //IF IOCTL FAILS DEVICE DISONNECTED PROBABLY
- usbi_err(NULL, "Error setting alternate interface");
- return _errno_to_libusb(command.alternate.status);
- }
- usbi_dbg("Setting alternate interface successful");
- return LIBUSB_SUCCESS;
-}
-
-
-USBDevice::USBDevice(const char *path)
- :
- fPath(NULL),
- fActiveConfiguration(0), //0?
- fConfigurationDescriptors(NULL),
- fClaimedInterfaces(0),
- fEndpointToIndex(NULL),
- fEndpointToInterface(NULL),
- fInitCheck(false)
-{
- fPath=strdup(path);
- Initialise();
-}
-
-USBDevice::~USBDevice()
-{
- free(fPath);
- if (fConfigurationDescriptors) {
- for(int i = 0; i < fDeviceDescriptor.num_configurations; i++) {
- if (fConfigurationDescriptors[i])
- delete fConfigurationDescriptors[i];
- }
- delete[] fConfigurationDescriptors;
- }
- if (fEndpointToIndex)
- delete[] fEndpointToIndex;
- if (fEndpointToInterface)
- delete[] fEndpointToInterface;
-}
-
-bool
-USBDevice::InitCheck()
-{
- return fInitCheck;
-}
-
-const char *
-USBDevice::Location() const
-{
- return fPath;
-}
-
-uint8
-USBDevice::CountConfigurations() const
-{
- return fDeviceDescriptor.num_configurations;
-}
-
-const usb_device_descriptor *
-USBDevice::Descriptor() const
-{
- return &fDeviceDescriptor;
-}
-
-const usb_configuration_descriptor *
-USBDevice::ConfigurationDescriptor(uint32 index) const
-{
- if (index > CountConfigurations())
- return NULL;
- return (usb_configuration_descriptor *) fConfigurationDescriptors[index];
-}
-
-const usb_configuration_descriptor *
-USBDevice::ActiveConfiguration() const
-{
- return (usb_configuration_descriptor *) fConfigurationDescriptors[fActiveConfiguration];
-}
-
-int
-USBDevice::ActiveConfigurationIndex() const
-{
- return fActiveConfiguration;
-}
-
-int USBDevice::ClaimInterface(int interface)
-{
- if (interface > ActiveConfiguration()->number_interfaces)
- return LIBUSB_ERROR_NOT_FOUND;
- if (fClaimedInterfaces & (1 << interface))
- return LIBUSB_ERROR_BUSY;
- fClaimedInterfaces |= (1 << interface);
- return LIBUSB_SUCCESS;
-}
-
-int USBDevice::ReleaseInterface(int interface)
-{
- fClaimedInterfaces &= ~(1 << interface);
- return LIBUSB_SUCCESS;
-}
-
-int
-USBDevice::CheckInterfacesFree(int config)
-{
- if (fConfigToIndex.count(config) == 0)
- return LIBUSB_ERROR_NOT_FOUND;
- if (fClaimedInterfaces == 0)
- return fConfigToIndex[(uint8)config];
- return LIBUSB_ERROR_BUSY;
-}
-
-int
-USBDevice::SetActiveConfiguration(int config_index)
-{
- fActiveConfiguration = config_index;
- return LIBUSB_SUCCESS;
-}
-
-uint8
-USBDevice::EndpointToIndex(uint8 address) const
-{
- return fEndpointToIndex[fActiveConfiguration][address];
-}
-
-uint8
-USBDevice::EndpointToInterface(uint8 address) const
-{
- return fEndpointToInterface[fActiveConfiguration][address];
-}
-
-int
-USBDevice::Initialise() //Do we need more error checking, etc? How to report?
-{
- int fRawFD = open(fPath, O_RDWR | O_CLOEXEC);
- if (fRawFD < 0)
- return B_ERROR;
- usb_raw_command command;
- command.device.descriptor = &fDeviceDescriptor;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR, &command, sizeof(command)) ||
- command.device.status != B_USB_RAW_STATUS_SUCCESS) {
- close(fRawFD);
- return B_ERROR;
- }
-
- fConfigurationDescriptors = new(std::nothrow) unsigned char *[fDeviceDescriptor.num_configurations];
- fEndpointToIndex = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
- fEndpointToInterface = new(std::nothrow) map<uint8,uint8> [fDeviceDescriptor.num_configurations];
- for (int i = 0; i < fDeviceDescriptor.num_configurations; i++) {
- usb_configuration_descriptor tmp_config;
- command.config.descriptor = &tmp_config;
- command.config.config_index = i;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving configuration descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- fConfigToIndex[tmp_config.configuration_value] = i;
- fConfigurationDescriptors[i] = new(std::nothrow) unsigned char[tmp_config.total_length];
- command.control.request_type = 128;
- command.control.request = 6;
- command.control.value = (2 << 8) | i;
- command.control.index = 0;
- command.control.length = tmp_config.total_length;
- command.control.data = fConfigurationDescriptors[i];
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command, sizeof(command)) ||
- command.control.status!=B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving full configuration descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- for (int j = 0; j < tmp_config.number_interfaces; j++) {
- command.alternate.config_index = i;
- command.alternate.interface_index = j;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving number of alternate interfaces");
- close(fRawFD);
- return B_ERROR;
- }
- int num_alternate = command.alternate.alternate_info;
- for (int k = 0; k < num_alternate; k++) {
- usb_interface_descriptor tmp_interface;
- command.interface_etc.config_index = i;
- command.interface_etc.interface_index = j;
- command.interface_etc.alternate_index = k;
- command.interface_etc.descriptor = &tmp_interface;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving interface descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- for (int l = 0; l < tmp_interface.num_endpoints; l++) {
- usb_endpoint_descriptor tmp_endpoint;
- command.endpoint_etc.config_index = i;
- command.endpoint_etc.interface_index = j;
- command.endpoint_etc.alternate_index = k;
- command.endpoint_etc.endpoint_index = l;
- command.endpoint_etc.descriptor = &tmp_endpoint;
- if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command, sizeof(command)) ||
- command.config.status != B_USB_RAW_STATUS_SUCCESS) {
- usbi_err(NULL, "failed retrieving endpoint descriptor");
- close(fRawFD);
- return B_ERROR;
- }
- fEndpointToIndex[i][tmp_endpoint.endpoint_address] = l;
- fEndpointToInterface[i][tmp_endpoint.endpoint_address] = j;
- }
- }
- }
- }
- close(fRawFD);
- fInitCheck = true;
- return B_OK;
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp b/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp
deleted file mode 100644
index 77adbd1..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Haiku Backend for libusb
- * Copyright © 2014 Akshay Jaggi <akshay1994.leo@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 <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <new>
-#include <vector>
-
-#include "haiku_usb.h"
-
-USBRoster gUsbRoster;
-int32 gInitCount = 0;
-
-static int
-haiku_init(struct libusb_context *ctx)
-{
- if (atomic_add(&gInitCount, 1) == 0)
- return gUsbRoster.Start();
- return LIBUSB_SUCCESS;
-}
-
-static void
-haiku_exit(void)
-{
- if (atomic_add(&gInitCount, -1) == 1)
- gUsbRoster.Stop();
-}
-
-static int
-haiku_open(struct libusb_device_handle *dev_handle)
-{
- USBDevice *dev = *((USBDevice **)dev_handle->dev->os_priv);
- USBDeviceHandle *handle = new(std::nothrow) USBDeviceHandle(dev);
- if (handle == NULL)
- return LIBUSB_ERROR_NO_MEM;
- if (handle->InitCheck() == false) {
- delete handle;
- return LIBUSB_ERROR_NO_DEVICE;
- }
- *((USBDeviceHandle **)dev_handle->os_priv) = handle;
- return LIBUSB_SUCCESS;
-}
-
-static void
-haiku_close(struct libusb_device_handle *dev_handle)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
- if (handle == NULL)
- return;
- delete handle;
- *((USBDeviceHandle **)dev_handle->os_priv) = NULL;
-}
-
-static int
-haiku_get_device_descriptor(struct libusb_device *device, unsigned char *buffer, int *host_endian)
-{
- USBDevice *dev = *((USBDevice **)device->os_priv);
- memcpy(buffer, dev->Descriptor(), DEVICE_DESC_LENGTH);
- *host_endian = 0;
- return LIBUSB_SUCCESS;
-}
-
-static int
-haiku_get_active_config_descriptor(struct libusb_device *device, unsigned char *buffer, size_t len, int *host_endian)
-{
- USBDevice *dev = *((USBDevice **)device->os_priv);
- const usb_configuration_descriptor *act_config = dev->ActiveConfiguration();
- if (len > act_config->total_length)
- return LIBUSB_ERROR_OVERFLOW;
- memcpy(buffer, act_config, len);
- *host_endian = 0;
- return LIBUSB_SUCCESS;
-}
-
-static int
-haiku_get_config_descriptor(struct libusb_device *device, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
-{
- USBDevice *dev = *((USBDevice **)device->os_priv);
- const usb_configuration_descriptor *config = dev->ConfigurationDescriptor(config_index);
- if (config == NULL) {
- usbi_err(DEVICE_CTX(device), "failed getting configuration descriptor");
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- if (len > config->total_length)
- len = config->total_length;
- memcpy(buffer, config, len);
- *host_endian = 0;
- return len;
-}
-
-static int
-haiku_set_configuration(struct libusb_device_handle *dev_handle, int config)
-{
- USBDeviceHandle *handle= *((USBDeviceHandle **)dev_handle->os_priv);
- return handle->SetConfiguration(config);
-}
-
-static int
-haiku_claim_interface(struct libusb_device_handle *dev_handle, int interface_number)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
- return handle->ClaimInterface(interface_number);
-}
-
-static int
-haiku_set_altsetting(struct libusb_device_handle *dev_handle, int interface_number, int altsetting)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
- return handle->SetAltSetting(interface_number, altsetting);
-}
-
-static int
-haiku_release_interface(struct libusb_device_handle *dev_handle, int interface_number)
-{
- USBDeviceHandle *handle = *((USBDeviceHandle **)dev_handle->os_priv);
- haiku_set_altsetting(dev_handle,interface_number, 0);
- return handle->ReleaseInterface(interface_number);
-}
-
-static int
-haiku_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv);
- return fDeviceHandle->SubmitTransfer(itransfer);
-}
-
-static int
-haiku_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *fLibusbTransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- USBDeviceHandle *fDeviceHandle = *((USBDeviceHandle **)fLibusbTransfer->dev_handle->os_priv);
- return fDeviceHandle->CancelTransfer(*((USBTransfer **)usbi_transfer_get_os_priv(itransfer)));
-}
-
-static void
-haiku_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
- delete transfer;
- *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
-}
-
-static int
-haiku_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- USBTransfer *transfer = *((USBTransfer **)usbi_transfer_get_os_priv(itransfer));
-
- usbi_mutex_lock(&itransfer->lock);
- if (transfer->IsCancelled()) {
- delete transfer;
- *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
- usbi_mutex_unlock(&itransfer->lock);
- if (itransfer->transferred < 0)
- itransfer->transferred = 0;
- return usbi_handle_transfer_cancellation(itransfer);
- }
- libusb_transfer_status status = LIBUSB_TRANSFER_COMPLETED;
- if (itransfer->transferred < 0) {
- usbi_err(ITRANSFER_CTX(itransfer), "error in transfer");
- status = LIBUSB_TRANSFER_ERROR;
- itransfer->transferred = 0;
- }
- delete transfer;
- *((USBTransfer **)usbi_transfer_get_os_priv(itransfer)) = NULL;
- usbi_mutex_unlock(&itransfer->lock);
- return usbi_handle_transfer_completion(itransfer, status);
-}
-
-static int
-haiku_clock_gettime(int clkid, struct timespec *tp)
-{
- if (clkid == USBI_CLOCK_REALTIME)
- return clock_gettime(CLOCK_REALTIME, tp);
- if (clkid == USBI_CLOCK_MONOTONIC)
- return clock_gettime(CLOCK_MONOTONIC, tp);
- return LIBUSB_ERROR_INVALID_PARAM;
-}
-
-const struct usbi_os_backend haiku_usb_raw_backend = {
- /*.name =*/ "Haiku usbfs",
- /*.caps =*/ 0,
- /*.init =*/ haiku_init,
- /*.exit =*/ haiku_exit,
- /*.get_device_list =*/ NULL,
- /*.hotplug_poll =*/ NULL,
- /*.open =*/ haiku_open,
- /*.close =*/ haiku_close,
- /*.get_device_descriptor =*/ haiku_get_device_descriptor,
- /*.get_active_config_descriptor =*/ haiku_get_active_config_descriptor,
- /*.get_config_descriptor =*/ haiku_get_config_descriptor,
- /*.get_config_descriptor_by_value =*/ NULL,
-
-
- /*.get_configuration =*/ NULL,
- /*.set_configuration =*/ haiku_set_configuration,
- /*.claim_interface =*/ haiku_claim_interface,
- /*.release_interface =*/ haiku_release_interface,
-
- /*.set_interface_altsetting =*/ haiku_set_altsetting,
- /*.clear_halt =*/ NULL,
- /*.reset_device =*/ NULL,
-
- /*.alloc_streams =*/ NULL,
- /*.free_streams =*/ NULL,
-
- /*.dev_mem_alloc =*/ NULL,
- /*.dev_mem_free =*/ NULL,
-
- /*.kernel_driver_active =*/ NULL,
- /*.detach_kernel_driver =*/ NULL,
- /*.attach_kernel_driver =*/ NULL,
-
- /*.destroy_device =*/ NULL,
-
- /*.submit_transfer =*/ haiku_submit_transfer,
- /*.cancel_transfer =*/ haiku_cancel_transfer,
- /*.clear_transfer_priv =*/ haiku_clear_transfer_priv,
-
- /*.handle_events =*/ NULL,
- /*.handle_transfer_completion =*/ haiku_handle_transfer_completion,
-
- /*.clock_gettime =*/ haiku_clock_gettime,
-
-#ifdef USBI_TIMERFD_AVAILABLE
- /*.get_timerfd_clockid =*/ NULL,
-#endif
-
- /*.device_priv_size =*/ sizeof(USBDevice *),
- /*.device_handle_priv_size =*/ sizeof(USBDeviceHandle *),
- /*.transfer_priv_size =*/ sizeof(USBTransfer *),
-};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h
deleted file mode 100644
index 5baf53d..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/haiku_usb_raw.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2006-2008, Haiku Inc. All rights reserved.
- * Distributed under the terms of the MIT License.
- */
-
-#ifndef _USB_RAW_H_
-#define _USB_RAW_H_
-
-#include <USB3.h>
-
-#define B_USB_RAW_PROTOCOL_VERSION 0x0015
-#define B_USB_RAW_ACTIVE_ALTERNATE 0xffffffff
-
-typedef enum {
- B_USB_RAW_COMMAND_GET_VERSION = 0x1000,
-
- B_USB_RAW_COMMAND_GET_DEVICE_DESCRIPTOR = 0x2000,
- B_USB_RAW_COMMAND_GET_CONFIGURATION_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_STRING_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR,
- B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT,
- B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX,
- B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC,
- B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC,
- B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC,
-
- B_USB_RAW_COMMAND_SET_CONFIGURATION = 0x3000,
- B_USB_RAW_COMMAND_SET_FEATURE,
- B_USB_RAW_COMMAND_CLEAR_FEATURE,
- B_USB_RAW_COMMAND_GET_STATUS,
- B_USB_RAW_COMMAND_GET_DESCRIPTOR,
- B_USB_RAW_COMMAND_SET_ALT_INTERFACE,
-
- B_USB_RAW_COMMAND_CONTROL_TRANSFER = 0x4000,
- B_USB_RAW_COMMAND_INTERRUPT_TRANSFER,
- B_USB_RAW_COMMAND_BULK_TRANSFER,
- B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER
-} usb_raw_command_id;
-
-
-typedef enum {
- B_USB_RAW_STATUS_SUCCESS = 0,
-
- B_USB_RAW_STATUS_FAILED,
- B_USB_RAW_STATUS_ABORTED,
- B_USB_RAW_STATUS_STALLED,
- B_USB_RAW_STATUS_CRC_ERROR,
- B_USB_RAW_STATUS_TIMEOUT,
-
- B_USB_RAW_STATUS_INVALID_CONFIGURATION,
- B_USB_RAW_STATUS_INVALID_INTERFACE,
- B_USB_RAW_STATUS_INVALID_ENDPOINT,
- B_USB_RAW_STATUS_INVALID_STRING,
-
- B_USB_RAW_STATUS_NO_MEMORY
-} usb_raw_command_status;
-
-
-typedef union {
- struct {
- status_t status;
- } version;
-
- struct {
- status_t status;
- usb_device_descriptor *descriptor;
- } device;
-
- struct {
- status_t status;
- usb_configuration_descriptor *descriptor;
- uint32 config_index;
- } config;
-
- struct {
- status_t status;
- uint32 alternate_info;
- uint32 config_index;
- uint32 interface_index;
- } alternate;
-
- struct {
- status_t status;
- usb_interface_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- } interface;
-
- struct {
- status_t status;
- usb_interface_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 alternate_index;
- } interface_etc;
-
- struct {
- status_t status;
- usb_endpoint_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 endpoint_index;
- } endpoint;
-
- struct {
- status_t status;
- usb_endpoint_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 alternate_index;
- uint32 endpoint_index;
- } endpoint_etc;
-
- struct {
- status_t status;
- usb_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 generic_index;
- size_t length;
- } generic;
-
- struct {
- status_t status;
- usb_descriptor *descriptor;
- uint32 config_index;
- uint32 interface_index;
- uint32 alternate_index;
- uint32 generic_index;
- size_t length;
- } generic_etc;
-
- struct {
- status_t status;
- usb_string_descriptor *descriptor;
- uint32 string_index;
- size_t length;
- } string;
-
- struct {
- status_t status;
- uint8 type;
- uint8 index;
- uint16 language_id;
- void *data;
- size_t length;
- } descriptor;
-
- struct {
- status_t status;
- uint8 request_type;
- uint8 request;
- uint16 value;
- uint16 index;
- uint16 length;
- void *data;
- } control;
-
- struct {
- status_t status;
- uint32 interface;
- uint32 endpoint;
- void *data;
- size_t length;
- } transfer;
-
- struct {
- status_t status;
- uint32 interface;
- uint32 endpoint;
- void *data;
- size_t length;
- usb_iso_packet_descriptor *packet_descriptors;
- uint32 packet_count;
- } isochronous;
-} usb_raw_command;
-
-#endif // _USB_RAW_H_
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c
deleted file mode 100644
index 60cf3ad..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_netlink.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
-/*
- * Linux usbfs backend for libusb
- * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
- * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright (c) 2016 Chris Dickens <christopher.a.dickens@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 <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#ifdef HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#include "libusbi.h"
-#include "linux_usbfs.h"
-
-#define NL_GROUP_KERNEL 1
-
-static int linux_netlink_socket = -1;
-static int netlink_control_pipe[2] = { -1, -1 };
-static pthread_t libusb_linux_event_thread;
-
-static void *linux_netlink_event_thread_main(void *arg);
-
-static int set_fd_cloexec_nb(int fd)
-{
- int flags;
-
-#if defined(FD_CLOEXEC)
- flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
- return -1;
- }
-
- if (!(flags & FD_CLOEXEC)) {
- if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
- usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
- return -1;
- }
- }
-#endif
-
- flags = fcntl(fd, F_GETFL);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
- return -1;
- }
-
- if (!(flags & O_NONBLOCK)) {
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
- usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
- return -1;
- }
- }
-
- return 0;
-}
-
-int linux_netlink_start_event_monitor(void)
-{
- struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
- int socktype = SOCK_RAW;
- int opt = 1;
- int ret;
-
-#if defined(SOCK_CLOEXEC)
- socktype |= SOCK_CLOEXEC;
-#endif
-#if defined(SOCK_NONBLOCK)
- socktype |= SOCK_NONBLOCK;
-#endif
-
- linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
- if (linux_netlink_socket == -1 && errno == EINVAL) {
- usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
- linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
- }
-
- if (linux_netlink_socket == -1) {
- usbi_err(NULL, "failed to create netlink socket (%d)", errno);
- goto err;
- }
-
- ret = set_fd_cloexec_nb(linux_netlink_socket);
- if (ret == -1)
- goto err_close_socket;
-
- ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
- if (ret == -1) {
- usbi_err(NULL, "failed to bind netlink socket (%d)", errno);
- goto err_close_socket;
- }
-
- ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
- if (ret == -1) {
- usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option (%d)", errno);
- goto err_close_socket;
- }
-
- ret = usbi_pipe(netlink_control_pipe);
- if (ret) {
- usbi_err(NULL, "failed to create netlink control pipe");
- goto err_close_socket;
- }
-
- ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
- if (ret != 0) {
- usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
- goto err_close_pipe;
- }
-
- return LIBUSB_SUCCESS;
-
-err_close_pipe:
- close(netlink_control_pipe[0]);
- close(netlink_control_pipe[1]);
- netlink_control_pipe[0] = -1;
- netlink_control_pipe[1] = -1;
-err_close_socket:
- close(linux_netlink_socket);
- linux_netlink_socket = -1;
-err:
- return LIBUSB_ERROR_OTHER;
-}
-
-int linux_netlink_stop_event_monitor(void)
-{
- char dummy = 1;
- ssize_t r;
-
- assert(linux_netlink_socket != -1);
-
- /* Write some dummy data to the control pipe and
- * wait for the thread to exit */
- r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy));
- if (r <= 0)
- usbi_warn(NULL, "netlink control pipe signal failed");
-
- pthread_join(libusb_linux_event_thread, NULL);
-
- close(linux_netlink_socket);
- linux_netlink_socket = -1;
-
- /* close and reset control pipe */
- close(netlink_control_pipe[0]);
- close(netlink_control_pipe[1]);
- netlink_control_pipe[0] = -1;
- netlink_control_pipe[1] = -1;
-
- return LIBUSB_SUCCESS;
-}
-
-static const char *netlink_message_parse(const char *buffer, size_t len, const char *key)
-{
- const char *end = buffer + len;
- size_t keylen = strlen(key);
-
- while (buffer < end && *buffer) {
- if (strncmp(buffer, key, keylen) == 0 && buffer[keylen] == '=')
- return buffer + keylen + 1;
- buffer += strlen(buffer) + 1;
- }
-
- return NULL;
-}
-
-/* parse parts of netlink message common to both libudev and the kernel */
-static int linux_netlink_parse(const char *buffer, size_t len, int *detached,
- const char **sys_name, uint8_t *busnum, uint8_t *devaddr)
-{
- const char *tmp, *slash;
-
- errno = 0;
-
- *sys_name = NULL;
- *detached = 0;
- *busnum = 0;
- *devaddr = 0;
-
- tmp = netlink_message_parse(buffer, len, "ACTION");
- if (!tmp) {
- return -1;
- } else if (strcmp(tmp, "remove") == 0) {
- *detached = 1;
- } else if (strcmp(tmp, "add") != 0) {
- usbi_dbg("unknown device action %s", tmp);
- return -1;
- }
-
- /* check that this is a usb message */
- tmp = netlink_message_parse(buffer, len, "SUBSYSTEM");
- if (!tmp || strcmp(tmp, "usb") != 0) {
- /* not usb. ignore */
- return -1;
- }
-
- /* check that this is an actual usb device */
- tmp = netlink_message_parse(buffer, len, "DEVTYPE");
- if (!tmp || strcmp(tmp, "usb_device") != 0) {
- /* not usb. ignore */
- return -1;
- }
-
- tmp = netlink_message_parse(buffer, len, "BUSNUM");
- if (tmp) {
- *busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
-
- tmp = netlink_message_parse(buffer, len, "DEVNUM");
- if (NULL == tmp)
- return -1;
-
- *devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
- } else {
- /* no bus number. try "DEVICE" */
- tmp = netlink_message_parse(buffer, len, "DEVICE");
- if (!tmp) {
- /* not usb. ignore */
- return -1;
- }
-
- /* Parse a device path such as /dev/bus/usb/003/004 */
- slash = strrchr(tmp, '/');
- if (!slash)
- return -1;
-
- *busnum = (uint8_t)(strtoul(slash - 3, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
-
- *devaddr = (uint8_t)(strtoul(slash + 1, NULL, 10) & 0xff);
- if (errno) {
- errno = 0;
- return -1;
- }
-
- return 0;
- }
-
- tmp = netlink_message_parse(buffer, len, "DEVPATH");
- if (!tmp)
- return -1;
-
- slash = strrchr(tmp, '/');
- if (slash)
- *sys_name = slash + 1;
-
- /* found a usb device */
- return 0;
-}
-
-static int linux_netlink_read_message(void)
-{
- char cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
- char msg_buffer[2048];
- const char *sys_name = NULL;
- uint8_t busnum, devaddr;
- int detached, r;
- ssize_t len;
- struct cmsghdr *cmsg;
- struct ucred *cred;
- struct sockaddr_nl sa_nl;
- struct iovec iov = { .iov_base = msg_buffer, .iov_len = sizeof(msg_buffer) };
- struct msghdr msg = {
- .msg_iov = &iov, .msg_iovlen = 1,
- .msg_control = cred_buffer, .msg_controllen = sizeof(cred_buffer),
- .msg_name = &sa_nl, .msg_namelen = sizeof(sa_nl)
- };
-
- /* read netlink message */
- len = recvmsg(linux_netlink_socket, &msg, 0);
- if (len == -1) {
- if (errno != EAGAIN && errno != EINTR)
- usbi_err(NULL, "error receiving message from netlink (%d)", errno);
- return -1;
- }
-
- if (len < 32 || (msg.msg_flags & MSG_TRUNC)) {
- usbi_err(NULL, "invalid netlink message length");
- return -1;
- }
-
- if (sa_nl.nl_groups != NL_GROUP_KERNEL || sa_nl.nl_pid != 0) {
- usbi_dbg("ignoring netlink message from unknown group/PID (%u/%u)",
- (unsigned int)sa_nl.nl_groups, (unsigned int)sa_nl.nl_pid);
- return -1;
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
- usbi_dbg("ignoring netlink message with no sender credentials");
- return -1;
- }
-
- cred = (struct ucred *)CMSG_DATA(cmsg);
- if (cred->uid != 0) {
- usbi_dbg("ignoring netlink message with non-zero sender UID %u", (unsigned int)cred->uid);
- return -1;
- }
-
- r = linux_netlink_parse(msg_buffer, (size_t)len, &detached, &sys_name, &busnum, &devaddr);
- if (r)
- return r;
-
- usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
- busnum, devaddr, sys_name, detached ? "yes" : "no");
-
- /* signal device is available (or not) to all contexts */
- if (detached)
- linux_device_disconnected(busnum, devaddr);
- else
- linux_hotplug_enumerate(busnum, devaddr, sys_name);
-
- return 0;
-}
-
-static void *linux_netlink_event_thread_main(void *arg)
-{
- char dummy;
- ssize_t r;
- struct pollfd fds[] = {
- { .fd = netlink_control_pipe[0],
- .events = POLLIN },
- { .fd = linux_netlink_socket,
- .events = POLLIN },
- };
-
- UNUSED(arg);
-
- usbi_dbg("netlink event thread entering");
-
- while (poll(fds, 2, -1) >= 0) {
- if (fds[0].revents & POLLIN) {
- /* activity on control pipe, read the byte and exit */
- r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy));
- if (r <= 0)
- usbi_warn(NULL, "netlink control pipe read failed");
- break;
- }
- if (fds[1].revents & POLLIN) {
- usbi_mutex_static_lock(&linux_hotplug_lock);
- linux_netlink_read_message();
- usbi_mutex_static_unlock(&linux_hotplug_lock);
- }
- }
-
- usbi_dbg("netlink event thread exiting");
-
- return NULL;
-}
-
-void linux_netlink_hotplug_poll(void)
-{
- int r;
-
- usbi_mutex_static_lock(&linux_hotplug_lock);
- do {
- r = linux_netlink_read_message();
- } while (r == 0);
- usbi_mutex_static_unlock(&linux_hotplug_lock);
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c
deleted file mode 100644
index 61d953d..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_udev.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
-/*
- * Linux usbfs backend for libusb
- * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
- * Copyright (c) 2012-2013 Nathan Hjelm <hjelmn@mac.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 <assert.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 <sys/socket.h>
-#include <unistd.h>
-#include <libudev.h>
-
-#include "libusbi.h"
-#include "linux_usbfs.h"
-
-/* udev context */
-static struct udev *udev_ctx = NULL;
-static int udev_monitor_fd = -1;
-static int udev_control_pipe[2] = {-1, -1};
-static struct udev_monitor *udev_monitor = NULL;
-static pthread_t linux_event_thread;
-
-static void udev_hotplug_event(struct udev_device* udev_dev);
-static void *linux_udev_event_thread_main(void *arg);
-
-int linux_udev_start_event_monitor(void)
-{
- int r;
-
- assert(udev_ctx == NULL);
- udev_ctx = udev_new();
- if (!udev_ctx) {
- usbi_err(NULL, "could not create udev context");
- goto err;
- }
-
- udev_monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
- if (!udev_monitor) {
- usbi_err(NULL, "could not initialize udev monitor");
- goto err_free_ctx;
- }
-
- r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device");
- if (r) {
- usbi_err(NULL, "could not initialize udev monitor filter for \"usb\" subsystem");
- goto err_free_monitor;
- }
-
- if (udev_monitor_enable_receiving(udev_monitor)) {
- usbi_err(NULL, "failed to enable the udev monitor");
- goto err_free_monitor;
- }
-
- udev_monitor_fd = udev_monitor_get_fd(udev_monitor);
-
- /* Some older versions of udev are not non-blocking by default,
- * so make sure this is set */
- r = fcntl(udev_monitor_fd, F_GETFL);
- if (r == -1) {
- usbi_err(NULL, "getting udev monitor fd flags (%d)", errno);
- goto err_free_monitor;
- }
- r = fcntl(udev_monitor_fd, F_SETFL, r | O_NONBLOCK);
- if (r) {
- usbi_err(NULL, "setting udev monitor fd flags (%d)", errno);
- goto err_free_monitor;
- }
-
- r = usbi_pipe(udev_control_pipe);
- if (r) {
- usbi_err(NULL, "could not create udev control pipe");
- goto err_free_monitor;
- }
-
- r = pthread_create(&linux_event_thread, NULL, linux_udev_event_thread_main, NULL);
- if (r) {
- usbi_err(NULL, "creating hotplug event thread (%d)", r);
- goto err_close_pipe;
- }
-
- return LIBUSB_SUCCESS;
-
-err_close_pipe:
- close(udev_control_pipe[0]);
- close(udev_control_pipe[1]);
-err_free_monitor:
- udev_monitor_unref(udev_monitor);
- udev_monitor = NULL;
- udev_monitor_fd = -1;
-err_free_ctx:
- udev_unref(udev_ctx);
-err:
- udev_ctx = NULL;
- return LIBUSB_ERROR_OTHER;
-}
-
-int linux_udev_stop_event_monitor(void)
-{
- char dummy = 1;
- int r;
-
- assert(udev_ctx != NULL);
- assert(udev_monitor != NULL);
- assert(udev_monitor_fd != -1);
-
- /* Write some dummy data to the control pipe and
- * wait for the thread to exit */
- r = usbi_write(udev_control_pipe[1], &dummy, sizeof(dummy));
- if (r <= 0) {
- usbi_warn(NULL, "udev control pipe signal failed");
- }
- pthread_join(linux_event_thread, NULL);
-
- /* Release the udev monitor */
- udev_monitor_unref(udev_monitor);
- udev_monitor = NULL;
- udev_monitor_fd = -1;
-
- /* Clean up the udev context */
- udev_unref(udev_ctx);
- udev_ctx = NULL;
-
- /* close and reset control pipe */
- close(udev_control_pipe[0]);
- close(udev_control_pipe[1]);
- udev_control_pipe[0] = -1;
- udev_control_pipe[1] = -1;
-
- return LIBUSB_SUCCESS;
-}
-
-static void *linux_udev_event_thread_main(void *arg)
-{
- char dummy;
- int r;
- struct udev_device* udev_dev;
- struct pollfd fds[] = {
- {.fd = udev_control_pipe[0],
- .events = POLLIN},
- {.fd = udev_monitor_fd,
- .events = POLLIN},
- };
-
- usbi_dbg("udev event thread entering.");
-
- while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
- if (r < 0) {
- /* temporary failure */
- continue;
- }
- if (fds[0].revents & POLLIN) {
- /* activity on control pipe, read the byte and exit */
- r = usbi_read(udev_control_pipe[0], &dummy, sizeof(dummy));
- if (r <= 0) {
- usbi_warn(NULL, "udev control pipe read failed");
- }
- break;
- }
- if (fds[1].revents & POLLIN) {
- usbi_mutex_static_lock(&linux_hotplug_lock);
- udev_dev = udev_monitor_receive_device(udev_monitor);
- if (udev_dev)
- udev_hotplug_event(udev_dev);
- usbi_mutex_static_unlock(&linux_hotplug_lock);
- }
- }
-
- usbi_dbg("udev event thread exiting");
-
- return NULL;
-}
-
-static int udev_device_info(struct libusb_context *ctx, int detached,
- struct udev_device *udev_dev, uint8_t *busnum,
- uint8_t *devaddr, const char **sys_name) {
- const char *dev_node;
-
- dev_node = udev_device_get_devnode(udev_dev);
- if (!dev_node) {
- return LIBUSB_ERROR_OTHER;
- }
-
- *sys_name = udev_device_get_sysname(udev_dev);
- if (!*sys_name) {
- return LIBUSB_ERROR_OTHER;
- }
-
- return linux_get_device_address(ctx, detached, busnum, devaddr,
- dev_node, *sys_name);
-}
-
-static void udev_hotplug_event(struct udev_device* udev_dev)
-{
- const char* udev_action;
- const char* sys_name = NULL;
- uint8_t busnum = 0, devaddr = 0;
- int detached;
- int r;
-
- do {
- udev_action = udev_device_get_action(udev_dev);
- if (!udev_action) {
- break;
- }
-
- detached = !strncmp(udev_action, "remove", 6);
-
- r = udev_device_info(NULL, detached, udev_dev, &busnum, &devaddr, &sys_name);
- if (LIBUSB_SUCCESS != r) {
- break;
- }
-
- usbi_dbg("udev hotplug event. action: %s.", udev_action);
-
- if (strncmp(udev_action, "add", 3) == 0) {
- linux_hotplug_enumerate(busnum, devaddr, sys_name);
- } else if (detached) {
- linux_device_disconnected(busnum, devaddr);
- } else {
- usbi_err(NULL, "ignoring udev action %s", udev_action);
- }
- } while (0);
-
- udev_device_unref(udev_dev);
-}
-
-int linux_udev_scan_devices(struct libusb_context *ctx)
-{
- struct udev_enumerate *enumerator;
- struct udev_list_entry *devices, *entry;
- struct udev_device *udev_dev;
- const char *sys_name;
- int r;
-
- assert(udev_ctx != NULL);
-
- enumerator = udev_enumerate_new(udev_ctx);
- if (NULL == enumerator) {
- usbi_err(ctx, "error creating udev enumerator");
- return LIBUSB_ERROR_OTHER;
- }
-
- udev_enumerate_add_match_subsystem(enumerator, "usb");
- udev_enumerate_add_match_property(enumerator, "DEVTYPE", "usb_device");
- udev_enumerate_scan_devices(enumerator);
- devices = udev_enumerate_get_list_entry(enumerator);
-
- udev_list_entry_foreach(entry, devices) {
- const char *path = udev_list_entry_get_name(entry);
- uint8_t busnum = 0, devaddr = 0;
-
- udev_dev = udev_device_new_from_syspath(udev_ctx, path);
-
- r = udev_device_info(ctx, 0, udev_dev, &busnum, &devaddr, &sys_name);
- if (r) {
- udev_device_unref(udev_dev);
- continue;
- }
-
- linux_enumerate_device(ctx, busnum, devaddr, sys_name);
- udev_device_unref(udev_dev);
- }
-
- udev_enumerate_unref(enumerator);
-
- return LIBUSB_SUCCESS;
-}
-
-void linux_udev_hotplug_poll(void)
-{
- struct udev_device* udev_dev;
-
- usbi_mutex_static_lock(&linux_hotplug_lock);
- do {
- udev_dev = udev_monitor_receive_device(udev_monitor);
- if (udev_dev) {
- usbi_dbg("Handling hotplug event from hotplug_poll");
- udev_hotplug_event(udev_dev);
- }
- } while (udev_dev);
- usbi_mutex_static_unlock(&linux_hotplug_lock);
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c
deleted file mode 100644
index 6b89ba2..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.c
+++ /dev/null
@@ -1,2738 +0,0 @@
-/* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
-/*
- * Linux usbfs backend for libusb
- * Copyright © 2007-2009 Daniel Drake <dsd@gentoo.org>
- * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
- * Copyright © 2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright © 2012-2013 Hans de Goede <hdegoede@redhat.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 <assert.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/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <time.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 contains all config descriptors since
- * 2.6.26, commit 217a9081d8e69026186067711131b77f0ce219ed
- * - The binary "descriptors" file was added in 2.6.23, commit
- * 69d42a78f935d19384d1f6e4f94b65bb162b36df, but it only contains the
- * active config descriptors
- * - The "busnum" file was added in 2.6.22, commit
- * 83f7d958eab2fbc6b159ee92bf1493924e1d0f72
- * - 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.
- * The busnum file is important as that is the only way we can relate sysfs
- * devices to usbfs nodes.
- *
- * If we also have all descriptors, we can obtain the device descriptor and
- * configuration without touching usbfs at all.
- */
-
-/* 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.
- *
- * In sysfs all descriptors are bus-endian.
- */
-
-static const char *usbfs_path = NULL;
-
-/* use usbdev*.* device names in /dev instead of the usbfs bus directories */
-static int usbdev_names = 0;
-
-/* 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;
-
-/* Linux 2.6.31 fixes support for the zero length packet URB flag. This
- * allows us to mark URBs that should be followed by a zero length data
- * packet, which can be required by device- or class-specific protocols.
- */
-static int supports_flag_zero_packet = -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;
-
-/* Linux 2.6.22 (commit 83f7d958eab2fbc6b159ee92bf1493924e1d0f72) adds a busnum
- * to sysfs, so we can relate devices. This also implies that we can read
- * the active configuration through bConfigurationValue */
-static int sysfs_can_relate_devices = -1;
-
-/* Linux 2.6.26 (commit 217a9081d8e69026186067711131b77f0ce219ed) adds all
- * config descriptors (rather then just the active config) to the sysfs
- * descriptors file, so from then on we can use them. */
-static int sysfs_has_descriptors = -1;
-
-/* how many times have we initted (and not exited) ? */
-static int init_count = 0;
-
-/* Serialize hotplug start/stop */
-static usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER;
-/* Serialize scan-devices, event-thread, and poll */
-usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER;
-
-static int linux_start_event_monitor(void);
-static int linux_stop_event_monitor(void);
-static int linux_scan_devices(struct libusb_context *ctx);
-static int sysfs_scan_device(struct libusb_context *ctx, const char *devname);
-static int detach_kernel_driver_and_claim(struct libusb_device_handle *, int);
-
-#if !defined(USE_UDEV)
-static int linux_default_scan_devices (struct libusb_context *ctx);
-#endif
-
-struct linux_device_priv {
- char *sysfs_dir;
- unsigned char *descriptors;
- int descriptors_len;
- int active_config; /* cache val for !sysfs_can_relate_devices */
-};
-
-struct linux_device_handle_priv {
- int fd;
- int fd_removed;
- uint32_t caps;
-};
-
-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;
- int num_retired;
- enum libusb_transfer_status reap_status;
-
- /* next iso packet in user-supplied transfer to be populated */
- int iso_packet_offset;
-};
-
-static int _get_usbfs_fd(struct libusb_device *dev, mode_t mode, int silent)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
- char path[PATH_MAX];
- int fd;
- int delay = 10000;
-
- if (usbdev_names)
- snprintf(path, PATH_MAX, "%s/usbdev%d.%d",
- usbfs_path, dev->bus_number, dev->device_address);
- else
- snprintf(path, PATH_MAX, "%s/%03d/%03d",
- usbfs_path, dev->bus_number, dev->device_address);
-
- fd = open(path, mode);
- if (fd != -1)
- return fd; /* Success */
-
- if (errno == ENOENT) {
- if (!silent)
- usbi_err(ctx, "File doesn't exist, wait %d ms and try again", delay/1000);
-
- /* Wait 10ms for USB device path creation.*/
- nanosleep(&(struct timespec){delay / 1000000, (delay * 1000) % 1000000000UL}, NULL);
-
- fd = open(path, mode);
- if (fd != -1)
- return fd; /* Success */
- }
-
- if (!silent) {
- usbi_err(ctx, "libusb couldn't open USB device %s: %s",
- path, strerror(errno));
- if (errno == EACCES && mode == O_RDWR)
- usbi_err(ctx, "libusb requires write access to USB "
- "device nodes.");
- }
-
- if (errno == EACCES)
- return LIBUSB_ERROR_ACCESS;
- if (errno == ENOENT)
- return LIBUSB_ERROR_NO_DEVICE;
- return LIBUSB_ERROR_IO;
-}
-
-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;
-}
-
-/* check dirent for a /dev/usbdev%d.%d name
- * optionally return bus/device on success */
-static int _is_usbdev_entry(struct dirent *entry, int *bus_p, int *dev_p)
-{
- int busnum, devnum;
-
- if (sscanf(entry->d_name, "usbdev%d.%d", &busnum, &devnum) != 2)
- return 0;
-
- usbi_dbg("found: %s", entry->d_name);
- if (bus_p != NULL)
- *bus_p = busnum;
- if (dev_p != NULL)
- *dev_p = devnum;
- return 1;
-}
-
-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;
- }
-
- /* look for /dev/usbdev*.* if the normal places fail */
- if (ret == NULL) {
- struct dirent *entry;
- DIR *dir;
-
- path = "/dev";
- dir = opendir(path);
- if (dir != NULL) {
- while ((entry = readdir(dir)) != NULL) {
- if (_is_usbdev_entry(entry, NULL, NULL)) {
- /* found one; that's enough */
- ret = path;
- usbdev_names = 1;
- break;
- }
- }
- closedir(dir);
- }
- }
-
-/* On udev based systems without any usb-devices /dev/bus/usb will not
- * exist. So if we've not found anything and we're using udev for hotplug
- * simply assume /dev/bus/usb rather then making libusb_init fail. */
-#if defined(USE_UDEV)
- if (ret == NULL)
- ret = "/dev/bus/usb";
-#endif
-
- if (ret != NULL)
- 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)
-{
-#ifdef CLOCK_MONOTONIC
- struct timespec ts;
- int r;
-
- /* 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;
-}
-
-static int kernel_version_ge(int major, int minor, int sublevel)
-{
- struct utsname uts;
- int atoms, kmajor, kminor, ksublevel;
-
- if (uname(&uts) < 0)
- return -1;
- atoms = sscanf(uts.release, "%d.%d.%d", &kmajor, &kminor, &ksublevel);
- if (atoms < 1)
- return -1;
-
- if (kmajor > major)
- return 1;
- if (kmajor < major)
- return 0;
-
- /* kmajor == major */
- if (atoms < 2)
- return 0 == minor && 0 == sublevel;
- if (kminor > minor)
- return 1;
- if (kminor < minor)
- return 0;
-
- /* kminor == minor */
- if (atoms < 3)
- return 0 == sublevel;
-
- return ksublevel >= sublevel;
-}
-
-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) {
- /* bulk continuation URB flag available from Linux 2.6.32 */
- supports_flag_bulk_continuation = kernel_version_ge(2,6,32);
- 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");
-
- if (-1 == supports_flag_zero_packet) {
- /* zero length packet URB flag fixed since Linux 2.6.31 */
- supports_flag_zero_packet = kernel_version_ge(2,6,31);
- if (-1 == supports_flag_zero_packet) {
- usbi_err(ctx, "error checking for zero length packet support");
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- if (supports_flag_zero_packet)
- usbi_dbg("zero length packet flag supported");
-
- if (-1 == sysfs_has_descriptors) {
- /* sysfs descriptors has all descriptors since Linux 2.6.26 */
- sysfs_has_descriptors = kernel_version_ge(2,6,26);
- if (-1 == sysfs_has_descriptors) {
- usbi_err(ctx, "error checking for sysfs descriptors");
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- if (-1 == sysfs_can_relate_devices) {
- /* sysfs has busnum since Linux 2.6.22 */
- sysfs_can_relate_devices = kernel_version_ge(2,6,22);
- if (-1 == sysfs_can_relate_devices) {
- usbi_err(ctx, "error checking for sysfs busnum");
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- if (sysfs_can_relate_devices || sysfs_has_descriptors) {
- r = stat(SYSFS_DEVICE_PATH, &statbuf);
- if (r != 0 || !S_ISDIR(statbuf.st_mode)) {
- usbi_warn(ctx, "sysfs not mounted");
- sysfs_can_relate_devices = 0;
- sysfs_has_descriptors = 0;
- }
- }
-
- if (sysfs_can_relate_devices)
- usbi_dbg("sysfs can relate devices");
-
- if (sysfs_has_descriptors)
- usbi_dbg("sysfs has complete descriptors");
-
- usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
- r = LIBUSB_SUCCESS;
- if (init_count == 0) {
- /* start up hotplug event handler */
- r = linux_start_event_monitor();
- }
- if (r == LIBUSB_SUCCESS) {
- r = linux_scan_devices(ctx);
- if (r == LIBUSB_SUCCESS)
- init_count++;
- else if (init_count == 0)
- linux_stop_event_monitor();
- } else
- usbi_err(ctx, "error starting hotplug event monitor");
- usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
-
- return r;
-}
-
-static void op_exit(void)
-{
- usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
- assert(init_count != 0);
- if (!--init_count) {
- /* tear down event handler */
- (void)linux_stop_event_monitor();
- }
- usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
-}
-
-static int linux_start_event_monitor(void)
-{
-#if defined(USE_UDEV)
- return linux_udev_start_event_monitor();
-#else
- return linux_netlink_start_event_monitor();
-#endif
-}
-
-static int linux_stop_event_monitor(void)
-{
-#if defined(USE_UDEV)
- return linux_udev_stop_event_monitor();
-#else
- return linux_netlink_stop_event_monitor();
-#endif
-}
-
-static int linux_scan_devices(struct libusb_context *ctx)
-{
- int ret;
-
- usbi_mutex_static_lock(&linux_hotplug_lock);
-
-#if defined(USE_UDEV)
- ret = linux_udev_scan_devices(ctx);
-#else
- ret = linux_default_scan_devices(ctx);
-#endif
-
- usbi_mutex_static_unlock(&linux_hotplug_lock);
-
- return ret;
-}
-
-static void op_hotplug_poll(void)
-{
-#if defined(USE_UDEV)
- linux_udev_hotplug_poll();
-#else
- linux_netlink_hotplug_poll();
-#endif
-}
-
-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 op_get_device_descriptor(struct libusb_device *dev,
- unsigned char *buffer, int *host_endian)
-{
- struct linux_device_priv *priv = _device_priv(dev);
-
- *host_endian = sysfs_has_descriptors ? 0 : 1;
- memcpy(buffer, priv->descriptors, DEVICE_DESC_LENGTH);
-
- return 0;
-}
-
-/* read the bConfigurationValue for a device */
-static int sysfs_get_active_config(struct libusb_device *dev, int *config)
-{
- char *endptr;
- char tmp[5] = {0, 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_dbg("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;
-}
-
-int linux_get_device_address (struct libusb_context *ctx, int detached,
- uint8_t *busnum, uint8_t *devaddr,const char *dev_node,
- const char *sys_name)
-{
- int sysfs_attr;
-
- usbi_dbg("getting address for device: %s detached: %d", sys_name, detached);
- /* can't use sysfs to read the bus and device number if the
- * device has been detached */
- if (!sysfs_can_relate_devices || detached || NULL == sys_name) {
- if (NULL == dev_node) {
- return LIBUSB_ERROR_OTHER;
- }
-
- /* will this work with all supported kernel versions? */
- if (!strncmp(dev_node, "/dev/bus/usb", 12)) {
- sscanf (dev_node, "/dev/bus/usb/%hhu/%hhu", busnum, devaddr);
- } else if (!strncmp(dev_node, "/proc/bus/usb", 13)) {
- sscanf (dev_node, "/proc/bus/usb/%hhu/%hhu", busnum, devaddr);
- }
-
- return LIBUSB_SUCCESS;
- }
-
- usbi_dbg("scan %s", sys_name);
-
- sysfs_attr = __read_sysfs_attr(ctx, sys_name, "busnum");
- if (0 > sysfs_attr)
- return sysfs_attr;
- if (sysfs_attr > 255)
- return LIBUSB_ERROR_INVALID_PARAM;
- *busnum = (uint8_t) sysfs_attr;
-
- sysfs_attr = __read_sysfs_attr(ctx, sys_name, "devnum");
- if (0 > sysfs_attr)
- return sysfs_attr;
- if (sysfs_attr > 255)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- *devaddr = (uint8_t) sysfs_attr;
-
- usbi_dbg("bus=%d dev=%d", *busnum, *devaddr);
-
- return LIBUSB_SUCCESS;
-}
-
-/* Return offset of the next descriptor with the given type */
-static int seek_to_next_descriptor(struct libusb_context *ctx,
- uint8_t descriptor_type, unsigned char *buffer, int size)
-{
- struct usb_descriptor_header header;
- int i;
-
- for (i = 0; size >= 0; i += header.bLength, size -= header.bLength) {
- if (size == 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (size < 2) {
- usbi_err(ctx, "short descriptor read %d/2", size);
- return LIBUSB_ERROR_IO;
- }
- usbi_parse_descriptor(buffer + i, "bb", &header, 0);
-
- if (i && header.bDescriptorType == descriptor_type)
- return i;
- }
- usbi_err(ctx, "bLength overflow by %d bytes", -size);
- return LIBUSB_ERROR_IO;
-}
-
-/* Return offset to next config */
-static int seek_to_next_config(struct libusb_context *ctx,
- unsigned char *buffer, int size)
-{
- struct libusb_config_descriptor config;
-
- if (size == 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (size < LIBUSB_DT_CONFIG_SIZE) {
- usbi_err(ctx, "short descriptor read %d/%d",
- size, LIBUSB_DT_CONFIG_SIZE);
- return LIBUSB_ERROR_IO;
- }
-
- usbi_parse_descriptor(buffer, "bbwbbbbb", &config, 0);
- if (config.bDescriptorType != LIBUSB_DT_CONFIG) {
- usbi_err(ctx, "descriptor is not a config desc (type 0x%02x)",
- config.bDescriptorType);
- return LIBUSB_ERROR_IO;
- }
-
- /*
- * In usbfs the config descriptors are config.wTotalLength bytes apart,
- * with any short reads from the device appearing as holes in the file.
- *
- * In sysfs wTotalLength is ignored, instead the kernel returns a
- * config descriptor with verified bLength fields, with descriptors
- * with an invalid bLength removed.
- */
- if (sysfs_has_descriptors) {
- int next = seek_to_next_descriptor(ctx, LIBUSB_DT_CONFIG,
- buffer, size);
- if (next == LIBUSB_ERROR_NOT_FOUND)
- next = size;
- if (next < 0)
- return next;
-
- if (next != config.wTotalLength)
- usbi_warn(ctx, "config length mismatch wTotalLength "
- "%d real %d", config.wTotalLength, next);
- return next;
- } else {
- if (config.wTotalLength < LIBUSB_DT_CONFIG_SIZE) {
- usbi_err(ctx, "invalid wTotalLength %d",
- config.wTotalLength);
- return LIBUSB_ERROR_IO;
- } else if (config.wTotalLength > size) {
- usbi_warn(ctx, "short descriptor read %d/%d",
- size, config.wTotalLength);
- return size;
- } else
- return config.wTotalLength;
- }
-}
-
-static int op_get_config_descriptor_by_value(struct libusb_device *dev,
- uint8_t value, unsigned char **buffer, int *host_endian)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct linux_device_priv *priv = _device_priv(dev);
- unsigned char *descriptors = priv->descriptors;
- int size = priv->descriptors_len;
- struct libusb_config_descriptor *config;
-
- *buffer = NULL;
- /* Unlike the device desc. config descs. are always in raw format */
- *host_endian = 0;
-
- /* Skip device header */
- descriptors += DEVICE_DESC_LENGTH;
- size -= DEVICE_DESC_LENGTH;
-
- /* Seek till the config is found, or till "EOF" */
- while (1) {
- int next = seek_to_next_config(ctx, descriptors, size);
- if (next < 0)
- return next;
- config = (struct libusb_config_descriptor *)descriptors;
- if (config->bConfigurationValue == value) {
- *buffer = descriptors;
- return next;
- }
- size -= next;
- descriptors += next;
- }
-}
-
-static int op_get_active_config_descriptor(struct libusb_device *dev,
- unsigned char *buffer, size_t len, int *host_endian)
-{
- int r, config;
- unsigned char *config_desc;
-
- if (sysfs_can_relate_devices) {
- r = sysfs_get_active_config(dev, &config);
- if (r < 0)
- return r;
- } else {
- /* Use cached bConfigurationValue */
- struct linux_device_priv *priv = _device_priv(dev);
- config = priv->active_config;
- }
- if (config == -1)
- return LIBUSB_ERROR_NOT_FOUND;
-
- r = op_get_config_descriptor_by_value(dev, config, &config_desc,
- host_endian);
- if (r < 0)
- return r;
-
- len = MIN(len, r);
- memcpy(buffer, config_desc, len);
- return len;
-}
-
-static int op_get_config_descriptor(struct libusb_device *dev,
- uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
-{
- struct linux_device_priv *priv = _device_priv(dev);
- unsigned char *descriptors = priv->descriptors;
- int i, r, size = priv->descriptors_len;
-
- /* Unlike the device desc. config descs. are always in raw format */
- *host_endian = 0;
-
- /* Skip device header */
- descriptors += DEVICE_DESC_LENGTH;
- size -= DEVICE_DESC_LENGTH;
-
- /* Seek till the config is found, or till "EOF" */
- for (i = 0; ; i++) {
- r = seek_to_next_config(DEVICE_CTX(dev), descriptors, size);
- if (r < 0)
- return r;
- if (i == config_index)
- break;
- size -= r;
- descriptors += r;
- }
-
- len = MIN(len, r);
- memcpy(buffer, descriptors, len);
- return len;
-}
-
-/* send a control message to retrieve active configuration */
-static int usbfs_get_active_config(struct libusb_device *dev, int fd)
-{
- struct linux_device_priv *priv = _device_priv(dev);
- 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);
- priv->active_config = -1;
- } else {
- if (active_config > 0) {
- priv->active_config = active_config;
- } else {
- /* 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_warn(DEVICE_CTX(dev),
- "active cfg 0? assuming unconfigured device");
- priv->active_config = -1;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-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);
- struct libusb_context *ctx = DEVICE_CTX(dev);
- int descriptors_size = 512; /* Begin with a 1024 byte alloc */
- int fd, speed;
- ssize_t r;
-
- dev->bus_number = busnum;
- dev->device_address = devaddr;
-
- if (sysfs_dir) {
- priv->sysfs_dir = strdup(sysfs_dir);
- if (!priv->sysfs_dir)
- return LIBUSB_ERROR_NO_MEM;
-
- /* 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);
- }
- }
- }
-
- /* cache descriptors in memory */
- if (sysfs_has_descriptors)
- fd = _open_sysfs_attr(dev, "descriptors");
- else
- fd = _get_usbfs_fd(dev, O_RDONLY, 0);
- if (fd < 0)
- return fd;
-
- do {
- descriptors_size *= 2;
- priv->descriptors = usbi_reallocf(priv->descriptors,
- descriptors_size);
- if (!priv->descriptors) {
- close(fd);
- return LIBUSB_ERROR_NO_MEM;
- }
- /* usbfs has holes in the file */
- if (!sysfs_has_descriptors) {
- memset(priv->descriptors + priv->descriptors_len,
- 0, descriptors_size - priv->descriptors_len);
- }
- r = read(fd, priv->descriptors + priv->descriptors_len,
- descriptors_size - priv->descriptors_len);
- if (r < 0) {
- usbi_err(ctx, "read descriptor failed ret=%d errno=%d",
- fd, errno);
- close(fd);
- return LIBUSB_ERROR_IO;
- }
- priv->descriptors_len += r;
- } while (priv->descriptors_len == descriptors_size);
-
- close(fd);
-
- if (priv->descriptors_len < DEVICE_DESC_LENGTH) {
- usbi_err(ctx, "short descriptor read (%d)",
- priv->descriptors_len);
- return LIBUSB_ERROR_IO;
- }
-
- if (sysfs_can_relate_devices)
- return LIBUSB_SUCCESS;
-
- /* cache active config */
- fd = _get_usbfs_fd(dev, O_RDWR, 1);
- if (fd < 0) {
- /* cannot send a control message to determine the active
- * config. just assume the first one is active. */
- usbi_warn(ctx, "Missing rw usbfs access; cannot determine "
- "active configuration descriptor");
- if (priv->descriptors_len >=
- (DEVICE_DESC_LENGTH + LIBUSB_DT_CONFIG_SIZE)) {
- struct libusb_config_descriptor config;
- usbi_parse_descriptor(
- priv->descriptors + DEVICE_DESC_LENGTH,
- "bbwbbbbb", &config, 0);
- priv->active_config = config.bConfigurationValue;
- } else
- priv->active_config = -1; /* No config dt */
-
- return LIBUSB_SUCCESS;
- }
-
- r = usbfs_get_active_config(dev, fd);
- close(fd);
-
- return r;
-}
-
-static int linux_get_parent_info(struct libusb_device *dev, const char *sysfs_dir)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev);
- struct libusb_device *it;
- char *parent_sysfs_dir, *tmp;
- int ret, add_parent = 1;
-
- /* XXX -- can we figure out the topology when using usbfs? */
- if (NULL == sysfs_dir || 0 == strncmp(sysfs_dir, "usb", 3)) {
- /* either using usbfs or finding the parent of a root hub */
- return LIBUSB_SUCCESS;
- }
-
- parent_sysfs_dir = strdup(sysfs_dir);
- if (NULL == parent_sysfs_dir) {
- return LIBUSB_ERROR_NO_MEM;
- }
- if (NULL != (tmp = strrchr(parent_sysfs_dir, '.')) ||
- NULL != (tmp = strrchr(parent_sysfs_dir, '-'))) {
- dev->port_number = atoi(tmp + 1);
- *tmp = '\0';
- } else {
- usbi_warn(ctx, "Can not parse sysfs_dir: %s, no parent info",
- parent_sysfs_dir);
- free (parent_sysfs_dir);
- return LIBUSB_SUCCESS;
- }
-
- /* is the parent a root hub? */
- if (NULL == strchr(parent_sysfs_dir, '-')) {
- tmp = parent_sysfs_dir;
- ret = asprintf (&parent_sysfs_dir, "usb%s", tmp);
- free (tmp);
- if (0 > ret) {
- return LIBUSB_ERROR_NO_MEM;
- }
- }
-
-retry:
- /* find the parent in the context */
- usbi_mutex_lock(&ctx->usb_devs_lock);
- list_for_each_entry(it, &ctx->usb_devs, list, struct libusb_device) {
- struct linux_device_priv *priv = _device_priv(it);
- if (priv->sysfs_dir) {
- if (0 == strcmp (priv->sysfs_dir, parent_sysfs_dir)) {
- dev->parent_dev = libusb_ref_device(it);
- break;
- }
- }
- }
- usbi_mutex_unlock(&ctx->usb_devs_lock);
-
- if (!dev->parent_dev && add_parent) {
- usbi_dbg("parent_dev %s not enumerated yet, enumerating now",
- parent_sysfs_dir);
- sysfs_scan_device(ctx, parent_sysfs_dir);
- add_parent = 0;
- goto retry;
- }
-
- usbi_dbg("Dev %p (%s) has parent %p (%s) port %d", dev, sysfs_dir,
- dev->parent_dev, parent_sysfs_dir, dev->port_number);
-
- free (parent_sysfs_dir);
-
- return LIBUSB_SUCCESS;
-}
-
-int linux_enumerate_device(struct libusb_context *ctx,
- uint8_t busnum, uint8_t devaddr, const char *sysfs_dir)
-{
- unsigned long session_id;
- 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) {
- /* device already exists in the context */
- usbi_dbg("session_id %ld already exists", session_id);
- libusb_unref_device(dev);
- return LIBUSB_SUCCESS;
- }
-
- 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;
-
- r = initialize_device(dev, busnum, devaddr, sysfs_dir);
- if (r < 0)
- goto out;
- r = usbi_sanitize_device(dev);
- if (r < 0)
- goto out;
-
- r = linux_get_parent_info(dev, sysfs_dir);
- if (r < 0)
- goto out;
-out:
- if (r < 0)
- libusb_unref_device(dev);
- else
- usbi_connect_device(dev);
-
- return r;
-}
-
-void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name)
-{
- struct libusb_context *ctx;
-
- usbi_mutex_static_lock(&active_contexts_lock);
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- linux_enumerate_device(ctx, busnum, devaddr, sys_name);
- }
- usbi_mutex_static_unlock(&active_contexts_lock);
-}
-
-void linux_device_disconnected(uint8_t busnum, uint8_t devaddr)
-{
- struct libusb_context *ctx;
- struct libusb_device *dev;
- unsigned long session_id = busnum << 8 | devaddr;
-
- usbi_mutex_static_lock(&active_contexts_lock);
- list_for_each_entry(ctx, &active_contexts_list, list, struct libusb_context) {
- dev = usbi_get_device_by_session_id (ctx, session_id);
- if (NULL != dev) {
- usbi_disconnect_device (dev);
- libusb_unref_device(dev);
- } else {
- usbi_dbg("device not found for session %x", session_id);
- }
- }
- usbi_mutex_static_unlock(&active_contexts_lock);
-}
-
-#if !defined(USE_UDEV)
-/* open a bus directory and adds all discovered devices to the context */
-static int usbfs_scan_busdir(struct libusb_context *ctx, uint8_t busnum)
-{
- DIR *dir;
- char dirpath[PATH_MAX];
- struct dirent *entry;
- 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 (linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL)) {
- usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
- continue;
- }
-
- r = 0;
- }
-
- closedir(dir);
- return r;
-}
-
-static int usbfs_get_device_list(struct libusb_context *ctx)
-{
- struct dirent *entry;
- DIR *buses = opendir(usbfs_path);
- int r = 0;
-
- if (!buses) {
- usbi_err(ctx, "opendir buses failed errno=%d", errno);
- return LIBUSB_ERROR_IO;
- }
-
- while ((entry = readdir(buses))) {
- int busnum;
-
- if (entry->d_name[0] == '.')
- continue;
-
- if (usbdev_names) {
- int devaddr;
- if (!_is_usbdev_entry(entry, &busnum, &devaddr))
- continue;
-
- r = linux_enumerate_device(ctx, busnum, (uint8_t) devaddr, NULL);
- if (r < 0) {
- usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
- continue;
- }
- } else {
- busnum = atoi(entry->d_name);
- if (busnum == 0) {
- usbi_dbg("unknown dir entry %s", entry->d_name);
- continue;
- }
-
- r = usbfs_scan_busdir(ctx, busnum);
- if (r < 0)
- break;
- }
- }
-
- closedir(buses);
- return r;
-
-}
-#endif
-
-static int sysfs_scan_device(struct libusb_context *ctx, const char *devname)
-{
- uint8_t busnum, devaddr;
- int ret;
-
- ret = linux_get_device_address (ctx, 0, &busnum, &devaddr, NULL, devname);
- if (LIBUSB_SUCCESS != ret) {
- return ret;
- }
-
- return linux_enumerate_device(ctx, busnum & 0xff, devaddr & 0xff,
- devname);
-}
-
-#if !defined(USE_UDEV)
-static int sysfs_get_device_list(struct libusb_context *ctx)
-{
- 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))) {
- if ((!isdigit(entry->d_name[0]) && strncmp(entry->d_name, "usb", 3))
- || strchr(entry->d_name, ':'))
- continue;
-
- if (sysfs_scan_device(ctx, entry->d_name)) {
- usbi_dbg("failed to enumerate dir entry %s", entry->d_name);
- continue;
- }
-
- r = 0;
- }
-
- closedir(devices);
- return r;
-}
-
-static int linux_default_scan_devices (struct libusb_context *ctx)
-{
- /* 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);
- else
- return usbfs_get_device_list(ctx);
-}
-#endif
-
-static int op_open(struct libusb_device_handle *handle)
-{
- struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
- int r;
-
- hpriv->fd = _get_usbfs_fd(handle->dev, O_RDWR, 0);
- if (hpriv->fd < 0) {
- if (hpriv->fd == LIBUSB_ERROR_NO_DEVICE) {
- /* device will still be marked as attached if hotplug monitor thread
- * hasn't processed remove event yet */
- usbi_mutex_static_lock(&linux_hotplug_lock);
- if (handle->dev->attached) {
- usbi_dbg("open failed with no device, but device still attached");
- linux_device_disconnected(handle->dev->bus_number,
- handle->dev->device_address);
- }
- usbi_mutex_static_unlock(&linux_hotplug_lock);
- }
- return hpriv->fd;
- }
-
- r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps);
- if (r < 0) {
- if (errno == ENOTTY)
- usbi_dbg("getcap not available");
- else
- usbi_err(HANDLE_CTX(handle), "getcap failed (%d)", errno);
- hpriv->caps = 0;
- if (supports_flag_zero_packet)
- hpriv->caps |= USBFS_CAP_ZERO_PACKET;
- if (supports_flag_bulk_continuation)
- hpriv->caps |= USBFS_CAP_BULK_CONTINUATION;
- }
-
- r = usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT);
- if (r < 0)
- close(hpriv->fd);
-
- return r;
-}
-
-static void op_close(struct libusb_device_handle *dev_handle)
-{
- struct linux_device_handle_priv *hpriv = _device_handle_priv(dev_handle);
- /* fd may have already been removed by POLLERR condition in op_handle_events() */
- if (!hpriv->fd_removed)
- usbi_remove_pollfd(HANDLE_CTX(dev_handle), hpriv->fd);
- close(hpriv->fd);
-}
-
-static int op_get_configuration(struct libusb_device_handle *handle,
- int *config)
-{
- int r;
-
- if (sysfs_can_relate_devices) {
- r = sysfs_get_active_config(handle->dev, config);
- } else {
- r = usbfs_get_active_config(handle->dev,
- _device_handle_priv(handle)->fd);
- if (r == LIBUSB_SUCCESS)
- *config = _device_priv(handle->dev)->active_config;
- }
- if (r < 0)
- return r;
-
- if (*config == -1) {
- usbi_err(HANDLE_CTX(handle), "device unconfigured");
- *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;
- }
-
- /* update our cached active config descriptor */
- priv->active_config = config;
-
- return LIBUSB_SUCCESS;
-}
-
-static int 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 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)) {
- 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)) {
- /*
- * A driver may have completed modprobing during
- * IOCTL_USBFS_RESET, and bound itself as soon as
- * IOCTL_USBFS_RESET released the device lock
- */
- r = detach_kernel_driver_and_claim(handle, i);
- if (r) {
- usbi_warn(HANDLE_CTX(handle),
- "failed to re-claim interface %d after reset: %s",
- i, libusb_error_name(r));
- handle->claimed_interfaces &= ~(1L << i);
- ret = LIBUSB_ERROR_NOT_FOUND;
- }
- }
- }
-out:
- usbi_mutex_unlock(&handle->lock);
- return ret;
-}
-
-static int do_streams_ioctl(struct libusb_device_handle *handle, long req,
- uint32_t num_streams, unsigned char *endpoints, int num_endpoints)
-{
- int r, fd = _device_handle_priv(handle)->fd;
- struct usbfs_streams *streams;
-
- if (num_endpoints > 30) /* Max 15 in + 15 out eps */
- return LIBUSB_ERROR_INVALID_PARAM;
-
- streams = malloc(sizeof(struct usbfs_streams) + num_endpoints);
- if (!streams)
- return LIBUSB_ERROR_NO_MEM;
-
- streams->num_streams = num_streams;
- streams->num_eps = num_endpoints;
- memcpy(streams->eps, endpoints, num_endpoints);
-
- r = ioctl(fd, req, streams);
-
- free(streams);
-
- if (r < 0) {
- if (errno == ENOTTY)
- return LIBUSB_ERROR_NOT_SUPPORTED;
- else if (errno == EINVAL)
- return LIBUSB_ERROR_INVALID_PARAM;
- else if (errno == ENODEV)
- return LIBUSB_ERROR_NO_DEVICE;
-
- usbi_err(HANDLE_CTX(handle),
- "streams-ioctl failed error %d errno %d", r, errno);
- return LIBUSB_ERROR_OTHER;
- }
- return r;
-}
-
-static int op_alloc_streams(struct libusb_device_handle *handle,
- uint32_t num_streams, unsigned char *endpoints, int num_endpoints)
-{
- return do_streams_ioctl(handle, IOCTL_USBFS_ALLOC_STREAMS,
- num_streams, endpoints, num_endpoints);
-}
-
-static int op_free_streams(struct libusb_device_handle *handle,
- unsigned char *endpoints, int num_endpoints)
-{
- return do_streams_ioctl(handle, IOCTL_USBFS_FREE_STREAMS, 0,
- endpoints, num_endpoints);
-}
-
-static unsigned char *op_dev_mem_alloc(struct libusb_device_handle *handle,
- size_t len)
-{
- struct linux_device_handle_priv *hpriv = _device_handle_priv(handle);
- unsigned char *buffer = (unsigned char *)mmap(NULL, len,
- PROT_READ | PROT_WRITE, MAP_SHARED, hpriv->fd, 0);
- if (buffer == MAP_FAILED) {
- usbi_err(HANDLE_CTX(handle), "alloc dev mem failed errno %d",
- errno);
- return NULL;
- }
- return buffer;
-}
-
-static int op_dev_mem_free(struct libusb_device_handle *handle,
- unsigned char *buffer, size_t len)
-{
- if (munmap(buffer, len) != 0) {
- usbi_err(HANDLE_CTX(handle), "free dev mem failed errno %d",
- errno);
- return LIBUSB_ERROR_OTHER;
- } else {
- return LIBUSB_SUCCESS;
- }
-}
-
-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 (strcmp(getdrv.driver, "usbfs") == 0) ? 0 : 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;
- struct usbfs_getdriver getdrv;
- int r;
-
- command.ifno = interface;
- command.ioctl_code = IOCTL_USBFS_DISCONNECT;
- command.data = NULL;
-
- getdrv.interface = interface;
- r = ioctl(fd, IOCTL_USBFS_GETDRIVER, &getdrv);
- if (r == 0 && strcmp(getdrv.driver, "usbfs") == 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- 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 int detach_kernel_driver_and_claim(struct libusb_device_handle *handle,
- int interface)
-{
- struct usbfs_disconnect_claim dc;
- int r, fd = _device_handle_priv(handle)->fd;
-
- dc.interface = interface;
- strcpy(dc.driver, "usbfs");
- dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER;
- r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc);
- if (r == 0 || (r != 0 && errno != ENOTTY)) {
- if (r == 0)
- return 0;
-
- switch (errno) {
- case EBUSY:
- return LIBUSB_ERROR_BUSY;
- case EINVAL:
- return LIBUSB_ERROR_INVALID_PARAM;
- case ENODEV:
- return LIBUSB_ERROR_NO_DEVICE;
- }
- usbi_err(HANDLE_CTX(handle),
- "disconnect-and-claim failed errno %d", errno);
- return LIBUSB_ERROR_OTHER;
- }
-
- /* Fallback code for kernels which don't support the
- disconnect-and-claim ioctl */
- r = op_detach_kernel_driver(handle, interface);
- if (r != 0 && r != LIBUSB_ERROR_NOT_FOUND)
- return r;
-
- return claim_interface(handle, interface);
-}
-
-static int op_claim_interface(struct libusb_device_handle *handle, int iface)
-{
- if (handle->auto_detach_kernel_driver)
- return detach_kernel_driver_and_claim(handle, iface);
- else
- return claim_interface(handle, iface);
-}
-
-static int op_release_interface(struct libusb_device_handle *handle, int iface)
-{
- int r;
-
- r = release_interface(handle, iface);
- if (r)
- return r;
-
- if (handle->auto_detach_kernel_driver)
- op_attach_kernel_driver(handle, iface);
-
- return 0;
-}
-
-static void op_destroy_device(struct libusb_device *dev)
-{
- struct linux_device_priv *priv = _device_priv(dev);
- if (priv->descriptors)
- free(priv->descriptors);
- 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");
- if (i == (last_plus_one - 1))
- 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)
-{
- 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 bulk_buffer_len, use_bulk_continuation;
- int r;
- int i;
-
- if (is_out && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) &&
- !(dpriv->caps & USBFS_CAP_ZERO_PACKET))
- return LIBUSB_ERROR_NOT_SUPPORTED;
-
- /*
- * Older versions of usbfs place a 16kb limit on bulk URBs. We work
- * around this by splitting large transfers into 16k blocks, and then
- * submit all urbs at once. it would be simpler to submit one urb at
- * a time, but there is a big performance gain doing it this way.
- *
- * Newer versions lift the 16k limit (USBFS_CAP_NO_PACKET_SIZE_LIM),
- * using arbritary large transfers can still be a bad idea though, as
- * the kernel needs to allocate physical contiguous memory for this,
- * which may fail for large buffers.
- *
- * The kernel solves this problem by splitting the transfer into
- * blocks itself when the host-controller is scatter-gather capable
- * (USBFS_CAP_BULK_SCATTER_GATHER), which most controllers are.
- *
- * Last, there is the issue of short-transfers when splitting, for
- * short split-transfers to work reliable USBFS_CAP_BULK_CONTINUATION
- * is needed, but this is not always available.
- */
- if (dpriv->caps & USBFS_CAP_BULK_SCATTER_GATHER) {
- /* Good! Just submit everything in one go */
- bulk_buffer_len = transfer->length ? transfer->length : 1;
- use_bulk_continuation = 0;
- } else if (dpriv->caps & USBFS_CAP_BULK_CONTINUATION) {
- /* Split the transfers and use bulk-continuation to
- avoid issues with short-transfers */
- bulk_buffer_len = MAX_BULK_BUFFER_LENGTH;
- use_bulk_continuation = 1;
- } else if (dpriv->caps & USBFS_CAP_NO_PACKET_SIZE_LIM) {
- /* Don't split, assume the kernel can alloc the buffer
- (otherwise the submit will fail with -ENOMEM) */
- bulk_buffer_len = transfer->length ? transfer->length : 1;
- use_bulk_continuation = 0;
- } else {
- /* Bad, splitting without bulk-continuation, short transfers
- which end before the last urb will not work reliable! */
- /* Note we don't warn here as this is "normal" on kernels <
- 2.6.32 and not a problem for most applications */
- bulk_buffer_len = MAX_BULK_BUFFER_LENGTH;
- use_bulk_continuation = 0;
- }
-
- int num_urbs = transfer->length / bulk_buffer_len;
- int last_urb_partial = 0;
-
- if (transfer->length == 0) {
- num_urbs = 1;
- } else if ((transfer->length % bulk_buffer_len) > 0) {
- last_urb_partial = 1;
- num_urbs++;
- }
- usbi_dbg("need %d urbs for new transfer with length %d", num_urbs,
- transfer->length);
- urbs = calloc(num_urbs, sizeof(struct usbfs_urb));
- if (!urbs)
- return LIBUSB_ERROR_NO_MEM;
- 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;
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_BULK:
- urb->type = USBFS_URB_TYPE_BULK;
- urb->stream_id = 0;
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- urb->type = USBFS_URB_TYPE_BULK;
- urb->stream_id = itransfer->stream_id;
- break;
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- urb->type = USBFS_URB_TYPE_INTERRUPT;
- break;
- }
- urb->endpoint = transfer->endpoint;
- urb->buffer = transfer->buffer + (i * bulk_buffer_len);
- /* don't set the short not ok flag for the last URB */
- if (use_bulk_continuation && !is_out && (i < num_urbs - 1))
- urb->flags = USBFS_URB_SHORT_NOT_OK;
- if (i == num_urbs - 1 && last_urb_partial)
- urb->buffer_length = transfer->length % bulk_buffer_len;
- else if (transfer->length == 0)
- urb->buffer_length = 0;
- else
- urb->buffer_length = bulk_buffer_len;
-
- if (i > 0 && use_bulk_continuation)
- urb->flags |= USBFS_URB_BULK_CONTINUATION;
-
- /* we have already checked that the flag is supported */
- if (is_out && i == num_urbs - 1 &&
- transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET)
- urb->flags |= USBFS_URB_ZERO_PACKET;
-
- 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;
-
- /* usbfs places arbitrary limits on iso URBs. this limit has changed
- * at least three times, and it's difficult to accurately detect which
- * limit this running kernel might impose. so we attempt to submit
- * whatever the user has provided. if the kernel rejects the request
- * due to its size, we return an error indicating such to the user.
- */
-
- /* calculate how many URBs we need */
- for (i = 0; i < num_packets; i++) {
- unsigned 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;
- /* check that we can actually support this packet length */
- if (this_urb_len > MAX_ISO_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
- } else {
- this_urb_len += packet_len;
- }
- }
- usbi_dbg("need %d %dk URBs for transfer", num_urbs, MAX_ISO_BUFFER_LENGTH / 1024);
-
- urbs = calloc(num_urbs, sizeof(*urbs));
- if (!urbs)
- return LIBUSB_ERROR_NO_MEM;
-
- 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;
- unsigned 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 = calloc(1, alloc_size);
- if (!urb) {
- free_iso_urbs(tpriv);
- return LIBUSB_ERROR_NO_MEM;
- }
- 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 if (errno == EINVAL) {
- usbi_warn(TRANSFER_CTX(transfer),
- "submiturb failed, transfer too large");
- r = LIBUSB_ERROR_INVALID_PARAM;
- } 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 (transfer->length - LIBUSB_CONTROL_SETUP_SIZE > MAX_CTRL_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- urb = calloc(1, sizeof(struct usbfs_urb));
- if (!urb)
- return LIBUSB_ERROR_NO_MEM;
- 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:
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- return submit_bulk_transfer(itransfer);
- 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 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);
- int r;
-
- if (!tpriv->urbs)
- return LIBUSB_ERROR_NOT_FOUND;
-
- r = discard_urbs(itransfer, 0, tpriv->num_urbs);
- if (r != 0)
- return r;
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- if (tpriv->reap_action == ERROR)
- break;
- /* else, fall through */
- default:
- tpriv->reap_action = CANCELLED;
- }
-
- return 0;
-}
-
-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_BULK_STREAM:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (tpriv->urbs) {
- free(tpriv->urbs);
- tpriv->urbs = NULL;
- }
- break;
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- if (tpriv->iso_urbs) {
- free_iso_urbs(tpriv);
- tpriv->iso_urbs = NULL;
- }
- 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 -ENODEV:
- 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:
- case -ECOMM:
- case -ENOSR:
- 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 = LIBUSB_TRANSFER_COMPLETED;
- switch (urb_desc->status) {
- case 0:
- break;
- case -ENOENT: /* cancelled */
- case -ECONNRESET:
- break;
- case -ENODEV:
- case -ESHUTDOWN:
- usbi_dbg("device removed");
- lib_desc->status = LIBUSB_TRANSFER_NO_DEVICE;
- break;
- case -EPIPE:
- usbi_dbg("detected endpoint stall");
- lib_desc->status = LIBUSB_TRANSFER_STALL;
- break;
- case -EOVERFLOW:
- usbi_dbg("overflow error");
- lib_desc->status = LIBUSB_TRANSFER_OVERFLOW;
- break;
- case -ETIME:
- case -EPROTO:
- case -EILSEQ:
- case -ECOMM:
- case -ENOSR:
- case -EXDEV:
- usbi_dbg("low-level USB error %d", urb_desc->status);
- lib_desc->status = LIBUSB_TRANSFER_ERROR;
- break;
- default:
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised urb status %d", urb_desc->status);
- lib_desc->status = LIBUSB_TRANSFER_ERROR;
- break;
- }
- 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 (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 */
- case -ECONNRESET:
- break;
- case -ESHUTDOWN:
- usbi_dbg("device removed");
- status = LIBUSB_TRANSFER_NO_DEVICE;
- break;
- default:
- usbi_warn(TRANSFER_CTX(transfer),
- "unrecognised urb status %d", urb->status);
- status = LIBUSB_TRANSFER_ERROR;
- break;
- }
-
- /* if we're the last urb 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 -ENODEV:
- 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 -EOVERFLOW:
- usbi_dbg("control overflow error");
- status = LIBUSB_TRANSFER_OVERFLOW;
- break;
- case -ETIME:
- case -EPROTO:
- case -EILSEQ:
- case -ECOMM:
- case -ENOSR:
- 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_BULK_STREAM:
- 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;
- unsigned 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 (!hpriv || hpriv->fd != pollfd->fd) {
- usbi_err(ctx, "cannot find handle for fd %d",
- pollfd->fd);
- continue;
- }
-
- if (pollfd->revents & POLLERR) {
- /* remove the fd from the pollfd set so that it doesn't continuously
- * trigger an event, and flag that it has been removed so op_close()
- * doesn't try to remove it a second time */
- usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd);
- hpriv->fd_removed = 1;
-
- /* device will still be marked as attached if hotplug monitor thread
- * hasn't processed remove event yet */
- usbi_mutex_static_lock(&linux_hotplug_lock);
- if (handle->dev->attached)
- linux_device_disconnected(handle->dev->bus_number,
- handle->dev->device_address);
- usbi_mutex_static_unlock(&linux_hotplug_lock);
-
- if (hpriv->caps & USBFS_CAP_REAP_AFTER_DISCONNECT) {
- do {
- r = reap_for_handle(handle);
- } while (r == 0);
- }
-
- usbi_handle_disconnect(handle);
- continue;
- }
-
- do {
- r = reap_for_handle(handle);
- } while (r == 0);
- 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",
- .caps = USBI_CAP_HAS_HID_ACCESS|USBI_CAP_SUPPORTS_DETACH_KERNEL_DRIVER,
- .init = op_init,
- .exit = op_exit,
- .get_device_list = NULL,
- .hotplug_poll = op_hotplug_poll,
- .get_device_descriptor = op_get_device_descriptor,
- .get_active_config_descriptor = op_get_active_config_descriptor,
- .get_config_descriptor = op_get_config_descriptor,
- .get_config_descriptor_by_value = op_get_config_descriptor_by_value,
-
- .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,
-
- .alloc_streams = op_alloc_streams,
- .free_streams = op_free_streams,
-
- .dev_mem_alloc = op_dev_mem_alloc,
- .dev_mem_free = op_dev_mem_free,
-
- .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),
-};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h
deleted file mode 100644
index 8bd3ebc..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/linux_usbfs.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * usbfs header structures
- * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
- * Copyright © 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
-
-#include <linux/types.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
-#define USBFS_URB_ZERO_PACKET 0x40
-
-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 49152 * 128
-#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;
- union {
- int number_of_packets; /* Only used for isoc urbs */
- unsigned int stream_id; /* Only used with bulk streams */
- };
- 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 USBFS_CAP_ZERO_PACKET 0x01
-#define USBFS_CAP_BULK_CONTINUATION 0x02
-#define USBFS_CAP_NO_PACKET_SIZE_LIM 0x04
-#define USBFS_CAP_BULK_SCATTER_GATHER 0x08
-#define USBFS_CAP_REAP_AFTER_DISCONNECT 0x10
-
-#define USBFS_DISCONNECT_CLAIM_IF_DRIVER 0x01
-#define USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER 0x02
-
-struct usbfs_disconnect_claim {
- unsigned int interface;
- unsigned int flags;
- char driver[USBFS_MAXDRIVERNAME + 1];
-};
-
-struct usbfs_streams {
- unsigned int num_streams; /* Not used by USBDEVFS_FREE_STREAMS */
- unsigned int num_eps;
- unsigned char eps[0];
-};
-
-#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)
-#define IOCTL_USBFS_CLAIM_PORT _IOR('U', 24, unsigned int)
-#define IOCTL_USBFS_RELEASE_PORT _IOR('U', 25, unsigned int)
-#define IOCTL_USBFS_GET_CAPABILITIES _IOR('U', 26, __u32)
-#define IOCTL_USBFS_DISCONNECT_CLAIM _IOR('U', 27, struct usbfs_disconnect_claim)
-#define IOCTL_USBFS_ALLOC_STREAMS _IOR('U', 28, struct usbfs_streams)
-#define IOCTL_USBFS_FREE_STREAMS _IOR('U', 29, struct usbfs_streams)
-
-extern usbi_mutex_static_t linux_hotplug_lock;
-
-#if defined(HAVE_LIBUDEV)
-int linux_udev_start_event_monitor(void);
-int linux_udev_stop_event_monitor(void);
-int linux_udev_scan_devices(struct libusb_context *ctx);
-void linux_udev_hotplug_poll(void);
-#else
-int linux_netlink_start_event_monitor(void);
-int linux_netlink_stop_event_monitor(void);
-void linux_netlink_hotplug_poll(void);
-#endif
-
-void linux_hotplug_enumerate(uint8_t busnum, uint8_t devaddr, const char *sys_name);
-void linux_device_disconnected(uint8_t busnum, uint8_t devaddr);
-
-int linux_get_device_address (struct libusb_context *ctx, int detached,
- uint8_t *busnum, uint8_t *devaddr, const char *dev_node,
- const char *sys_name);
-int linux_enumerate_device(struct libusb_context *ctx,
- uint8_t busnum, uint8_t devaddr, const char *sysfs_dir);
-
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c
deleted file mode 100644
index ad1ede7..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/netbsd_usb.c
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright © 2011 Martin Pieuchot <mpi@openbsd.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 <sys/time.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <dev/usb/usb.h>
-
-#include "libusbi.h"
-
-struct device_priv {
- char devnode[16];
- int fd;
-
- unsigned char *cdesc; /* active config descriptor */
- usb_device_descriptor_t ddesc; /* usb device descriptor */
-};
-
-struct handle_priv {
- int endpoints[USB_MAX_ENDPOINTS];
-};
-
-/*
- * Backend functions
- */
-static int netbsd_get_device_list(struct libusb_context *,
- struct discovered_devs **);
-static int netbsd_open(struct libusb_device_handle *);
-static void netbsd_close(struct libusb_device_handle *);
-
-static int netbsd_get_device_descriptor(struct libusb_device *, unsigned char *,
- int *);
-static int netbsd_get_active_config_descriptor(struct libusb_device *,
- unsigned char *, size_t, int *);
-static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
- unsigned char *, size_t, int *);
-
-static int netbsd_get_configuration(struct libusb_device_handle *, int *);
-static int netbsd_set_configuration(struct libusb_device_handle *, int);
-
-static int netbsd_claim_interface(struct libusb_device_handle *, int);
-static int netbsd_release_interface(struct libusb_device_handle *, int);
-
-static int netbsd_set_interface_altsetting(struct libusb_device_handle *, int,
- int);
-static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
-static int netbsd_reset_device(struct libusb_device_handle *);
-static void netbsd_destroy_device(struct libusb_device *);
-
-static int netbsd_submit_transfer(struct usbi_transfer *);
-static int netbsd_cancel_transfer(struct usbi_transfer *);
-static void netbsd_clear_transfer_priv(struct usbi_transfer *);
-static int netbsd_handle_transfer_completion(struct usbi_transfer *);
-static int netbsd_clock_gettime(int, struct timespec *);
-
-/*
- * Private functions
- */
-static int _errno_to_libusb(int);
-static int _cache_active_config_descriptor(struct libusb_device *, int);
-static int _sync_control_transfer(struct usbi_transfer *);
-static int _sync_gen_transfer(struct usbi_transfer *);
-static int _access_endpoint(struct libusb_transfer *);
-
-const struct usbi_os_backend netbsd_backend = {
- "Synchronous NetBSD backend",
- 0,
- NULL, /* init() */
- NULL, /* exit() */
- netbsd_get_device_list,
- NULL, /* hotplug_poll */
- netbsd_open,
- netbsd_close,
-
- netbsd_get_device_descriptor,
- netbsd_get_active_config_descriptor,
- netbsd_get_config_descriptor,
- NULL, /* get_config_descriptor_by_value() */
-
- netbsd_get_configuration,
- netbsd_set_configuration,
-
- netbsd_claim_interface,
- netbsd_release_interface,
-
- netbsd_set_interface_altsetting,
- netbsd_clear_halt,
- netbsd_reset_device,
-
- NULL, /* alloc_streams */
- NULL, /* free_streams */
-
- NULL, /* dev_mem_alloc() */
- NULL, /* dev_mem_free() */
-
- NULL, /* kernel_driver_active() */
- NULL, /* detach_kernel_driver() */
- NULL, /* attach_kernel_driver() */
-
- netbsd_destroy_device,
-
- netbsd_submit_transfer,
- netbsd_cancel_transfer,
- netbsd_clear_transfer_priv,
-
- NULL, /* handle_events() */
- netbsd_handle_transfer_completion,
-
- netbsd_clock_gettime,
- sizeof(struct device_priv),
- sizeof(struct handle_priv),
- 0, /* transfer_priv_size */
-};
-
-int
-netbsd_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- struct libusb_device *dev;
- struct device_priv *dpriv;
- struct usb_device_info di;
- unsigned long session_id;
- char devnode[16];
- int fd, err, i;
-
- usbi_dbg("");
-
- /* Only ugen(4) is supported */
- for (i = 0; i < USB_MAX_DEVICES; i++) {
- /* Control endpoint is always .00 */
- snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
-
- if ((fd = open(devnode, O_RDONLY)) < 0) {
- if (errno != ENOENT && errno != ENXIO)
- usbi_err(ctx, "could not open %s", devnode);
- continue;
- }
-
- if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
- continue;
-
- session_id = (di.udi_bus << 8 | di.udi_addr);
- dev = usbi_get_device_by_session_id(ctx, session_id);
-
- if (dev == NULL) {
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- dev->bus_number = di.udi_bus;
- dev->device_address = di.udi_addr;
- dev->speed = di.udi_speed;
-
- dpriv = (struct device_priv *)dev->os_priv;
- strlcpy(dpriv->devnode, devnode, sizeof(devnode));
- dpriv->fd = -1;
-
- if (ioctl(fd, USB_GET_DEVICE_DESC, &dpriv->ddesc) < 0) {
- err = errno;
- goto error;
- }
-
- dpriv->cdesc = NULL;
- if (_cache_active_config_descriptor(dev, fd)) {
- err = errno;
- goto error;
- }
-
- if ((err = usbi_sanitize_device(dev)))
- goto error;
- }
- close(fd);
-
- if (discovered_devs_append(*discdevs, dev) == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- libusb_unref_device(dev);
- }
-
- return (LIBUSB_SUCCESS);
-
-error:
- close(fd);
- libusb_unref_device(dev);
- return _errno_to_libusb(err);
-}
-
-int
-netbsd_open(struct libusb_device_handle *handle)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
-
- dpriv->fd = open(dpriv->devnode, O_RDWR);
- if (dpriv->fd < 0) {
- dpriv->fd = open(dpriv->devnode, O_RDONLY);
- if (dpriv->fd < 0)
- return _errno_to_libusb(errno);
- }
-
- usbi_dbg("open %s: fd %d", dpriv->devnode, dpriv->fd);
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-netbsd_close(struct libusb_device_handle *handle)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
-
- usbi_dbg("close: fd %d", dpriv->fd);
-
- close(dpriv->fd);
- dpriv->fd = -1;
-}
-
-int
-netbsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
- int *host_endian)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-
- usbi_dbg("");
-
- memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
-
- *host_endian = 0;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_get_active_config_descriptor(struct libusb_device *dev,
- unsigned char *buf, size_t len, int *host_endian)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
- usb_config_descriptor_t *ucd;
-
- ucd = (usb_config_descriptor_t *) dpriv->cdesc;
- len = MIN(len, UGETW(ucd->wTotalLength));
-
- usbi_dbg("len %d", len);
-
- memcpy(buf, dpriv->cdesc, len);
-
- *host_endian = 0;
-
- return len;
-}
-
-int
-netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- unsigned char *buf, size_t len, int *host_endian)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
- struct usb_full_desc ufd;
- int fd, err;
-
- usbi_dbg("index %d, len %d", idx, len);
-
- /* A config descriptor may be requested before opening the device */
- if (dpriv->fd >= 0) {
- fd = dpriv->fd;
- } else {
- fd = open(dpriv->devnode, O_RDONLY);
- if (fd < 0)
- return _errno_to_libusb(errno);
- }
-
- ufd.ufd_config_index = idx;
- ufd.ufd_size = len;
- ufd.ufd_data = buf;
-
- if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
- err = errno;
- if (dpriv->fd < 0)
- close(fd);
- return _errno_to_libusb(err);
- }
-
- if (dpriv->fd < 0)
- close(fd);
-
- *host_endian = 0;
-
- return len;
-}
-
-int
-netbsd_get_configuration(struct libusb_device_handle *handle, int *config)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
-
- usbi_dbg("");
-
- if (ioctl(dpriv->fd, USB_GET_CONFIG, config) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg("configuration %d", *config);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_set_configuration(struct libusb_device_handle *handle, int config)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
-
- usbi_dbg("configuration %d", config);
-
- if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
- return _errno_to_libusb(errno);
-
- return _cache_active_config_descriptor(handle->dev, dpriv->fd);
-}
-
-int
-netbsd_claim_interface(struct libusb_device_handle *handle, int iface)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- int i;
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- hpriv->endpoints[i] = -1;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_release_interface(struct libusb_device_handle *handle, int iface)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- int i;
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- if (hpriv->endpoints[i] >= 0)
- close(hpriv->endpoints[i]);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
- int altsetting)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
- struct usb_alt_interface intf;
-
- usbi_dbg("iface %d, setting %d", iface, altsetting);
-
- memset(&intf, 0, sizeof(intf));
-
- intf.uai_interface_index = iface;
- intf.uai_alt_no = altsetting;
-
- if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
- return _errno_to_libusb(errno);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
- struct usb_ctl_request req;
-
- usbi_dbg("");
-
- req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
- req.ucr_request.bRequest = UR_CLEAR_FEATURE;
- USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
- USETW(req.ucr_request.wIndex, endpoint);
- USETW(req.ucr_request.wLength, 0);
-
- if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
- return _errno_to_libusb(errno);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_reset_device(struct libusb_device_handle *handle)
-{
- usbi_dbg("");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-void
-netbsd_destroy_device(struct libusb_device *dev)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-
- usbi_dbg("");
-
- free(dpriv->cdesc);
-}
-
-int
-netbsd_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct handle_priv *hpriv;
- int err = 0;
-
- usbi_dbg("");
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- err = _sync_control_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- if (IS_XFEROUT(transfer)) {
- /* Isochronous write is not supported */
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) &&
- transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- if (err)
- return (err);
-
- usbi_signal_transfer_completion(itransfer);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-netbsd_cancel_transfer(struct usbi_transfer *itransfer)
-{
- usbi_dbg("");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-void
-netbsd_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- usbi_dbg("");
-
- /* Nothing to do */
-}
-
-int
-netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
-}
-
-int
-netbsd_clock_gettime(int clkid, struct timespec *tp)
-{
- usbi_dbg("clock %d", clkid);
-
- if (clkid == USBI_CLOCK_REALTIME)
- return clock_gettime(CLOCK_REALTIME, tp);
-
- if (clkid == USBI_CLOCK_MONOTONIC)
- return clock_gettime(CLOCK_MONOTONIC, tp);
-
- return (LIBUSB_ERROR_INVALID_PARAM);
-}
-
-int
-_errno_to_libusb(int err)
-{
- switch (err) {
- case EIO:
- return (LIBUSB_ERROR_IO);
- case EACCES:
- return (LIBUSB_ERROR_ACCESS);
- case ENOENT:
- return (LIBUSB_ERROR_NO_DEVICE);
- case ENOMEM:
- return (LIBUSB_ERROR_NO_MEM);
- }
-
- usbi_dbg("error: %s", strerror(err));
-
- return (LIBUSB_ERROR_OTHER);
-}
-
-int
-_cache_active_config_descriptor(struct libusb_device *dev, int fd)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
- struct usb_config_desc ucd;
- struct usb_full_desc ufd;
- unsigned char* buf;
- int len;
-
- usbi_dbg("fd %d", fd);
-
- ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
-
- if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg("active bLength %d", ucd.ucd_desc.bLength);
-
- len = UGETW(ucd.ucd_desc.wTotalLength);
- buf = malloc(len);
- if (buf == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- ufd.ufd_config_index = ucd.ucd_config_index;
- ufd.ufd_size = len;
- ufd.ufd_data = buf;
-
- usbi_dbg("index %d, len %d", ufd.ufd_config_index, len);
-
- if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
- free(buf);
- return _errno_to_libusb(errno);
- }
-
- if (dpriv->cdesc)
- free(dpriv->cdesc);
- dpriv->cdesc = buf;
-
- return (0);
-}
-
-int
-_sync_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct libusb_control_setup *setup;
- struct device_priv *dpriv;
- struct usb_ctl_request req;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
- setup = (struct libusb_control_setup *)transfer->buffer;
-
- usbi_dbg("type %d request %d value %d index %d length %d timeout %d",
- setup->bmRequestType, setup->bRequest,
- libusb_le16_to_cpu(setup->wValue),
- libusb_le16_to_cpu(setup->wIndex),
- libusb_le16_to_cpu(setup->wLength), transfer->timeout);
-
- req.ucr_request.bmRequestType = setup->bmRequestType;
- req.ucr_request.bRequest = setup->bRequest;
- /* Don't use USETW, libusb already deals with the endianness */
- (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
- (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
- (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
- req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
-
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- req.ucr_flags = USBD_SHORT_XFER_OK;
-
- if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
- return _errno_to_libusb(errno);
-
- itransfer->transferred = req.ucr_actlen;
-
- usbi_dbg("transferred %d", itransfer->transferred);
-
- return (0);
-}
-
-int
-_access_endpoint(struct libusb_transfer *transfer)
-{
- struct handle_priv *hpriv;
- struct device_priv *dpriv;
- char *s, devnode[16];
- int fd, endpt;
- mode_t mode;
-
- hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
- dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
-
- endpt = UE_GET_ADDR(transfer->endpoint);
- mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
-
- usbi_dbg("endpoint %d mode %d", endpt, mode);
-
- if (hpriv->endpoints[endpt] < 0) {
- /* Pick the right node given the control one */
- strlcpy(devnode, dpriv->devnode, sizeof(devnode));
- s = strchr(devnode, '.');
- snprintf(s, 4, ".%02d", endpt);
-
- /* We may need to read/write to the same endpoint later. */
- if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
- if ((fd = open(devnode, mode)) < 0)
- return (-1);
-
- hpriv->endpoints[endpt] = fd;
- }
-
- return (hpriv->endpoints[endpt]);
-}
-
-int
-_sync_gen_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- int fd, nr = 1;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- /*
- * Bulk, Interrupt or Isochronous transfer depends on the
- * endpoint and thus the node to open.
- */
- if ((fd = _access_endpoint(transfer)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if (IS_XFERIN(transfer)) {
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
- return _errno_to_libusb(errno);
-
- nr = read(fd, transfer->buffer, transfer->length);
- } else {
- nr = write(fd, transfer->buffer, transfer->length);
- }
-
- if (nr < 0)
- return _errno_to_libusb(errno);
-
- itransfer->transferred = nr;
-
- return (0);
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c
deleted file mode 100644
index c660257..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/openbsd_usb.c
+++ /dev/null
@@ -1,771 +0,0 @@
-/*
- * Copyright © 2011-2013 Martin Pieuchot <mpi@openbsd.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 <sys/time.h>
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <dev/usb/usb.h>
-
-#include "libusbi.h"
-
-struct device_priv {
- char *devname; /* name of the ugen(4) node */
- int fd; /* device file descriptor */
-
- unsigned char *cdesc; /* active config descriptor */
- usb_device_descriptor_t ddesc; /* usb device descriptor */
-};
-
-struct handle_priv {
- int endpoints[USB_MAX_ENDPOINTS];
-};
-
-/*
- * Backend functions
- */
-static int obsd_get_device_list(struct libusb_context *,
- struct discovered_devs **);
-static int obsd_open(struct libusb_device_handle *);
-static void obsd_close(struct libusb_device_handle *);
-
-static int obsd_get_device_descriptor(struct libusb_device *, unsigned char *,
- int *);
-static int obsd_get_active_config_descriptor(struct libusb_device *,
- unsigned char *, size_t, int *);
-static int obsd_get_config_descriptor(struct libusb_device *, uint8_t,
- unsigned char *, size_t, int *);
-
-static int obsd_get_configuration(struct libusb_device_handle *, int *);
-static int obsd_set_configuration(struct libusb_device_handle *, int);
-
-static int obsd_claim_interface(struct libusb_device_handle *, int);
-static int obsd_release_interface(struct libusb_device_handle *, int);
-
-static int obsd_set_interface_altsetting(struct libusb_device_handle *, int,
- int);
-static int obsd_clear_halt(struct libusb_device_handle *, unsigned char);
-static int obsd_reset_device(struct libusb_device_handle *);
-static void obsd_destroy_device(struct libusb_device *);
-
-static int obsd_submit_transfer(struct usbi_transfer *);
-static int obsd_cancel_transfer(struct usbi_transfer *);
-static void obsd_clear_transfer_priv(struct usbi_transfer *);
-static int obsd_handle_transfer_completion(struct usbi_transfer *);
-static int obsd_clock_gettime(int, struct timespec *);
-
-/*
- * Private functions
- */
-static int _errno_to_libusb(int);
-static int _cache_active_config_descriptor(struct libusb_device *);
-static int _sync_control_transfer(struct usbi_transfer *);
-static int _sync_gen_transfer(struct usbi_transfer *);
-static int _access_endpoint(struct libusb_transfer *);
-
-static int _bus_open(int);
-
-
-const struct usbi_os_backend openbsd_backend = {
- "Synchronous OpenBSD backend",
- 0,
- NULL, /* init() */
- NULL, /* exit() */
- obsd_get_device_list,
- NULL, /* hotplug_poll */
- obsd_open,
- obsd_close,
-
- obsd_get_device_descriptor,
- obsd_get_active_config_descriptor,
- obsd_get_config_descriptor,
- NULL, /* get_config_descriptor_by_value() */
-
- obsd_get_configuration,
- obsd_set_configuration,
-
- obsd_claim_interface,
- obsd_release_interface,
-
- obsd_set_interface_altsetting,
- obsd_clear_halt,
- obsd_reset_device,
-
- NULL, /* alloc_streams */
- NULL, /* free_streams */
-
- NULL, /* dev_mem_alloc() */
- NULL, /* dev_mem_free() */
-
- NULL, /* kernel_driver_active() */
- NULL, /* detach_kernel_driver() */
- NULL, /* attach_kernel_driver() */
-
- obsd_destroy_device,
-
- obsd_submit_transfer,
- obsd_cancel_transfer,
- obsd_clear_transfer_priv,
-
- NULL, /* handle_events() */
- obsd_handle_transfer_completion,
-
- obsd_clock_gettime,
- sizeof(struct device_priv),
- sizeof(struct handle_priv),
- 0, /* transfer_priv_size */
-};
-
-#define DEVPATH "/dev/"
-#define USBDEV DEVPATH "usb"
-
-int
-obsd_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- struct discovered_devs *ddd;
- struct libusb_device *dev;
- struct device_priv *dpriv;
- struct usb_device_info di;
- struct usb_device_ddesc dd;
- unsigned long session_id;
- char devices[USB_MAX_DEVICES];
- char busnode[16];
- char *udevname;
- int fd, addr, i, j;
-
- usbi_dbg("");
-
- for (i = 0; i < 8; i++) {
- snprintf(busnode, sizeof(busnode), USBDEV "%d", i);
-
- if ((fd = open(busnode, O_RDWR)) < 0) {
- if (errno != ENOENT && errno != ENXIO)
- usbi_err(ctx, "could not open %s", busnode);
- continue;
- }
-
- bzero(devices, sizeof(devices));
- for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
- if (devices[addr])
- continue;
-
- di.udi_addr = addr;
- if (ioctl(fd, USB_DEVICEINFO, &di) < 0)
- continue;
-
- /*
- * XXX If ugen(4) is attached to the USB device
- * it will be used.
- */
- udevname = NULL;
- for (j = 0; j < USB_MAX_DEVNAMES; j++)
- if (!strncmp("ugen", di.udi_devnames[j], 4)) {
- udevname = strdup(di.udi_devnames[j]);
- break;
- }
-
- session_id = (di.udi_bus << 8 | di.udi_addr);
- dev = usbi_get_device_by_session_id(ctx, session_id);
-
- if (dev == NULL) {
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL) {
- close(fd);
- return (LIBUSB_ERROR_NO_MEM);
- }
-
- dev->bus_number = di.udi_bus;
- dev->device_address = di.udi_addr;
- dev->speed = di.udi_speed;
-
- dpriv = (struct device_priv *)dev->os_priv;
- dpriv->fd = -1;
- dpriv->cdesc = NULL;
- dpriv->devname = udevname;
-
- dd.udd_bus = di.udi_bus;
- dd.udd_addr = di.udi_addr;
- if (ioctl(fd, USB_DEVICE_GET_DDESC, &dd) < 0) {
- libusb_unref_device(dev);
- continue;
- }
- dpriv->ddesc = dd.udd_desc;
-
- if (_cache_active_config_descriptor(dev)) {
- libusb_unref_device(dev);
- continue;
- }
-
- if (usbi_sanitize_device(dev)) {
- libusb_unref_device(dev);
- continue;
- }
- }
-
- ddd = discovered_devs_append(*discdevs, dev);
- if (ddd == NULL) {
- close(fd);
- return (LIBUSB_ERROR_NO_MEM);
- }
- libusb_unref_device(dev);
-
- *discdevs = ddd;
- devices[addr] = 1;
- }
-
- close(fd);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_open(struct libusb_device_handle *handle)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
- char devnode[16];
-
- if (dpriv->devname) {
- /*
- * Only open ugen(4) attached devices read-write, all
- * read-only operations are done through the bus node.
- */
- snprintf(devnode, sizeof(devnode), DEVPATH "%s.00",
- dpriv->devname);
- dpriv->fd = open(devnode, O_RDWR);
- if (dpriv->fd < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg("open %s: fd %d", devnode, dpriv->fd);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-obsd_close(struct libusb_device_handle *handle)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
-
- if (dpriv->devname) {
- usbi_dbg("close: fd %d", dpriv->fd);
-
- close(dpriv->fd);
- dpriv->fd = -1;
- }
-}
-
-int
-obsd_get_device_descriptor(struct libusb_device *dev, unsigned char *buf,
- int *host_endian)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-
- usbi_dbg("");
-
- memcpy(buf, &dpriv->ddesc, DEVICE_DESC_LENGTH);
-
- *host_endian = 0;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_get_active_config_descriptor(struct libusb_device *dev,
- unsigned char *buf, size_t len, int *host_endian)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
- usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
-
- len = MIN(len, UGETW(ucd->wTotalLength));
-
- usbi_dbg("len %d", len);
-
- memcpy(buf, dpriv->cdesc, len);
-
- *host_endian = 0;
-
- return (len);
-}
-
-int
-obsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- unsigned char *buf, size_t len, int *host_endian)
-{
- struct usb_device_fdesc udf;
- int fd, err;
-
- if ((fd = _bus_open(dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- udf.udf_bus = dev->bus_number;
- udf.udf_addr = dev->device_address;
- udf.udf_config_index = idx;
- udf.udf_size = len;
- udf.udf_data = buf;
-
- usbi_dbg("index %d, len %d", udf.udf_config_index, len);
-
- if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(err);
- }
- close(fd);
-
- *host_endian = 0;
-
- return (len);
-}
-
-int
-obsd_get_configuration(struct libusb_device_handle *handle, int *config)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
- usb_config_descriptor_t *ucd = (usb_config_descriptor_t *)dpriv->cdesc;
-
- *config = ucd->bConfigurationValue;
-
- usbi_dbg("bConfigurationValue %d", *config);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_set_configuration(struct libusb_device_handle *handle, int config)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
-
- if (dpriv->devname == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- usbi_dbg("bConfigurationValue %d", config);
-
- if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
- return _errno_to_libusb(errno);
-
- return _cache_active_config_descriptor(handle->dev);
-}
-
-int
-obsd_claim_interface(struct libusb_device_handle *handle, int iface)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- int i;
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- hpriv->endpoints[i] = -1;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_release_interface(struct libusb_device_handle *handle, int iface)
-{
- struct handle_priv *hpriv = (struct handle_priv *)handle->os_priv;
- int i;
-
- for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- if (hpriv->endpoints[i] >= 0)
- close(hpriv->endpoints[i]);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
- int altsetting)
-{
- struct device_priv *dpriv = (struct device_priv *)handle->dev->os_priv;
- struct usb_alt_interface intf;
-
- if (dpriv->devname == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- usbi_dbg("iface %d, setting %d", iface, altsetting);
-
- memset(&intf, 0, sizeof(intf));
-
- intf.uai_interface_index = iface;
- intf.uai_alt_no = altsetting;
-
- if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
- return _errno_to_libusb(errno);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
-{
- struct usb_ctl_request req;
- int fd, err;
-
- if ((fd = _bus_open(handle->dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg("");
-
- req.ucr_addr = handle->dev->device_address;
- req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
- req.ucr_request.bRequest = UR_CLEAR_FEATURE;
- USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
- USETW(req.ucr_request.wIndex, endpoint);
- USETW(req.ucr_request.wLength, 0);
-
- if (ioctl(fd, USB_REQUEST, &req) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(err);
- }
- close(fd);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_reset_device(struct libusb_device_handle *handle)
-{
- usbi_dbg("");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-void
-obsd_destroy_device(struct libusb_device *dev)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
-
- usbi_dbg("");
-
- free(dpriv->cdesc);
- free(dpriv->devname);
-}
-
-int
-obsd_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct handle_priv *hpriv;
- int err = 0;
-
- usbi_dbg("");
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- err = _sync_control_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- if (IS_XFEROUT(transfer)) {
- /* Isochronous write is not supported */
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) &&
- transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- err = _sync_gen_transfer(itransfer);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- if (err)
- return (err);
-
- usbi_signal_transfer_completion(itransfer);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-obsd_cancel_transfer(struct usbi_transfer *itransfer)
-{
- usbi_dbg("");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-void
-obsd_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- usbi_dbg("");
-
- /* Nothing to do */
-}
-
-int
-obsd_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
-}
-
-int
-obsd_clock_gettime(int clkid, struct timespec *tp)
-{
- usbi_dbg("clock %d", clkid);
-
- if (clkid == USBI_CLOCK_REALTIME)
- return clock_gettime(CLOCK_REALTIME, tp);
-
- if (clkid == USBI_CLOCK_MONOTONIC)
- return clock_gettime(CLOCK_MONOTONIC, tp);
-
- return (LIBUSB_ERROR_INVALID_PARAM);
-}
-
-int
-_errno_to_libusb(int err)
-{
- usbi_dbg("error: %s (%d)", strerror(err), err);
-
- switch (err) {
- case EIO:
- return (LIBUSB_ERROR_IO);
- case EACCES:
- return (LIBUSB_ERROR_ACCESS);
- case ENOENT:
- return (LIBUSB_ERROR_NO_DEVICE);
- case ENOMEM:
- return (LIBUSB_ERROR_NO_MEM);
- case ETIMEDOUT:
- return (LIBUSB_ERROR_TIMEOUT);
- }
-
- return (LIBUSB_ERROR_OTHER);
-}
-
-int
-_cache_active_config_descriptor(struct libusb_device *dev)
-{
- struct device_priv *dpriv = (struct device_priv *)dev->os_priv;
- struct usb_device_cdesc udc;
- struct usb_device_fdesc udf;
- unsigned char* buf;
- int fd, len, err;
-
- if ((fd = _bus_open(dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- usbi_dbg("fd %d, addr %d", fd, dev->device_address);
-
- udc.udc_bus = dev->bus_number;
- udc.udc_addr = dev->device_address;
- udc.udc_config_index = USB_CURRENT_CONFIG_INDEX;
- if (ioctl(fd, USB_DEVICE_GET_CDESC, &udc) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(errno);
- }
-
- usbi_dbg("active bLength %d", udc.udc_desc.bLength);
-
- len = UGETW(udc.udc_desc.wTotalLength);
- buf = malloc(len);
- if (buf == NULL)
- return (LIBUSB_ERROR_NO_MEM);
-
- udf.udf_bus = dev->bus_number;
- udf.udf_addr = dev->device_address;
- udf.udf_config_index = udc.udc_config_index;
- udf.udf_size = len;
- udf.udf_data = buf;
-
- usbi_dbg("index %d, len %d", udf.udf_config_index, len);
-
- if (ioctl(fd, USB_DEVICE_GET_FDESC, &udf) < 0) {
- err = errno;
- close(fd);
- free(buf);
- return _errno_to_libusb(err);
- }
- close(fd);
-
- if (dpriv->cdesc)
- free(dpriv->cdesc);
- dpriv->cdesc = buf;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-_sync_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct libusb_control_setup *setup;
- struct device_priv *dpriv;
- struct usb_ctl_request req;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
- setup = (struct libusb_control_setup *)transfer->buffer;
-
- usbi_dbg("type %x request %x value %x index %d length %d timeout %d",
- setup->bmRequestType, setup->bRequest,
- libusb_le16_to_cpu(setup->wValue),
- libusb_le16_to_cpu(setup->wIndex),
- libusb_le16_to_cpu(setup->wLength), transfer->timeout);
-
- req.ucr_addr = transfer->dev_handle->dev->device_address;
- req.ucr_request.bmRequestType = setup->bmRequestType;
- req.ucr_request.bRequest = setup->bRequest;
- /* Don't use USETW, libusb already deals with the endianness */
- (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
- (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
- (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
- req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
-
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- req.ucr_flags = USBD_SHORT_XFER_OK;
-
- if (dpriv->devname == NULL) {
- /*
- * XXX If the device is not attached to ugen(4) it is
- * XXX still possible to submit a control transfer but
- * XXX with the default timeout only.
- */
- int fd, err;
-
- if ((fd = _bus_open(transfer->dev_handle->dev->bus_number)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(fd, USB_REQUEST, &req)) < 0) {
- err = errno;
- close(fd);
- return _errno_to_libusb(err);
- }
- close(fd);
- } else {
- if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
- return _errno_to_libusb(errno);
- }
-
- itransfer->transferred = req.ucr_actlen;
-
- usbi_dbg("transferred %d", itransfer->transferred);
-
- return (0);
-}
-
-int
-_access_endpoint(struct libusb_transfer *transfer)
-{
- struct handle_priv *hpriv;
- struct device_priv *dpriv;
- char devnode[16];
- int fd, endpt;
- mode_t mode;
-
- hpriv = (struct handle_priv *)transfer->dev_handle->os_priv;
- dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
-
- endpt = UE_GET_ADDR(transfer->endpoint);
- mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
-
- usbi_dbg("endpoint %d mode %d", endpt, mode);
-
- if (hpriv->endpoints[endpt] < 0) {
- /* Pick the right endpoint node */
- snprintf(devnode, sizeof(devnode), DEVPATH "%s.%02d",
- dpriv->devname, endpt);
-
- /* We may need to read/write to the same endpoint later. */
- if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
- if ((fd = open(devnode, mode)) < 0)
- return (-1);
-
- hpriv->endpoints[endpt] = fd;
- }
-
- return (hpriv->endpoints[endpt]);
-}
-
-int
-_sync_gen_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct device_priv *dpriv;
- int fd, nr = 1;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- dpriv = (struct device_priv *)transfer->dev_handle->dev->os_priv;
-
- if (dpriv->devname == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- /*
- * Bulk, Interrupt or Isochronous transfer depends on the
- * endpoint and thus the node to open.
- */
- if ((fd = _access_endpoint(transfer)) < 0)
- return _errno_to_libusb(errno);
-
- if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
- return _errno_to_libusb(errno);
-
- if (IS_XFERIN(transfer)) {
- if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
- if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
- return _errno_to_libusb(errno);
-
- nr = read(fd, transfer->buffer, transfer->length);
- } else {
- nr = write(fd, transfer->buffer, transfer->length);
- }
-
- if (nr < 0)
- return _errno_to_libusb(errno);
-
- itransfer->transferred = nr;
-
- return (0);
-}
-
-int
-_bus_open(int number)
-{
- char busnode[16];
-
- snprintf(busnode, sizeof(busnode), USBDEV "%d", number);
-
- return open(busnode, O_RDWR);
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c
deleted file mode 100644
index e2f55a5..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * poll_posix: poll compatibility wrapper for POSIX systems
- * Copyright © 2013 RealVNC Ltd.
- *
- * 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 <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "libusbi.h"
-
-int usbi_pipe(int pipefd[2])
-{
- int ret = pipe(pipefd);
- if (ret != 0) {
- return ret;
- }
- ret = fcntl(pipefd[1], F_GETFL);
- if (ret == -1) {
- usbi_dbg("Failed to get pipe fd flags: %d", errno);
- goto err_close_pipe;
- }
- ret = fcntl(pipefd[1], F_SETFL, ret | O_NONBLOCK);
- if (ret != 0) {
- usbi_dbg("Failed to set non-blocking on new pipe: %d", errno);
- goto err_close_pipe;
- }
-
- return 0;
-
-err_close_pipe:
- usbi_close(pipefd[0]);
- usbi_close(pipefd[1]);
- return ret;
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h
deleted file mode 100644
index 5b4b2c9..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_posix.h
+++ /dev/null
@@ -1,11 +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_poll poll
-
-int usbi_pipe(int pipefd[2]);
-
-#endif /* LIBUSB_POLL_POSIX_H */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c
deleted file mode 100644
index 9825607..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.c
+++ /dev/null
@@ -1,728 +0,0 @@
-/*
- * poll_windows: poll compatibility wrapper for Windows
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
- * 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 RW_READ and once in RW_WRITE 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 <config.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.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
-// MSVC++ < 2005 cannot use a variadic argument and non MSVC
-// compilers produce warnings if parenthesis are omitted.
-#if defined(_MSC_VER) && (_MSC_VER < 1400)
-#define poll_dbg
-#else
-#define poll_dbg(...)
-#endif
-#endif
-
-#if defined(_PREFAST_)
-#pragma warning(disable:28719)
-#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, NULL, 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;
-LONG pipe_number = 0;
-static volatile LONG compat_spinlock = 0;
-
-#if !defined(_WIN32_WCE)
-// 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 Use_Duplicate_Handles (pCancelIoEx == NULL)
-
-static inline void setup_cancel_io(void)
-{
- HMODULE hKernel32 = GetModuleHandleA("KERNEL32");
- if (hKernel32 != NULL) {
- pCancelIoEx = (BOOL (__stdcall *)(HANDLE,LPOVERLAPPED))
- GetProcAddress(hKernel32, "CancelIoEx");
- }
- usbi_dbg("Will use CancelIo%s for I/O cancellation",
- Use_Duplicate_Handles?"":"Ex");
-}
-
-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 (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
- // Cancel outstanding transfer via the specific callback
- (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
- return TRUE;
- }
- if (pCancelIoEx != NULL) {
- 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;
-}
-#else
-#define Use_Duplicate_Handles FALSE
-
-static __inline void setup_cancel_io()
-{
- // No setup needed on WinCE
-}
-
-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 (poll_fd[_index].itransfer && poll_fd[_index].cancel_fn) {
- // Cancel outstanding transfer via the specific callback
- (*poll_fd[_index].cancel_fn)(poll_fd[_index].itransfer);
- }
- return TRUE;
-}
-#endif
-
-// Init
-void init_polling(void)
-{
- int i;
-
- while (InterlockedExchange((LONG *)&compat_spinlock, 1) == 1) {
- SleepEx(0, TRUE);
- }
- if (!is_polling_set) {
- setup_cancel_io();
- 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);
- }
- is_polling_set = TRUE;
- }
- InterlockedExchange((LONG *)&compat_spinlock, 0);
-}
-
-// Internal function to retrieve the table index (and lock the fd mutex)
-static 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;
-}
-
-static OVERLAPPED *create_overlapped(void)
-{
- OVERLAPPED *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;
-}
-
-static void free_overlapped(OVERLAPPED *overlapped)
-{
- if (overlapped == NULL)
- return;
-
- if ( (overlapped->hEvent != 0)
- && (overlapped->hEvent != INVALID_HANDLE_VALUE) ) {
- CloseHandle(overlapped->hEvent);
- }
- free(overlapped);
-}
-
-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);
- free_overlapped(poll_fd[i].overlapped);
- if (Use_Duplicate_Handles) {
- // Close duplicate handle
- if (_poll_fd[i].original_handle != INVALID_HANDLE_VALUE) {
- CloseHandle(poll_fd[i].handle);
- }
- }
- poll_fd[i] = INVALID_WINFD;
- LeaveCriticalSection(&_poll_fd[i].mutex);
- DeleteCriticalSection(&_poll_fd[i].mutex);
- }
- }
- InterlockedExchange((LONG *)&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 = create_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;
-
- 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;
- }
-
- // Use index as the unique fd number
- poll_fd[i].fd = i;
- // Read end of the "pipe"
- filedes[0] = poll_fd[i].fd;
- // We can use the same handle for both ends
- filedes[1] = 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;
- }
- }
- free_overlapped(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, struct usbi_transfer *itransfer, cancel_transfer *cancel_fn)
-{
- int i;
- struct winfd wfd = INVALID_WINFD;
- OVERLAPPED* overlapped = NULL;
-
- CHECK_INIT_POLLING;
-
- if ((handle == 0) || (handle == INVALID_HANDLE_VALUE)) {
- return INVALID_WINFD;
- }
-
- wfd.itransfer = itransfer;
- wfd.cancel_fn = cancel_fn;
-
- if ((access_mode != RW_READ) && (access_mode != RW_WRITE)) {
- usbi_warn(NULL, "only one of RW_READ or RW_WRITE are supported. "
- "If you want to poll for R/W simultaneously, create multiple fds from the same handle.");
- return INVALID_WINFD;
- }
- if (access_mode == RW_READ) {
- wfd.rw = RW_READ;
- } else {
- wfd.rw = RW_WRITE;
- }
-
- overlapped = create_overlapped();
- if(overlapped == NULL) {
- 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;
- }
- // Use index as the unique fd number
- wfd.fd = i;
- // Attempt to emulate some of the CancelIoEx behaviour on platforms
- // that don't have it
- if (Use_Duplicate_Handles) {
- _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);
- return wfd;
- }
- }
- free_overlapped(overlapped);
- return INVALID_WINFD;
-}
-
-static void _free_index(int _index)
-{
- // Cancel any async IO (Don't care about the validity of our handles for this)
- cancel_io(_index);
- // close the duplicate handle (if we have an actual duplicate)
- if (Use_Duplicate_Handles) {
- 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(struct winfd *wfd)
-{
- int _index;
-
- CHECK_INIT_POLLING;
-
- _index = _fd_to_index_and_lock(wfd->fd);
- if (_index < 0) {
- return;
- }
- _free_index(_index);
- *wfd = INVALID_WINFD;
- 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;
-
- CHECK_INIT_POLLING;
-
- triggered = 0;
- handles_to_wait_on = (HANDLE*) calloc(nfds+1, sizeof(HANDLE)); // +1 for fd_update
- handle_to_index = (int*) calloc(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;
- nb_handles_to_wait_on++;
- }
- LeaveCriticalSection(&_poll_fd[_index].mutex);
- }
-
- // If nothing was triggered, wait on all fds that require it
- if ((timeout != 0) && (triggered == 0) && (nb_handles_to_wait_on != 0)) {
- if (timeout < 0) {
- poll_dbg("starting infinite wait for %u handles...", (unsigned int)nb_handles_to_wait_on);
- } else {
- poll_dbg("starting %d ms wait for %u handles...", timeout, (unsigned 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)) {
- 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);
- }
- 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 {
- free_overlapped(poll_fd[_index].overlapped);
- 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;
- UNUSED(buf);
-
- 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, (unsigned int)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;
- UNUSED(buf);
-
- 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: %u", (unsigned int)GetLastError());
- errno = EIO;
- goto out;
- }
-
- poll_dbg("clr pipe event (fd = %d, thread = %08X)", _index, (unsigned int)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/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h
deleted file mode 100644
index aa4c985..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/poll_windows.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Windows compat: POSIX compatibility wrapper
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2010 Pete Batard <pete@akeo.ie>
- * 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
- *
- */
-#pragma once
-
-#if defined(_MSC_VER)
-// disable /W4 MSVC warnings that are benign
-#pragma warning(disable:4127) // conditional expression is constant
-#endif
-
-// 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
-#if defined(_WIN32_WCE)
-// WinCE doesn't have a HasOverlappedIoCompleted() macro, so attempt to emulate it
-#define HasOverlappedIoCompleted(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) != STATUS_PENDING)
-#endif
-#define HasOverlappedIoCompletedSync(lpOverlapped) (((DWORD)(lpOverlapped)->Internal) == STATUS_COMPLETED_SYNCHRONOUSLY)
-
-#define DUMMY_HANDLE ((HANDLE)(LONG_PTR)-2)
-
-/* Windows versions */
-enum windows_version {
- WINDOWS_CE = -2,
- WINDOWS_UNDEFINED = -1,
- WINDOWS_UNSUPPORTED = 0,
- WINDOWS_XP = 0x51,
- WINDOWS_2003 = 0x52, // Also XP x64
- WINDOWS_VISTA = 0x60,
- WINDOWS_7 = 0x61,
- WINDOWS_8 = 0x62,
- WINDOWS_8_1_OR_LATER = 0x63,
- WINDOWS_MAX
-};
-extern int 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 */
-
-struct pollfd {
- int fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
-};
-
-// access modes
-enum rw_type {
- RW_NONE,
- RW_READ,
- RW_WRITE,
-};
-
-// fd struct that can be used for polling on Windows
-typedef int cancel_transfer(struct usbi_transfer *itransfer);
-
-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
- struct usbi_transfer *itransfer; // Associated transfer, or NULL if completed
- cancel_transfer *cancel_fn; // Function pointer to cancel transfer API
- 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,
- struct usbi_transfer *transfer, cancel_transfer *cancel_fn);
-void usbi_free_fd(struct winfd* winfd);
-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
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c
deleted file mode 100644
index cb60897..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.c
+++ /dev/null
@@ -1,1292 +0,0 @@
-/*
- *
- * Copyright (c) 2016, Oracle and/or its affiliates.
- *
- * 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 <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <strings.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <aio.h>
-#include <libdevinfo.h>
-#include <sys/usb/clients/ugen/usb_ugen.h>
-#include <sys/usb/usba.h>
-#include <sys/pci.h>
-
-#include "libusbi.h"
-#include "sunos_usb.h"
-
-/*
- * Backend functions
- */
-static int sunos_init(struct libusb_context *);
-static void sunos_exit(void);
-static int sunos_get_device_list(struct libusb_context *,
- struct discovered_devs **);
-static int sunos_open(struct libusb_device_handle *);
-static void sunos_close(struct libusb_device_handle *);
-static int sunos_get_device_descriptor(struct libusb_device *,
- uint8_t*, int *);
-static int sunos_get_active_config_descriptor(struct libusb_device *,
- uint8_t*, size_t, int *);
-static int sunos_get_config_descriptor(struct libusb_device *, uint8_t,
- uint8_t*, size_t, int *);
-static int sunos_get_configuration(struct libusb_device_handle *, int *);
-static int sunos_set_configuration(struct libusb_device_handle *, int);
-static int sunos_claim_interface(struct libusb_device_handle *, int);
-static int sunos_release_interface(struct libusb_device_handle *, int);
-static int sunos_set_interface_altsetting(struct libusb_device_handle *,
- int, int);
-static int sunos_clear_halt(struct libusb_device_handle *, uint8_t);
-static int sunos_reset_device(struct libusb_device_handle *);
-static void sunos_destroy_device(struct libusb_device *);
-static int sunos_submit_transfer(struct usbi_transfer *);
-static int sunos_cancel_transfer(struct usbi_transfer *);
-static void sunos_clear_transfer_priv(struct usbi_transfer *);
-static int sunos_handle_transfer_completion(struct usbi_transfer *);
-static int sunos_clock_gettime(int, struct timespec *);
-
-/*
- * Private functions
- */
-static int _errno_to_libusb(int);
-static int sunos_usb_get_status(int fd);
-
-static int sunos_init(struct libusb_context *ctx)
-{
- return (LIBUSB_SUCCESS);
-}
-
-static void sunos_exit(void)
-{
- usbi_dbg("");
-}
-
-static int
-sunos_fill_in_dev_info(di_node_t node, struct libusb_device *dev)
-{
- int proplen;
- int n, *addr, *port_prop;
- char *phypath;
- uint8_t *rdata;
- struct libusb_device_descriptor *descr;
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
-
- /* Device descriptors */
- proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
- "usb-dev-descriptor", &rdata);
- if (proplen <= 0) {
-
- return (LIBUSB_ERROR_IO);
- }
-
- descr = (struct libusb_device_descriptor *)rdata;
- bcopy(descr, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE);
- dpriv->dev_descr.bcdUSB = libusb_cpu_to_le16(descr->bcdUSB);
- dpriv->dev_descr.idVendor = libusb_cpu_to_le16(descr->idVendor);
- dpriv->dev_descr.idProduct = libusb_cpu_to_le16(descr->idProduct);
- dpriv->dev_descr.bcdDevice = libusb_cpu_to_le16(descr->bcdDevice);
-
- /* Raw configuration descriptors */
- proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
- "usb-raw-cfg-descriptors", &rdata);
- if (proplen <= 0) {
- usbi_dbg("can't find raw config descriptors");
-
- return (LIBUSB_ERROR_IO);
- }
- dpriv->raw_cfgdescr = calloc(1, proplen);
- if (dpriv->raw_cfgdescr == NULL) {
- return (LIBUSB_ERROR_NO_MEM);
- } else {
- bcopy(rdata, dpriv->raw_cfgdescr, proplen);
- dpriv->cfgvalue = ((struct libusb_config_descriptor *)
- rdata)->bConfigurationValue;
- }
-
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &port_prop);
-
- if ((n != 1) || (*port_prop <= 0)) {
- return (LIBUSB_ERROR_IO);
- }
- dev->port_number = *port_prop;
-
- /* device physical path */
- phypath = di_devfs_path(node);
- if (phypath) {
- dpriv->phypath = strdup(phypath);
- di_devfs_path_free(phypath);
- } else {
- free(dpriv->raw_cfgdescr);
-
- return (LIBUSB_ERROR_IO);
- }
-
- /* address */
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "assigned-address", &addr);
- if (n != 1 || *addr == 0) {
- usbi_dbg("can't get address");
- } else {
- dev->device_address = *addr;
- }
-
- /* speed */
- if (di_prop_exists(DDI_DEV_T_ANY, node, "low-speed") == 1) {
- dev->speed = LIBUSB_SPEED_LOW;
- } else if (di_prop_exists(DDI_DEV_T_ANY, node, "high-speed") == 1) {
- dev->speed = LIBUSB_SPEED_HIGH;
- } else if (di_prop_exists(DDI_DEV_T_ANY, node, "full-speed") == 1) {
- dev->speed = LIBUSB_SPEED_FULL;
- } else if (di_prop_exists(DDI_DEV_T_ANY, node, "super-speed") == 1) {
- dev->speed = LIBUSB_SPEED_SUPER;
- }
-
- usbi_dbg("vid=%x pid=%x, path=%s, bus_nmber=0x%x, port_number=%d, "
- "speed=%d", dpriv->dev_descr.idVendor, dpriv->dev_descr.idProduct,
- dpriv->phypath, dev->bus_number, dev->port_number, dev->speed);
-
- return (LIBUSB_SUCCESS);
-}
-
-
-static int
-sunos_add_devices(di_devlink_t link, void *arg)
-{
- struct devlink_cbarg *largs = (struct devlink_cbarg *)arg;
- struct node_args *nargs;
- di_node_t myself, pnode;
- uint64_t session_id = 0;
- uint16_t bdf = 0;
- struct libusb_device *dev;
- sunos_dev_priv_t *devpriv;
- const char *path, *newpath;
- int n, i;
- int *addr_prop;
- uint8_t bus_number = 0;
-
- nargs = (struct node_args *)largs->nargs;
- myself = largs->myself;
- if (nargs->last_ugenpath) {
- /* the same node's links */
- return (DI_WALK_CONTINUE);
- }
-
- /*
- * Construct session ID.
- * session ID = ...parent hub addr|hub addr|dev addr.
- */
- pnode = myself;
- i = 0;
- while (pnode != DI_NODE_NIL) {
- if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) {
- /* walk to root */
- uint32_t *regbuf = NULL;
- uint32_t reg;
-
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg",
- (int **)&regbuf);
- reg = regbuf[0];
- bdf = (PCI_REG_BUS_G(reg) << 8) |
- (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
- session_id |= (bdf << i * 8);
-
- /* same as 'unit-address' property */
- bus_number =
- (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
-
- usbi_dbg("device bus address=%s:%x",
- di_bus_addr(pnode), bus_number);
-
- break;
- }
-
- /* usb_addr */
- n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode,
- "assigned-address", &addr_prop);
- if ((n != 1) || (addr_prop[0] == 0)) {
- usbi_dbg("cannot get valid usb_addr");
-
- return (DI_WALK_CONTINUE);
- }
-
- session_id |= ((addr_prop[0] & 0xff) << i * 8);
- if (++i > 7)
- break;
-
- pnode = di_parent_node(pnode);
- }
-
- path = di_devlink_path(link);
- dev = usbi_get_device_by_session_id(nargs->ctx, session_id);
- if (dev == NULL) {
- dev = usbi_alloc_device(nargs->ctx, session_id);
- if (dev == NULL) {
- usbi_dbg("can't alloc device");
-
- return (DI_WALK_TERMINATE);
- }
- devpriv = (sunos_dev_priv_t *)dev->os_priv;
- if ((newpath = strrchr(path, '/')) == NULL) {
- libusb_unref_device(dev);
-
- return (DI_WALK_TERMINATE);
- }
- devpriv->ugenpath = strndup(path, strlen(path) -
- strlen(newpath));
- dev->bus_number = bus_number;
-
- if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) {
- libusb_unref_device(dev);
-
- return (DI_WALK_TERMINATE);
- }
- if (usbi_sanitize_device(dev) < 0) {
- libusb_unref_device(dev);
- usbi_dbg("sanatize failed: ");
- return (DI_WALK_TERMINATE);
- }
- } else {
- usbi_dbg("Dev %s exists", path);
- }
-
- devpriv = (sunos_dev_priv_t *)dev->os_priv;
- if (nargs->last_ugenpath == NULL) {
- /* first device */
- nargs->last_ugenpath = devpriv->ugenpath;
-
- if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
- usbi_dbg("cannot append device");
- }
-
- /*
- * we alloc and hence ref this dev. We don't need to ref it
- * hereafter. Front end or app should take care of their ref.
- */
- libusb_unref_device(dev);
- }
-
- usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
- devpriv->ugenpath, path, (uint64_t)session_id,
- (*nargs->discdevs)->len, bdf);
-
- return (DI_WALK_CONTINUE);
-}
-
-static int
-sunos_walk_minor_node_link(di_node_t node, void *args)
-{
- di_minor_t minor = DI_MINOR_NIL;
- char *minor_path;
- struct devlink_cbarg arg;
- struct node_args *nargs = (struct node_args *)args;
- di_devlink_handle_t devlink_hdl = nargs->dlink_hdl;
-
- /* walk each minor to find ugen devices */
- while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
- minor_path = di_devfs_minor_path(minor);
- arg.nargs = args;
- arg.myself = node;
- arg.minor = minor;
- (void) di_devlink_walk(devlink_hdl,
- "^usb/[0-9a-f]+[.][0-9a-f]+", minor_path,
- DI_PRIMARY_LINK, (void *)&arg, sunos_add_devices);
- di_devfs_path_free(minor_path);
- }
-
- /* switch to a different node */
- nargs->last_ugenpath = NULL;
-
- return (DI_WALK_CONTINUE);
-}
-
-int
-sunos_get_device_list(struct libusb_context * ctx,
- struct discovered_devs **discdevs)
-{
- di_node_t root_node;
- struct node_args args;
- di_devlink_handle_t devlink_hdl;
-
- args.ctx = ctx;
- args.discdevs = discdevs;
- args.last_ugenpath = NULL;
- if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
- usbi_dbg("di_int() failed: %s", strerror(errno));
- return (LIBUSB_ERROR_IO);
- }
-
- if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
- di_fini(root_node);
- usbi_dbg("di_devlink_init() failed: %s", strerror(errno));
-
- return (LIBUSB_ERROR_IO);
- }
- args.dlink_hdl = devlink_hdl;
-
- /* walk each node to find USB devices */
- if (di_walk_node(root_node, DI_WALK_SIBFIRST, &args,
- sunos_walk_minor_node_link) == -1) {
- usbi_dbg("di_walk_node() failed: %s", strerror(errno));
- di_fini(root_node);
-
- return (LIBUSB_ERROR_IO);
- }
-
- di_fini(root_node);
- di_devlink_fini(&devlink_hdl);
-
- usbi_dbg("%d devices", (*discdevs)->len);
-
- return ((*discdevs)->len);
-}
-
-static int
-sunos_usb_open_ep0(sunos_dev_handle_priv_t *hpriv, sunos_dev_priv_t *dpriv)
-{
- char filename[PATH_MAX + 1];
-
- if (hpriv->eps[0].datafd > 0) {
-
- return (LIBUSB_SUCCESS);
- }
- snprintf(filename, PATH_MAX, "%s/cntrl0", dpriv->ugenpath);
-
- usbi_dbg("opening %s", filename);
- hpriv->eps[0].datafd = open(filename, O_RDWR);
- if (hpriv->eps[0].datafd < 0) {
- return(_errno_to_libusb(errno));
- }
-
- snprintf(filename, PATH_MAX, "%s/cntrl0stat", dpriv->ugenpath);
- hpriv->eps[0].statfd = open(filename, O_RDONLY);
- if (hpriv->eps[0].statfd < 0) {
- close(hpriv->eps[0].datafd);
- hpriv->eps[0].datafd = -1;
-
- return(_errno_to_libusb(errno));
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-static void
-sunos_usb_close_all_eps(sunos_dev_handle_priv_t *hdev)
-{
- int i;
-
- /* not close ep0 */
- for (i = 1; i < USB_MAXENDPOINTS; i++) {
- if (hdev->eps[i].datafd != -1) {
- (void) close(hdev->eps[i].datafd);
- hdev->eps[i].datafd = -1;
- }
- if (hdev->eps[i].statfd != -1) {
- (void) close(hdev->eps[i].statfd);
- hdev->eps[i].statfd = -1;
- }
- }
-}
-
-static void
-sunos_usb_close_ep0(sunos_dev_handle_priv_t *hdev, sunos_dev_priv_t *dpriv)
-{
- if (hdev->eps[0].datafd >= 0) {
- close(hdev->eps[0].datafd);
- close(hdev->eps[0].statfd);
- hdev->eps[0].datafd = -1;
- hdev->eps[0].statfd = -1;
- }
-}
-
-static uchar_t
-sunos_usb_ep_index(uint8_t ep_addr)
-{
- return ((ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK) +
- ((ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? 16 : 0));
-}
-
-static int
-sunos_find_interface(struct libusb_device_handle *hdev,
- uint8_t endpoint, uint8_t *interface)
-{
- struct libusb_config_descriptor *config;
- int r;
- int iface_idx;
-
- r = libusb_get_active_config_descriptor(hdev->dev, &config);
- if (r < 0) {
- return (LIBUSB_ERROR_INVALID_PARAM);
- }
-
- 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) {
- *interface = iface_idx;
- libusb_free_config_descriptor(config);
-
- return (LIBUSB_SUCCESS);
- }
- }
- }
- }
- libusb_free_config_descriptor(config);
-
- return (LIBUSB_ERROR_INVALID_PARAM);
-}
-
-static int
-sunos_check_device_and_status_open(struct libusb_device_handle *hdl,
- uint8_t ep_addr, int ep_type)
-{
- char filename[PATH_MAX + 1], statfilename[PATH_MAX + 1];
- char cfg_num[16], alt_num[16];
- int fd, fdstat, mode;
- uint8_t ifc = 0;
- uint8_t ep_index;
- sunos_dev_handle_priv_t *hpriv;
-
- usbi_dbg("open ep 0x%02x", ep_addr);
- hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv;
- ep_index = sunos_usb_ep_index(ep_addr);
- /* ep already opened */
- if ((hpriv->eps[ep_index].datafd > 0) &&
- (hpriv->eps[ep_index].statfd > 0)) {
- usbi_dbg("ep 0x%02x already opened, return success",
- ep_addr);
-
- return (0);
- }
-
- if (sunos_find_interface(hdl, ep_addr, &ifc) < 0) {
- usbi_dbg("can't find interface for endpoint 0x%02x",
- ep_addr);
-
- return (LIBUSB_ERROR_ACCESS);
- }
-
- /* create filename */
- if (hpriv->config_index > 0) {
- (void) snprintf(cfg_num, sizeof (cfg_num), "cfg%d",
- hpriv->config_index + 1);
- } else {
- bzero(cfg_num, sizeof (cfg_num));
- }
-
- if (hpriv->altsetting[ifc] > 0) {
- (void) snprintf(alt_num, sizeof (alt_num), ".%d",
- hpriv->altsetting[ifc]);
- } else {
- bzero(alt_num, sizeof (alt_num));
- }
-
- (void) snprintf(filename, PATH_MAX, "%s/%sif%d%s%s%d",
- hpriv->dpriv->ugenpath, cfg_num, ifc, alt_num,
- (ep_addr & LIBUSB_ENDPOINT_DIR_MASK) ? "in" :
- "out", (ep_addr & LIBUSB_ENDPOINT_ADDRESS_MASK));
- (void) snprintf(statfilename, PATH_MAX, "%sstat", filename);
-
- /*
- * for interrupt IN endpoints, we need to enable one xfer
- * mode before opening the endpoint
- */
- if ((ep_type == LIBUSB_TRANSFER_TYPE_INTERRUPT) &&
- (ep_addr & LIBUSB_ENDPOINT_IN)) {
- char control = USB_EP_INTR_ONE_XFER;
- int count;
-
- /* open the status device node for the ep first RDWR */
- if ((fdstat = open(statfilename, O_RDWR)) == -1) {
- usbi_dbg("can't open %s RDWR: %d",
- statfilename, errno);
- } else {
- count = write(fdstat, &control, sizeof (control));
- if (count != 1) {
- /* this should have worked */
- usbi_dbg("can't write to %s: %d",
- statfilename, errno);
- (void) close(fdstat);
-
- return (errno);
- }
- /* close status node and open xfer node first */
- close (fdstat);
- }
- }
-
- /* open the xfer node first in case alt needs to be changed */
- if (ep_type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- mode = O_RDWR;
- } else if (ep_addr & LIBUSB_ENDPOINT_IN) {
- mode = O_RDONLY;
- } else {
- mode = O_WRONLY;
- }
-
- /*
- * IMPORTANT: must open data xfer node first and then open stat node
- * Otherwise, it will fail on multi-config or multi-altsetting devices
- * with "Device Busy" error. See ugen_epxs_switch_cfg_alt() and
- * ugen_epxs_check_alt_switch() in ugen driver source code.
- */
- if ((fd = open(filename, mode)) == -1) {
- usbi_dbg("can't open %s: %d(%s)", filename, errno,
- strerror(errno));
-
- return (errno);
- }
- /* open the status node */
- if ((fdstat = open(statfilename, O_RDONLY)) == -1) {
- usbi_dbg("can't open %s: %d", statfilename, errno);
-
- (void) close(fd);
-
- return (errno);
- }
-
- hpriv->eps[ep_index].datafd = fd;
- hpriv->eps[ep_index].statfd = fdstat;
- usbi_dbg("ep=0x%02x datafd=%d, statfd=%d", ep_addr, fd, fdstat);
-
- return (0);
-}
-
-int
-sunos_open(struct libusb_device_handle *handle)
-{
- sunos_dev_handle_priv_t *hpriv;
- sunos_dev_priv_t *dpriv;
- int i;
- int ret;
-
- hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
- dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
- hpriv->dpriv = dpriv;
-
- /* set all file descriptors to "closed" */
- for (i = 0; i < USB_MAXENDPOINTS; i++) {
- hpriv->eps[i].datafd = -1;
- hpriv->eps[i].statfd = -1;
- }
-
- if ((ret = sunos_usb_open_ep0(hpriv, dpriv)) != LIBUSB_SUCCESS) {
- usbi_dbg("fail: %d", ret);
- return (ret);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-void
-sunos_close(struct libusb_device_handle *handle)
-{
- sunos_dev_handle_priv_t *hpriv;
- sunos_dev_priv_t *dpriv;
-
- usbi_dbg("");
- if (!handle) {
- return;
- }
-
- hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
- if (!hpriv) {
- return;
- }
- dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
- if (!dpriv) {
- return;
- }
-
- sunos_usb_close_all_eps(hpriv);
- sunos_usb_close_ep0(hpriv, dpriv);
-}
-
-int
-sunos_get_device_descriptor(struct libusb_device *dev, uint8_t *buf,
- int *host_endian)
-{
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
-
- memcpy(buf, &dpriv->dev_descr, LIBUSB_DT_DEVICE_SIZE);
- *host_endian = 0;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_get_active_config_descriptor(struct libusb_device *dev,
- uint8_t *buf, size_t len, int *host_endian)
-{
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
- struct libusb_config_descriptor *cfg;
- int proplen;
- di_node_t node;
- uint8_t *rdata;
-
- /*
- * Keep raw configuration descriptors updated, in case config
- * has ever been changed through setCfg.
- */
- if ((node = di_init(dpriv->phypath, DINFOCPYALL)) == DI_NODE_NIL) {
- usbi_dbg("di_int() failed: %s", strerror(errno));
- return (LIBUSB_ERROR_IO);
- }
- proplen = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
- "usb-raw-cfg-descriptors", &rdata);
- if (proplen <= 0) {
- usbi_dbg("can't find raw config descriptors");
-
- return (LIBUSB_ERROR_IO);
- }
- dpriv->raw_cfgdescr = realloc(dpriv->raw_cfgdescr, proplen);
- if (dpriv->raw_cfgdescr == NULL) {
- return (LIBUSB_ERROR_NO_MEM);
- } else {
- bcopy(rdata, dpriv->raw_cfgdescr, proplen);
- dpriv->cfgvalue = ((struct libusb_config_descriptor *)
- rdata)->bConfigurationValue;
- }
- di_fini(node);
-
- cfg = (struct libusb_config_descriptor *)dpriv->raw_cfgdescr;
- len = MIN(len, libusb_le16_to_cpu(cfg->wTotalLength));
- memcpy(buf, dpriv->raw_cfgdescr, len);
- *host_endian = 0;
- usbi_dbg("path:%s len %d", dpriv->phypath, len);
-
- return (len);
-}
-
-int
-sunos_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
- uint8_t *buf, size_t len, int *host_endian)
-{
- /* XXX */
- return(sunos_get_active_config_descriptor(dev, buf, len, host_endian));
-}
-
-int
-sunos_get_configuration(struct libusb_device_handle *handle, int *config)
-{
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
-
- *config = dpriv->cfgvalue;
-
- usbi_dbg("bConfigurationValue %d", *config);
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_set_configuration(struct libusb_device_handle *handle, int config)
-{
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
- sunos_dev_handle_priv_t *hpriv;
-
- usbi_dbg("bConfigurationValue %d", config);
- hpriv = (sunos_dev_handle_priv_t *)handle->os_priv;
-
- if (dpriv->ugenpath == NULL)
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-
- if (config < 1 || config > dpriv->dev_descr.bNumConfigurations)
- return (LIBUSB_ERROR_INVALID_PARAM);
-
- dpriv->cfgvalue = config;
- hpriv->config_index = config - 1;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_claim_interface(struct libusb_device_handle *handle, int iface)
-{
- usbi_dbg("iface %d", iface);
- if (iface < 0) {
- return (LIBUSB_ERROR_INVALID_PARAM);
- }
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_release_interface(struct libusb_device_handle *handle, int iface)
-{
- sunos_dev_handle_priv_t *hpriv =
- (sunos_dev_handle_priv_t *)handle->os_priv;
-
- usbi_dbg("iface %d", iface);
- if (iface < 0) {
- return (LIBUSB_ERROR_INVALID_PARAM);
- }
-
- /* XXX: can we release it? */
- hpriv->altsetting[iface] = 0;
-
- return (LIBUSB_SUCCESS);
-}
-
-int
-sunos_set_interface_altsetting(struct libusb_device_handle *handle, int iface,
- int altsetting)
-{
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)handle->dev->os_priv;
- sunos_dev_handle_priv_t *hpriv =
- (sunos_dev_handle_priv_t *)handle->os_priv;
-
- usbi_dbg("iface %d, setting %d", iface, altsetting);
-
- if (iface < 0 || altsetting < 0) {
- return (LIBUSB_ERROR_INVALID_PARAM);
- }
- if (dpriv->ugenpath == NULL)
- return (LIBUSB_ERROR_NOT_FOUND);
-
- /* XXX: can we switch altsetting? */
- hpriv->altsetting[iface] = altsetting;
-
- return (LIBUSB_SUCCESS);
-}
-
-static void
-usb_dump_data(unsigned char *data, size_t size)
-{
- int i;
-
- if (getenv("LIBUSB_DEBUG") == NULL) {
- return;
- }
-
- (void) fprintf(stderr, "data dump:");
- for (i = 0; i < size; i++) {
- if (i % 16 == 0) {
- (void) fprintf(stderr, "\n%08x ", i);
- }
- (void) fprintf(stderr, "%02x ", (uchar_t)data[i]);
- }
- (void) fprintf(stderr, "\n");
-}
-
-static void
-sunos_async_callback(union sigval arg)
-{
- struct sunos_transfer_priv *tpriv =
- (struct sunos_transfer_priv *)arg.sival_ptr;
- struct libusb_transfer *xfer = tpriv->transfer;
- struct aiocb *aiocb = &tpriv->aiocb;
- int ret;
- sunos_dev_handle_priv_t *hpriv;
- uint8_t ep;
-
- hpriv = (sunos_dev_handle_priv_t *)xfer->dev_handle->os_priv;
- ep = sunos_usb_ep_index(xfer->endpoint);
-
- ret = aio_error(aiocb);
- if (ret != 0) {
- xfer->status = sunos_usb_get_status(hpriv->eps[ep].statfd);
- } else {
- xfer->actual_length =
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer)->transferred =
- aio_return(aiocb);
- }
-
- usb_dump_data(xfer->buffer, xfer->actual_length);
-
- usbi_dbg("ret=%d, len=%d, actual_len=%d", ret, xfer->length,
- xfer->actual_length);
-
- /* async notification */
- usbi_signal_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(xfer));
-}
-
-static int
-sunos_do_async_io(struct libusb_transfer *transfer)
-{
- int ret = -1;
- struct aiocb *aiocb;
- sunos_dev_handle_priv_t *hpriv;
- uint8_t ep;
- struct sunos_transfer_priv *tpriv;
-
- usbi_dbg("");
-
- tpriv = usbi_transfer_get_os_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
- hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv;
- ep = sunos_usb_ep_index(transfer->endpoint);
-
- tpriv->transfer = transfer;
- aiocb = &tpriv->aiocb;
- bzero(aiocb, sizeof (*aiocb));
- aiocb->aio_fildes = hpriv->eps[ep].datafd;
- aiocb->aio_buf = transfer->buffer;
- aiocb->aio_nbytes = transfer->length;
- aiocb->aio_lio_opcode =
- ((transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK) ==
- LIBUSB_ENDPOINT_IN) ? LIO_READ:LIO_WRITE;
- aiocb->aio_sigevent.sigev_notify = SIGEV_THREAD;
- aiocb->aio_sigevent.sigev_value.sival_ptr = tpriv;
- aiocb->aio_sigevent.sigev_notify_function = sunos_async_callback;
-
- if (aiocb->aio_lio_opcode == LIO_READ) {
- ret = aio_read(aiocb);
- } else {
- ret = aio_write(aiocb);
- }
-
- return (ret);
-}
-
-/* return the number of bytes read/written */
-static int
-usb_do_io(int fd, int stat_fd, char *data, size_t size, int flag, int *status)
-{
- int error;
- int ret = -1;
-
- usbi_dbg("usb_do_io(): datafd=%d statfd=%d size=0x%x flag=%s",
- fd, stat_fd, size, flag? "WRITE":"READ");
-
- switch (flag) {
- case READ:
- errno = 0;
- ret = read(fd, data, size);
- usb_dump_data(data, size);
- break;
- case WRITE:
- usb_dump_data(data, size);
- errno = 0;
- ret = write(fd, data, size);
- break;
- }
-
- usbi_dbg("usb_do_io(): amount=%d", ret);
-
- if (ret < 0) {
- int save_errno = errno;
-
- usbi_dbg("TID=%x io %s errno=%d(%s) ret=%d", pthread_self(),
- flag?"WRITE":"READ", errno, strerror(errno), ret);
-
- /* sunos_usb_get_status will do a read and overwrite errno */
- error = sunos_usb_get_status(stat_fd);
- usbi_dbg("io status=%d errno=%d(%s)", error,
- save_errno, strerror(save_errno));
-
- if (status) {
- *status = save_errno;
- }
-
- return (save_errno);
-
- } else if (status) {
- *status = 0;
- }
-
- return (ret);
-}
-
-static int
-solaris_submit_ctrl_on_default(struct libusb_transfer *transfer)
-{
- int ret = -1, setup_ret;
- int status;
- sunos_dev_handle_priv_t *hpriv;
- struct libusb_device_handle *hdl = transfer->dev_handle;
- uint16_t wLength;
- uint8_t *data = transfer->buffer;
-
- hpriv = (sunos_dev_handle_priv_t *)hdl->os_priv;
- wLength = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- if (hpriv->eps[0].datafd == -1) {
- usbi_dbg("ep0 not opened");
-
- return (LIBUSB_ERROR_NOT_FOUND);
- }
-
- if ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
- usbi_dbg("IN request");
- ret = usb_do_io(hpriv->eps[0].datafd,
- hpriv->eps[0].statfd, (char *)data, LIBUSB_CONTROL_SETUP_SIZE,
- WRITE, (int *)&status);
- } else {
- usbi_dbg("OUT request");
- ret = usb_do_io(hpriv->eps[0].datafd, hpriv->eps[0].statfd,
- transfer->buffer, transfer->length, WRITE,
- (int *)&transfer->status);
- }
-
- setup_ret = ret;
- if (ret < LIBUSB_CONTROL_SETUP_SIZE) {
- usbi_dbg("error sending control msg: %d", ret);
-
- return (LIBUSB_ERROR_IO);
- }
-
- ret = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- /* Read the remaining bytes for IN request */
- if ((wLength) && ((data[0] & LIBUSB_ENDPOINT_DIR_MASK) ==
- LIBUSB_ENDPOINT_IN)) {
- usbi_dbg("DATA: %d", transfer->length - setup_ret);
- ret = usb_do_io(hpriv->eps[0].datafd,
- hpriv->eps[0].statfd,
- (char *)transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE,
- wLength, READ, (int *)&transfer->status);
- }
-
- if (ret >= 0) {
- transfer->actual_length = ret;
- LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer)->transferred = ret;
- }
- usbi_dbg("Done: ctrl data bytes %d", ret);
-
- /* sync transfer handling */
- ret = usbi_handle_transfer_completion(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer),
- transfer->status);
-
- return (ret);
-}
-
-int
-sunos_clear_halt(struct libusb_device_handle *handle, uint8_t endpoint)
-{
- int ret;
-
- usbi_dbg("endpoint=0x%02x", endpoint);
-
- ret = libusb_control_transfer(handle, LIBUSB_ENDPOINT_OUT |
- LIBUSB_RECIPIENT_ENDPOINT | LIBUSB_REQUEST_TYPE_STANDARD,
- LIBUSB_REQUEST_CLEAR_FEATURE, 0, endpoint, NULL, 0, 1000);
-
- usbi_dbg("ret=%d", ret);
-
- return (ret);
-}
-
-int
-sunos_reset_device(struct libusb_device_handle *handle)
-{
- usbi_dbg("");
-
- return (LIBUSB_ERROR_NOT_SUPPORTED);
-}
-
-void
-sunos_destroy_device(struct libusb_device *dev)
-{
- sunos_dev_priv_t *dpriv = (sunos_dev_priv_t *)dev->os_priv;
-
- usbi_dbg("");
-
- free(dpriv->raw_cfgdescr);
- free(dpriv->ugenpath);
- free(dpriv->phypath);
-}
-
-int
-sunos_submit_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer;
- struct libusb_device_handle *hdl;
- int err = 0;
-
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- hdl = transfer->dev_handle;
-
- err = sunos_check_device_and_status_open(hdl,
- transfer->endpoint, transfer->type);
- if (err < 0) {
-
- return (_errno_to_libusb(err));
- }
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- /* sync transfer */
- usbi_dbg("CTRL transfer: %d", transfer->length);
- err = solaris_submit_ctrl_on_default(transfer);
- break;
-
- case LIBUSB_TRANSFER_TYPE_BULK:
- /* fallthru */
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (transfer->type == LIBUSB_TRANSFER_TYPE_BULK)
- usbi_dbg("BULK transfer: %d", transfer->length);
- else
- usbi_dbg("INTR transfer: %d", transfer->length);
- err = sunos_do_async_io(transfer);
- break;
-
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- /* Isochronous/Stream is not supported */
-
- /* fallthru */
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS)
- usbi_dbg("ISOC transfer: %d", transfer->length);
- else
- usbi_dbg("BULK STREAM transfer: %d", transfer->length);
- err = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- return (err);
-}
-
-int
-sunos_cancel_transfer(struct usbi_transfer *itransfer)
-{
- sunos_xfer_priv_t *tpriv;
- sunos_dev_handle_priv_t *hpriv;
- struct libusb_transfer *transfer;
- struct aiocb *aiocb;
- uint8_t ep;
- int ret;
-
- tpriv = usbi_transfer_get_os_priv(itransfer);
- aiocb = &tpriv->aiocb;
- transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- hpriv = (sunos_dev_handle_priv_t *)transfer->dev_handle->os_priv;
- ep = sunos_usb_ep_index(transfer->endpoint);
-
- ret = aio_cancel(hpriv->eps[ep].datafd, aiocb);
-
- usbi_dbg("aio->fd=%d fd=%d ret = %d, %s", aiocb->aio_fildes,
- hpriv->eps[ep].datafd, ret, (ret == AIO_CANCELED)?
- strerror(0):strerror(errno));
-
- if (ret != AIO_CANCELED) {
- ret = _errno_to_libusb(errno);
- } else {
- /*
- * we don't need to call usbi_handle_transfer_cancellation(),
- * because we'll handle everything in sunos_async_callback.
- */
- ret = LIBUSB_SUCCESS;
- }
-
- return (ret);
-}
-
-void
-sunos_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- usbi_dbg("");
-
- /* Nothing to do */
-}
-
-int
-sunos_handle_transfer_completion(struct usbi_transfer *itransfer)
-{
- return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
-}
-
-int
-sunos_clock_gettime(int clkid, struct timespec *tp)
-{
- usbi_dbg("clock %d", clkid);
-
- if (clkid == USBI_CLOCK_REALTIME)
- return clock_gettime(CLOCK_REALTIME, tp);
-
- if (clkid == USBI_CLOCK_MONOTONIC)
- return clock_gettime(CLOCK_MONOTONIC, tp);
-
- return (LIBUSB_ERROR_INVALID_PARAM);
-}
-
-int
-_errno_to_libusb(int err)
-{
- usbi_dbg("error: %s (%d)", strerror(err), err);
-
- switch (err) {
- case EIO:
- return (LIBUSB_ERROR_IO);
- case EACCES:
- return (LIBUSB_ERROR_ACCESS);
- case ENOENT:
- return (LIBUSB_ERROR_NO_DEVICE);
- case ENOMEM:
- return (LIBUSB_ERROR_NO_MEM);
- case ETIMEDOUT:
- return (LIBUSB_ERROR_TIMEOUT);
- }
-
- return (LIBUSB_ERROR_OTHER);
-}
-
-/*
- * sunos_usb_get_status:
- * gets status of endpoint
- *
- * Returns: ugen's last cmd status
- */
-static int
-sunos_usb_get_status(int fd)
-{
- int status, ret;
-
- usbi_dbg("sunos_usb_get_status(): fd=%d", fd);
-
- ret = read(fd, &status, sizeof (status));
- if (ret == sizeof (status)) {
- switch (status) {
- case USB_LC_STAT_NOERROR:
- usbi_dbg("No Error");
- break;
- case USB_LC_STAT_CRC:
- usbi_dbg("CRC Timeout Detected\n");
- break;
- case USB_LC_STAT_BITSTUFFING:
- usbi_dbg("Bit Stuffing Violation\n");
- break;
- case USB_LC_STAT_DATA_TOGGLE_MM:
- usbi_dbg("Data Toggle Mismatch\n");
- break;
- case USB_LC_STAT_STALL:
- usbi_dbg("End Point Stalled\n");
- break;
- case USB_LC_STAT_DEV_NOT_RESP:
- usbi_dbg("Device is Not Responding\n");
- break;
- case USB_LC_STAT_PID_CHECKFAILURE:
- usbi_dbg("PID Check Failure\n");
- break;
- case USB_LC_STAT_UNEXP_PID:
- usbi_dbg("Unexpected PID\n");
- break;
- case USB_LC_STAT_DATA_OVERRUN:
- usbi_dbg("Data Exceeded Size\n");
- break;
- case USB_LC_STAT_DATA_UNDERRUN:
- usbi_dbg("Less data received\n");
- break;
- case USB_LC_STAT_BUFFER_OVERRUN:
- usbi_dbg("Buffer Size Exceeded\n");
- break;
- case USB_LC_STAT_BUFFER_UNDERRUN:
- usbi_dbg("Buffer Underrun\n");
- break;
- case USB_LC_STAT_TIMEOUT:
- usbi_dbg("Command Timed Out\n");
- break;
- case USB_LC_STAT_NOT_ACCESSED:
- usbi_dbg("Not Accessed by h/w\n");
- break;
- case USB_LC_STAT_UNSPECIFIED_ERR:
- usbi_dbg("Unspecified Error\n");
- break;
- case USB_LC_STAT_NO_BANDWIDTH:
- usbi_dbg("No Bandwidth\n");
- break;
- case USB_LC_STAT_HW_ERR:
- usbi_dbg("Host Controller h/w Error\n");
- break;
- case USB_LC_STAT_SUSPENDED:
- usbi_dbg("Device was Suspended\n");
- break;
- case USB_LC_STAT_DISCONNECTED:
- usbi_dbg("Device was Disconnected\n");
- break;
- case USB_LC_STAT_INTR_BUF_FULL:
- usbi_dbg("Interrupt buffer was full\n");
- break;
- case USB_LC_STAT_INVALID_REQ:
- usbi_dbg("Request was Invalid\n");
- break;
- case USB_LC_STAT_INTERRUPTED:
- usbi_dbg("Request was Interrupted\n");
- break;
- case USB_LC_STAT_NO_RESOURCES:
- usbi_dbg("No resources available for "
- "request\n");
- break;
- case USB_LC_STAT_INTR_POLLING_FAILED:
- usbi_dbg("Failed to Restart Poll");
- break;
- default:
- usbi_dbg("Error Not Determined %d\n",
- status);
- break;
- }
- } else {
- usbi_dbg("read stat error: %s",strerror(errno));
- status = -1;
- }
-
- return (status);
-}
-
-const struct usbi_os_backend sunos_backend = {
- .name = "Solaris",
- .caps = 0,
- .init = sunos_init,
- .exit = sunos_exit,
- .get_device_list = sunos_get_device_list,
- .get_device_descriptor = sunos_get_device_descriptor,
- .get_active_config_descriptor = sunos_get_active_config_descriptor,
- .get_config_descriptor = sunos_get_config_descriptor,
- .hotplug_poll = NULL,
- .open = sunos_open,
- .close = sunos_close,
- .get_configuration = sunos_get_configuration,
- .set_configuration = sunos_set_configuration,
-
- .claim_interface = sunos_claim_interface,
- .release_interface = sunos_release_interface,
- .set_interface_altsetting = sunos_set_interface_altsetting,
- .clear_halt = sunos_clear_halt,
- .reset_device = sunos_reset_device, /* TODO */
- .alloc_streams = NULL,
- .free_streams = NULL,
- .kernel_driver_active = NULL,
- .detach_kernel_driver = NULL,
- .attach_kernel_driver = NULL,
- .destroy_device = sunos_destroy_device,
- .submit_transfer = sunos_submit_transfer,
- .cancel_transfer = sunos_cancel_transfer,
- .handle_events = NULL,
- .clear_transfer_priv = sunos_clear_transfer_priv,
- .handle_transfer_completion = sunos_handle_transfer_completion,
- .clock_gettime = sunos_clock_gettime,
- .device_priv_size = sizeof(sunos_dev_priv_t),
- .device_handle_priv_size = sizeof(sunos_dev_handle_priv_t),
- .transfer_priv_size = sizeof(sunos_xfer_priv_t),
-};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h
deleted file mode 100644
index 5741660..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/sunos_usb.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *
- * Copyright (c) 2016, Oracle and/or its affiliates.
- *
- * 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_SUNOS_H
-#define LIBUSB_SUNOS_H
-
-#include <libdevinfo.h>
-#include <pthread.h>
-#include "libusbi.h"
-
-#define READ 0
-#define WRITE 1
-
-typedef struct sunos_device_priv {
- uint8_t cfgvalue; /* active config value */
- uint8_t *raw_cfgdescr; /* active config descriptor */
- struct libusb_device_descriptor dev_descr; /* usb device descriptor */
- char *ugenpath; /* name of the ugen(4) node */
- char *phypath; /* physical path */
-} sunos_dev_priv_t;
-
-typedef struct endpoint {
- int datafd; /* data file */
- int statfd; /* state file */
-} sunos_ep_priv_t;
-
-typedef struct sunos_device_handle_priv {
- uint8_t altsetting[USB_MAXINTERFACES]; /* a interface's alt */
- uint8_t config_index;
- sunos_ep_priv_t eps[USB_MAXENDPOINTS];
- sunos_dev_priv_t *dpriv; /* device private */
-} sunos_dev_handle_priv_t;
-
-typedef struct sunos_transfer_priv {
- struct aiocb aiocb;
- struct libusb_transfer *transfer;
-} sunos_xfer_priv_t;
-
-struct node_args {
- struct libusb_context *ctx;
- struct discovered_devs **discdevs;
- const char *last_ugenpath;
- di_devlink_handle_t dlink_hdl;
-};
-
-struct devlink_cbarg {
- struct node_args *nargs; /* di node walk arguments */
- di_node_t myself; /* the di node */
- di_minor_t minor;
-};
-
-/* AIO callback args */
-struct aio_callback_args{
- struct libusb_transfer *transfer;
- struct aiocb aiocb;
-};
-
-#endif /* LIBUSB_SUNOS_H */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c
deleted file mode 100644
index a4f270b..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * libusb synchronization using POSIX Threads
- *
- * Copyright © 2011 Vitali Lovich <vlovich@aliph.com>
- * Copyright © 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
- */
-
-#include <config.h>
-
-#include <time.h>
-#if defined(__linux__) || defined(__OpenBSD__)
-# if defined(__OpenBSD__)
-# define _BSD_SOURCE
-# endif
-# include <unistd.h>
-# include <sys/syscall.h>
-#elif defined(__APPLE__)
-# include <mach/mach.h>
-#elif defined(__CYGWIN__)
-# include <windows.h>
-#endif
-
-#include "threads_posix.h"
-#include "libusbi.h"
-
-int usbi_cond_timedwait(pthread_cond_t *cond,
- pthread_mutex_t *mutex, const struct timeval *tv)
-{
- struct timespec timeout;
- int r;
-
- r = usbi_backend->clock_gettime(USBI_CLOCK_REALTIME, &timeout);
- if (r < 0)
- return r;
-
- timeout.tv_sec += tv->tv_sec;
- timeout.tv_nsec += tv->tv_usec * 1000;
- while (timeout.tv_nsec >= 1000000000L) {
- timeout.tv_nsec -= 1000000000L;
- timeout.tv_sec++;
- }
-
- return pthread_cond_timedwait(cond, mutex, &timeout);
-}
-
-int usbi_get_tid(void)
-{
- int ret = -1;
-#if defined(__ANDROID__)
- ret = gettid();
-#elif defined(__linux__)
- ret = syscall(SYS_gettid);
-#elif defined(__OpenBSD__)
- /* The following only works with OpenBSD > 5.1 as it requires
- real thread support. For 5.1 and earlier, -1 is returned. */
- ret = syscall(SYS_getthrid);
-#elif defined(__APPLE__)
- ret = mach_thread_self();
- mach_port_deallocate(mach_task_self(), ret);
-#elif defined(__CYGWIN__)
- ret = GetCurrentThreadId();
-#endif
-/* TODO: NetBSD thread ID support */
- return ret;
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h
deleted file mode 100644
index 4c1514e..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_posix.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * libusb synchronization using POSIX Threads
- *
- * Copyright © 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>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#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(mutex) pthread_mutex_init((mutex), NULL)
-#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(cond) pthread_cond_init((cond), NULL)
-#define usbi_cond_wait pthread_cond_wait
-#define usbi_cond_broadcast pthread_cond_broadcast
-#define usbi_cond_destroy pthread_cond_destroy
-
-#define usbi_tls_key_t pthread_key_t
-#define usbi_tls_key_create(key) pthread_key_create((key), NULL)
-#define usbi_tls_key_get pthread_getspecific
-#define usbi_tls_key_set pthread_setspecific
-#define usbi_tls_key_delete pthread_key_delete
-
-int usbi_get_tid(void);
-
-#endif /* LIBUSB_THREADS_POSIX_H */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c
deleted file mode 100644
index 7c2e52d..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * libusb synchronization on Microsoft Windows
- *
- * Copyright © 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 "libusbi.h"
-
-struct usbi_cond_perthread {
- struct list_head list;
- DWORD tid;
- HANDLE event;
-};
-
-int usbi_mutex_static_lock(usbi_mutex_static_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- while (InterlockedExchange(mutex, 1) == 1)
- SleepEx(0, TRUE);
- return 0;
-}
-
-int usbi_mutex_static_unlock(usbi_mutex_static_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- InterlockedExchange(mutex, 0);
- return 0;
-}
-
-int usbi_mutex_init(usbi_mutex_t *mutex)
-{
- if (!mutex)
- return EINVAL;
- *mutex = CreateMutex(NULL, FALSE, NULL);
- if (!*mutex)
- return ENOMEM;
- return 0;
-}
-
-int usbi_mutex_lock(usbi_mutex_t *mutex)
-{
- DWORD result;
-
- if (!mutex)
- return EINVAL;
- result = WaitForSingleObject(*mutex, INFINITE);
- if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
- return 0; // acquired (ToDo: check that abandoned is ok)
- else
- return 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 EINVAL;
- if (ReleaseMutex(*mutex))
- return 0;
- else
- return EPERM;
-}
-
-int usbi_mutex_trylock(usbi_mutex_t *mutex)
-{
- DWORD result;
-
- if (!mutex)
- return EINVAL;
- result = WaitForSingleObject(*mutex, 0);
- if (result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
- return 0; // acquired (ToDo: check that abandoned is ok)
- else if (result == WAIT_TIMEOUT)
- return EBUSY;
- else
- return EINVAL; // don't know how this would happen
- // so don't know proper error
-}
-
-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 EINVAL;
- *mutex = NULL;
- return 0;
-}
-
-int usbi_cond_init(usbi_cond_t *cond)
-{
- if (!cond)
- return 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, *next_pos;
-
- if(!cond)
- return EINVAL;
- if (!list_empty(&cond->waiters))
- return EBUSY; // (!see above!)
- list_for_each_entry_safe(pos, next_pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
- CloseHandle(pos->event);
- list_del(&pos->list);
- free(pos);
- }
- 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 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 ? EINVAL : 0;
-}
-
-__inline static int usbi_cond_intwait(usbi_cond_t *cond,
- usbi_mutex_t *mutex, DWORD timeout_ms)
-{
- struct usbi_cond_perthread *pos;
- int r, found = 0;
- DWORD r2, tid = GetCurrentThreadId();
-
- if (!cond || !mutex)
- return EINVAL;
- list_for_each_entry(pos, &cond->not_waiting, list, struct usbi_cond_perthread) {
- if(tid == pos->tid) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- pos = calloc(1, sizeof(struct usbi_cond_perthread));
- if (!pos)
- return 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 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_OBJECT_0)
- return 0;
- else if (r2 == WAIT_TIMEOUT)
- return ETIMEDOUT;
- else
- return EINVAL;
-}
-// 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 timeval *tv)
-{
- DWORD millis;
-
- millis = (DWORD)(tv->tv_sec * 1000) + (tv->tv_usec / 1000);
- /* round up to next millisecond */
- if (tv->tv_usec % 1000)
- millis++;
- return usbi_cond_intwait(cond, mutex, millis);
-}
-
-int usbi_tls_key_create(usbi_tls_key_t *key)
-{
- if (!key)
- return EINVAL;
- *key = TlsAlloc();
- if (*key == TLS_OUT_OF_INDEXES)
- return ENOMEM;
- else
- return 0;
-}
-
-void *usbi_tls_key_get(usbi_tls_key_t key)
-{
- return TlsGetValue(key);
-}
-
-int usbi_tls_key_set(usbi_tls_key_t key, void *value)
-{
- if (TlsSetValue(key, value))
- return 0;
- else
- return EINVAL;
-}
-
-int usbi_tls_key_delete(usbi_tls_key_t key)
-{
- if (TlsFree(key))
- return 0;
- else
- return EINVAL;
-}
-
-int usbi_get_tid(void)
-{
- return (int)GetCurrentThreadId();
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h
deleted file mode 100644
index e97ee78..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/threads_windows.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * libusb synchronization on Microsoft Windows
- *
- * Copyright © 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
-
-typedef struct usbi_cond {
- // 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;
-} 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_tls_key_t DWORD
-
-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);
-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);
-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 timeval *tv);
-int usbi_cond_broadcast(usbi_cond_t *cond);
-int usbi_cond_destroy(usbi_cond_t *cond);
-
-int usbi_tls_key_create(usbi_tls_key_t *key);
-void *usbi_tls_key_get(usbi_tls_key_t key);
-int usbi_tls_key_set(usbi_tls_key_t key, void *value);
-int usbi_tls_key_delete(usbi_tls_key_t key);
-
-int usbi_get_tid(void);
-
-#endif /* LIBUSB_THREADS_WINDOWS_H */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c
deleted file mode 100644
index 0d466b8..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.c
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
- * Windows CE backend for libusb 1.0
- * Copyright © 2011-2013 RealVNC Ltd.
- * Large portions taken from Windows backend, which is
- * Copyright © 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
- */
-
-#include <config.h>
-
-#include <stdint.h>
-#include <inttypes.h>
-
-#include "libusbi.h"
-#include "wince_usb.h"
-
-// Global variables
-int windows_version = WINDOWS_CE;
-static uint64_t hires_frequency, hires_ticks_to_ps;
-static HANDLE driver_handle = INVALID_HANDLE_VALUE;
-static int concurrent_usage = -1;
-
-/*
- * Converts a windows error to human readable string
- * uses retval as errorcode, or, if 0, use GetLastError()
- */
-#if defined(ENABLE_LOGGING)
-static const char *windows_error_str(DWORD error_code)
-{
- static TCHAR wErr_string[ERR_BUFFER_SIZE];
- static char err_string[ERR_BUFFER_SIZE];
-
- DWORD size;
- int len;
-
- if (error_code == 0)
- error_code = GetLastError();
-
- len = sprintf(err_string, "[%u] ", (unsigned int)error_code);
-
- size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- wErr_string, ERR_BUFFER_SIZE, NULL);
- if (size == 0) {
- DWORD format_error = GetLastError();
- if (format_error)
- snprintf(err_string, ERR_BUFFER_SIZE,
- "Windows error code %u (FormatMessage error code %u)",
- (unsigned int)error_code, (unsigned int)format_error);
- else
- snprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)error_code);
- } else {
- // Remove CR/LF terminators, if present
- size_t pos = size - 2;
- if (wErr_string[pos] == 0x0D)
- wErr_string[pos] = 0;
-
- if (!WideCharToMultiByte(CP_ACP, 0, wErr_string, -1, &err_string[len], ERR_BUFFER_SIZE - len, NULL, NULL))
- strcpy(err_string, "Unable to convert error string");
- }
-
- return err_string;
-}
-#endif
-
-static struct wince_device_priv *_device_priv(struct libusb_device *dev)
-{
- return (struct wince_device_priv *)dev->os_priv;
-}
-
-// ceusbkwrapper to libusb error code mapping
-static int translate_driver_error(DWORD error)
-{
- switch (error) {
- case ERROR_INVALID_PARAMETER:
- return LIBUSB_ERROR_INVALID_PARAM;
- case ERROR_CALL_NOT_IMPLEMENTED:
- case ERROR_NOT_SUPPORTED:
- return LIBUSB_ERROR_NOT_SUPPORTED;
- case ERROR_NOT_ENOUGH_MEMORY:
- return LIBUSB_ERROR_NO_MEM;
- case ERROR_INVALID_HANDLE:
- return LIBUSB_ERROR_NO_DEVICE;
- case ERROR_BUSY:
- return LIBUSB_ERROR_BUSY;
-
- // Error codes that are either unexpected, or have
- // no suitable LIBUSB_ERROR equivalent.
- case ERROR_CANCELLED:
- case ERROR_INTERNAL_ERROR:
- default:
- return LIBUSB_ERROR_OTHER;
- }
-}
-
-static int init_dllimports(void)
-{
- DLL_GET_HANDLE(ceusbkwrapper);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwOpenDriver, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceList, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwReleaseDeviceList, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceAddress, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwGetDeviceDescriptor, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwGetConfigDescriptor, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwCloseDriver, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwCancelTransfer, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueControlTransfer, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwClaimInterface, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwReleaseInterface, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwSetInterfaceAlternateSetting, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwClearHaltHost, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwClearHaltDevice, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwGetConfig, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwSetConfig, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwResetDevice, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwKernelDriverActive, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwAttachKernelDriver, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwDetachKernelDriver, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwIssueBulkTransfer, TRUE);
- DLL_LOAD_FUNC(ceusbkwrapper, UkwIsPipeHalted, TRUE);
-
- return LIBUSB_SUCCESS;
-}
-
-static void exit_dllimports(void)
-{
- DLL_FREE_HANDLE(ceusbkwrapper);
-}
-
-static int init_device(
- struct libusb_device *dev, UKW_DEVICE drv_dev,
- unsigned char bus_addr, unsigned char dev_addr)
-{
- struct wince_device_priv *priv = _device_priv(dev);
- int r = LIBUSB_SUCCESS;
-
- dev->bus_number = bus_addr;
- dev->device_address = dev_addr;
- priv->dev = drv_dev;
-
- if (!UkwGetDeviceDescriptor(priv->dev, &(priv->desc)))
- r = translate_driver_error(GetLastError());
-
- return r;
-}
-
-// Internal API functions
-static int wince_init(struct libusb_context *ctx)
-{
- int r = LIBUSB_ERROR_OTHER;
- HANDLE semaphore;
- LARGE_INTEGER li_frequency;
- TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-
- _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
- semaphore = CreateSemaphore(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?
- // Initialize pollable file descriptors
- init_polling();
-
- // Load DLL imports
- if (init_dllimports() != LIBUSB_SUCCESS) {
- usbi_err(ctx, "could not resolve DLL functions");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- goto init_exit;
- }
-
- // try to open a handle to the driver
- driver_handle = UkwOpenDriver();
- if (driver_handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not connect to driver");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- goto init_exit;
- }
-
- // find out if we have access to a monotonic (hires) timer
- if (QueryPerformanceFrequency(&li_frequency)) {
- 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);
- } else {
- usbi_dbg("no hires timer available on this platform");
- hires_frequency = 0;
- hires_ticks_to_ps = UINT64_C(0);
- }
- }
- // 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?
- exit_dllimports();
- exit_polling();
-
- if (driver_handle != INVALID_HANDLE_VALUE) {
- UkwCloseDriver(driver_handle);
- driver_handle = INVALID_HANDLE_VALUE;
- }
- }
-
- 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;
-}
-
-static void wince_exit(void)
-{
- HANDLE semaphore;
- TCHAR sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-
- _stprintf(sem_name, _T("libusb_init%08X"), (unsigned int)(GetCurrentProcessId() & 0xFFFFFFFF));
- semaphore = CreateSemaphore(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
- exit_dllimports();
- exit_polling();
-
- if (driver_handle != INVALID_HANDLE_VALUE) {
- UkwCloseDriver(driver_handle);
- driver_handle = INVALID_HANDLE_VALUE;
- }
- }
-
- ReleaseSemaphore(semaphore, 1, NULL); // increase count back to 1
- CloseHandle(semaphore);
-}
-
-static int wince_get_device_list(
- struct libusb_context *ctx,
- struct discovered_devs **discdevs)
-{
- UKW_DEVICE devices[MAX_DEVICE_COUNT];
- struct discovered_devs *new_devices = *discdevs;
- DWORD count = 0, i;
- struct libusb_device *dev = NULL;
- unsigned char bus_addr, dev_addr;
- unsigned long session_id;
- BOOL success;
- DWORD release_list_offset = 0;
- int r = LIBUSB_SUCCESS;
-
- success = UkwGetDeviceList(driver_handle, devices, MAX_DEVICE_COUNT, &count);
- if (!success) {
- int libusbErr = translate_driver_error(GetLastError());
- usbi_err(ctx, "could not get devices: %s", windows_error_str(0));
- return libusbErr;
- }
-
- for (i = 0; i < count; ++i) {
- release_list_offset = i;
- success = UkwGetDeviceAddress(devices[i], &bus_addr, &dev_addr, &session_id);
- if (!success) {
- r = translate_driver_error(GetLastError());
- usbi_err(ctx, "could not get device address for %u: %s", (unsigned int)i, windows_error_str(0));
- goto err_out;
- }
-
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev) {
- usbi_dbg("using existing device for %u/%u (session %lu)",
- bus_addr, dev_addr, session_id);
- // Release just this element in the device list (as we already hold a
- // reference to it).
- UkwReleaseDeviceList(driver_handle, &devices[i], 1);
- release_list_offset++;
- } else {
- usbi_dbg("allocating new device for %u/%u (session %lu)",
- bus_addr, dev_addr, session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (!dev) {
- r = LIBUSB_ERROR_NO_MEM;
- goto err_out;
- }
-
- r = init_device(dev, devices[i], bus_addr, dev_addr);
- if (r < 0)
- goto err_out;
-
- r = usbi_sanitize_device(dev);
- if (r < 0)
- goto err_out;
- }
-
- new_devices = discovered_devs_append(new_devices, dev);
- if (!discdevs) {
- r = LIBUSB_ERROR_NO_MEM;
- goto err_out;
- }
-
- libusb_unref_device(dev);
- }
-
- *discdevs = new_devices;
- return r;
-err_out:
- *discdevs = new_devices;
- libusb_unref_device(dev);
- // Release the remainder of the unprocessed device list.
- // The devices added to new_devices already will still be passed up to libusb,
- // which can dispose of them at its leisure.
- UkwReleaseDeviceList(driver_handle, &devices[release_list_offset], count - release_list_offset);
- return r;
-}
-
-static int wince_open(struct libusb_device_handle *handle)
-{
- // Nothing to do to open devices as a handle to it has
- // been retrieved by wince_get_device_list
- return LIBUSB_SUCCESS;
-}
-
-static void wince_close(struct libusb_device_handle *handle)
-{
- // Nothing to do as wince_open does nothing.
-}
-
-static int wince_get_device_descriptor(
- struct libusb_device *device,
- unsigned char *buffer, int *host_endian)
-{
- struct wince_device_priv *priv = _device_priv(device);
-
- *host_endian = 1;
- memcpy(buffer, &priv->desc, DEVICE_DESC_LENGTH);
- return LIBUSB_SUCCESS;
-}
-
-static int wince_get_active_config_descriptor(
- struct libusb_device *device,
- unsigned char *buffer, size_t len, int *host_endian)
-{
- struct wince_device_priv *priv = _device_priv(device);
- DWORD actualSize = len;
-
- *host_endian = 0;
- if (!UkwGetConfigDescriptor(priv->dev, UKW_ACTIVE_CONFIGURATION, buffer, len, &actualSize))
- return translate_driver_error(GetLastError());
-
- return actualSize;
-}
-
-static int wince_get_config_descriptor(
- struct libusb_device *device,
- uint8_t config_index,
- unsigned char *buffer, size_t len, int *host_endian)
-{
- struct wince_device_priv *priv = _device_priv(device);
- DWORD actualSize = len;
-
- *host_endian = 0;
- if (!UkwGetConfigDescriptor(priv->dev, config_index, buffer, len, &actualSize))
- return translate_driver_error(GetLastError());
-
- return actualSize;
-}
-
-static int wince_get_configuration(
- struct libusb_device_handle *handle,
- int *config)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
- UCHAR cv = 0;
-
- if (!UkwGetConfig(priv->dev, &cv))
- return translate_driver_error(GetLastError());
-
- (*config) = cv;
- return LIBUSB_SUCCESS;
-}
-
-static int wince_set_configuration(
- struct libusb_device_handle *handle,
- int config)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
- // Setting configuration 0 places the device in Address state.
- // This should correspond to the "unconfigured state" required by
- // libusb when the specified configuration is -1.
- UCHAR cv = (config < 0) ? 0 : config;
- if (!UkwSetConfig(priv->dev, cv))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_claim_interface(
- struct libusb_device_handle *handle,
- int interface_number)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwClaimInterface(priv->dev, interface_number))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_release_interface(
- struct libusb_device_handle *handle,
- int interface_number)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, 0))
- return translate_driver_error(GetLastError());
-
- if (!UkwReleaseInterface(priv->dev, interface_number))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_set_interface_altsetting(
- struct libusb_device_handle *handle,
- int interface_number, int altsetting)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwSetInterfaceAlternateSetting(priv->dev, interface_number, altsetting))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_clear_halt(
- struct libusb_device_handle *handle,
- unsigned char endpoint)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwClearHaltHost(priv->dev, endpoint))
- return translate_driver_error(GetLastError());
-
- if (!UkwClearHaltDevice(priv->dev, endpoint))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_reset_device(
- struct libusb_device_handle *handle)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwResetDevice(priv->dev))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_kernel_driver_active(
- struct libusb_device_handle *handle,
- int interface_number)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
- BOOL result = FALSE;
-
- if (!UkwKernelDriverActive(priv->dev, interface_number, &result))
- return translate_driver_error(GetLastError());
-
- return result ? 1 : 0;
-}
-
-static int wince_detach_kernel_driver(
- struct libusb_device_handle *handle,
- int interface_number)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwDetachKernelDriver(priv->dev, interface_number))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_attach_kernel_driver(
- struct libusb_device_handle *handle,
- int interface_number)
-{
- struct wince_device_priv *priv = _device_priv(handle->dev);
-
- if (!UkwAttachKernelDriver(priv->dev, interface_number))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static void wince_destroy_device(struct libusb_device *dev)
-{
- struct wince_device_priv *priv = _device_priv(dev);
-
- UkwReleaseDeviceList(driver_handle, &priv->dev, 1);
-}
-
-static void wince_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct winfd wfd = fd_to_winfd(transfer_priv->pollable_fd.fd);
-
- // No need to cancel transfer as it is either complete or abandoned
- wfd.itransfer = NULL;
- CloseHandle(wfd.handle);
- usbi_free_fd(&transfer_priv->pollable_fd);
-}
-
-static int wince_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- struct wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-
- if (!UkwCancelTransfer(priv->dev, transfer_priv->pollable_fd.overlapped, UKW_TF_NO_WAIT))
- return translate_driver_error(GetLastError());
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_submit_control_or_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 wince_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
- struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- BOOL direction_in, ret;
- struct winfd wfd;
- DWORD flags;
- HANDLE eventHandle;
- PUKW_CONTROL_HEADER setup = NULL;
- const BOOL control_transfer = transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL;
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- if (control_transfer) {
- setup = (PUKW_CONTROL_HEADER) transfer->buffer;
- direction_in = setup->bmRequestType & LIBUSB_ENDPOINT_IN;
- } else {
- direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
- }
- flags = direction_in ? UKW_TF_IN_TRANSFER : UKW_TF_OUT_TRANSFER;
- flags |= UKW_TF_SHORT_TRANSFER_OK;
-
- eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (eventHandle == NULL) {
- usbi_err(ctx, "Failed to create event for async transfer");
- return LIBUSB_ERROR_NO_MEM;
- }
-
- wfd = usbi_create_fd(eventHandle, direction_in ? RW_READ : RW_WRITE, itransfer, &wince_cancel_transfer);
- if (wfd.fd < 0) {
- CloseHandle(eventHandle);
- return LIBUSB_ERROR_NO_MEM;
- }
-
- transfer_priv->pollable_fd = wfd;
- if (control_transfer) {
- // Split out control setup header and data buffer
- DWORD bufLen = transfer->length - sizeof(UKW_CONTROL_HEADER);
- PVOID buf = (PVOID) &transfer->buffer[sizeof(UKW_CONTROL_HEADER)];
-
- ret = UkwIssueControlTransfer(priv->dev, flags, setup, buf, bufLen, &transfer->actual_length, wfd.overlapped);
- } else {
- ret = UkwIssueBulkTransfer(priv->dev, flags, transfer->endpoint, transfer->buffer,
- transfer->length, &transfer->actual_length, wfd.overlapped);
- }
-
- if (!ret) {
- int libusbErr = translate_driver_error(GetLastError());
- usbi_err(ctx, "UkwIssue%sTransfer failed: error %u",
- control_transfer ? "Control" : "Bulk", (unsigned int)GetLastError());
- wince_clear_transfer_priv(itransfer);
- return libusbErr;
- }
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, direction_in ? POLLIN : POLLOUT);
-
- return LIBUSB_SUCCESS;
-}
-
-static int wince_submit_iso_transfer(struct usbi_transfer *itransfer)
-{
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int wince_submit_transfer(struct usbi_transfer *itransfer)
-{
- 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:
- return wince_submit_control_or_bulk_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return wince_submit_iso_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- return LIBUSB_ERROR_NOT_SUPPORTED;
- default:
- usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-static void wince_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 wince_transfer_priv *transfer_priv = (struct wince_transfer_priv*)usbi_transfer_get_os_priv(itransfer);
- struct wince_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- int status;
-
- usbi_dbg("handling I/O completion with errcode %u", io_result);
-
- if (io_result == ERROR_NOT_SUPPORTED &&
- transfer->type != LIBUSB_TRANSFER_TYPE_CONTROL) {
- /* For functional stalls, the WinCE USB layer (and therefore the USB Kernel Wrapper
- * Driver) will report USB_ERROR_STALL/ERROR_NOT_SUPPORTED in situations where the
- * endpoint isn't actually stalled.
- *
- * One example of this is that some devices will occasionally fail to reply to an IN
- * token. The WinCE USB layer carries on with the transaction until it is completed
- * (or cancelled) but then completes it with USB_ERROR_STALL.
- *
- * This code therefore needs to confirm that there really is a stall error, by both
- * checking the pipe status and requesting the endpoint status from the device.
- */
- BOOL halted = FALSE;
- usbi_dbg("checking I/O completion with errcode ERROR_NOT_SUPPORTED is really a stall");
- if (UkwIsPipeHalted(priv->dev, transfer->endpoint, &halted)) {
- /* Pipe status retrieved, so now request endpoint status by sending a GET_STATUS
- * control request to the device. This is done synchronously, which is a bit
- * naughty, but this is a special corner case.
- */
- WORD wStatus = 0;
- DWORD written = 0;
- UKW_CONTROL_HEADER ctrlHeader;
- ctrlHeader.bmRequestType = LIBUSB_REQUEST_TYPE_STANDARD |
- LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_ENDPOINT;
- ctrlHeader.bRequest = LIBUSB_REQUEST_GET_STATUS;
- ctrlHeader.wValue = 0;
- ctrlHeader.wIndex = transfer->endpoint;
- ctrlHeader.wLength = sizeof(wStatus);
- if (UkwIssueControlTransfer(priv->dev,
- UKW_TF_IN_TRANSFER | UKW_TF_SEND_TO_ENDPOINT,
- &ctrlHeader, &wStatus, sizeof(wStatus), &written, NULL)) {
- if (written == sizeof(wStatus) &&
- (wStatus & STATUS_HALT_FLAG) == 0) {
- if (!halted || UkwClearHaltHost(priv->dev, transfer->endpoint)) {
- usbi_dbg("Endpoint doesn't appear to be stalled, overriding error with success");
- io_result = ERROR_SUCCESS;
- } else {
- usbi_dbg("Endpoint doesn't appear to be stalled, but the host is halted, changing error");
- io_result = ERROR_IO_DEVICE;
- }
- }
- }
- }
- }
-
- switch(io_result) {
- case ERROR_SUCCESS:
- itransfer->transferred += io_size;
- status = LIBUSB_TRANSFER_COMPLETED;
- break;
- case ERROR_CANCELLED:
- usbi_dbg("detected transfer cancel");
- status = LIBUSB_TRANSFER_CANCELLED;
- break;
- case ERROR_NOT_SUPPORTED:
- 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:
- usbi_dbg("detected operation aborted");
- status = LIBUSB_TRANSFER_CANCELLED;
- break;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error: %s", windows_error_str(io_result));
- status = LIBUSB_TRANSFER_ERROR;
- break;
- }
-
- wince_clear_transfer_priv(itransfer);
- if (status == LIBUSB_TRANSFER_CANCELLED)
- usbi_handle_transfer_cancellation(itransfer);
- else
- usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
-}
-
-static void wince_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:
- wince_transfer_callback (itransfer, io_result, io_size);
- break;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- break;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- }
-}
-
-static int wince_handle_events(
- struct libusb_context *ctx,
- struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
-{
- struct wince_transfer_priv* transfer_priv = NULL;
- POLL_NFDS_TYPE i = 0;
- BOOL found = FALSE;
- struct usbi_transfer *transfer;
- DWORD io_size, io_result;
- int r = LIBUSB_SUCCESS;
-
- 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 && HasOverlappedIoCompleted(transfer_priv->pollable_fd.overlapped)) {
- io_result = (DWORD)transfer_priv->pollable_fd.overlapped->Internal;
- io_size = (DWORD)transfer_priv->pollable_fd.overlapped->InternalHigh;
- 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.
- wince_handle_callback(transfer, io_result, io_size);
- } else if (found) {
- usbi_err(ctx, "matching transfer for fd %d has not completed", fds[i]);
- r = LIBUSB_ERROR_OTHER;
- break;
- } else {
- usbi_err(ctx, "could not find a matching transfer for fd %d", fds[i]);
- r = LIBUSB_ERROR_NOT_FOUND;
- break;
- }
- }
- usbi_mutex_unlock(&ctx->open_devs_lock);
-
- return r;
-}
-
-/*
- * Monotonic and real time functions
- */
-static int wince_clock_gettime(int clk_id, struct timespec *tp)
-{
- LARGE_INTEGER hires_counter;
- ULARGE_INTEGER rtime;
- FILETIME filetime;
- SYSTEMTIME st;
-
- switch(clk_id) {
- case USBI_CLOCK_MONOTONIC:
- if (hires_frequency != 0 && QueryPerformanceCounter(&hires_counter)) {
- tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
- tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
- return LIBUSB_SUCCESS;
- }
- // Fall through and return real-time if monotonic read failed or was not detected @ 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)
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &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;
- }
-}
-
-const struct usbi_os_backend wince_backend = {
- "Windows CE",
- 0,
- wince_init,
- wince_exit,
-
- wince_get_device_list,
- NULL, /* hotplug_poll */
- wince_open,
- wince_close,
-
- wince_get_device_descriptor,
- wince_get_active_config_descriptor,
- wince_get_config_descriptor,
- NULL, /* get_config_descriptor_by_value() */
-
- wince_get_configuration,
- wince_set_configuration,
- wince_claim_interface,
- wince_release_interface,
-
- wince_set_interface_altsetting,
- wince_clear_halt,
- wince_reset_device,
-
- NULL, /* alloc_streams */
- NULL, /* free_streams */
-
- NULL, /* dev_mem_alloc() */
- NULL, /* dev_mem_free() */
-
- wince_kernel_driver_active,
- wince_detach_kernel_driver,
- wince_attach_kernel_driver,
-
- wince_destroy_device,
-
- wince_submit_transfer,
- wince_cancel_transfer,
- wince_clear_transfer_priv,
-
- wince_handle_events,
- NULL, /* handle_transfer_completion() */
-
- wince_clock_gettime,
- sizeof(struct wince_device_priv),
- 0,
- sizeof(struct wince_transfer_priv),
-};
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h
deleted file mode 100644
index edcb9fc..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/wince_usb.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Windows CE backend for libusb 1.0
- * Copyright © 2011-2013 RealVNC Ltd.
- * Portions taken from Windows backend, which is
- * Copyright © 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
-
-#include "windows_common.h"
-
-#include <windows.h>
-#include "poll_windows.h"
-
-#define MAX_DEVICE_COUNT 256
-
-// This is a modified dump of the types in the ceusbkwrapper.h library header
-// with functions transformed into extern pointers.
-//
-// This backend dynamically loads ceusbkwrapper.dll and doesn't include
-// ceusbkwrapper.h directly to simplify the build process. The kernel
-// side wrapper driver is built using the platform image build tools,
-// which makes it difficult to reference directly from the libusb build
-// system.
-struct UKW_DEVICE_PRIV;
-typedef struct UKW_DEVICE_PRIV *UKW_DEVICE;
-typedef UKW_DEVICE *PUKW_DEVICE, *LPUKW_DEVICE;
-
-typedef struct {
- UINT8 bLength;
- UINT8 bDescriptorType;
- UINT16 bcdUSB;
- UINT8 bDeviceClass;
- UINT8 bDeviceSubClass;
- UINT8 bDeviceProtocol;
- UINT8 bMaxPacketSize0;
- UINT16 idVendor;
- UINT16 idProduct;
- UINT16 bcdDevice;
- UINT8 iManufacturer;
- UINT8 iProduct;
- UINT8 iSerialNumber;
- UINT8 bNumConfigurations;
-} UKW_DEVICE_DESCRIPTOR, *PUKW_DEVICE_DESCRIPTOR, *LPUKW_DEVICE_DESCRIPTOR;
-
-typedef struct {
- UINT8 bmRequestType;
- UINT8 bRequest;
- UINT16 wValue;
- UINT16 wIndex;
- UINT16 wLength;
-} UKW_CONTROL_HEADER, *PUKW_CONTROL_HEADER, *LPUKW_CONTROL_HEADER;
-
-// Collection of flags which can be used when issuing transfer requests
-/* Indicates that the transfer direction is 'in' */
-#define UKW_TF_IN_TRANSFER 0x00000001
-/* Indicates that the transfer direction is 'out' */
-#define UKW_TF_OUT_TRANSFER 0x00000000
-/* Specifies that the transfer should complete as soon as possible,
- * even if no OVERLAPPED structure has been provided. */
-#define UKW_TF_NO_WAIT 0x00000100
-/* Indicates that transfers shorter than the buffer are ok */
-#define UKW_TF_SHORT_TRANSFER_OK 0x00000200
-#define UKW_TF_SEND_TO_DEVICE 0x00010000
-#define UKW_TF_SEND_TO_INTERFACE 0x00020000
-#define UKW_TF_SEND_TO_ENDPOINT 0x00040000
-/* Don't block when waiting for memory allocations */
-#define UKW_TF_DONT_BLOCK_FOR_MEM 0x00080000
-
-/* Value to use when dealing with configuration values, such as UkwGetConfigDescriptor,
- * to specify the currently active configuration for the device. */
-#define UKW_ACTIVE_CONFIGURATION -1
-
-DLL_DECLARE_HANDLE(ceusbkwrapper);
-DLL_DECLARE_FUNC(WINAPI, HANDLE, UkwOpenDriver, ());
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetDeviceList, (HANDLE, LPUKW_DEVICE, DWORD, LPDWORD));
-DLL_DECLARE_FUNC(WINAPI, void, UkwReleaseDeviceList, (HANDLE, LPUKW_DEVICE, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetDeviceAddress, (UKW_DEVICE, unsigned char*, unsigned char*, unsigned long*));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetDeviceDescriptor, (UKW_DEVICE, LPUKW_DEVICE_DESCRIPTOR));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetConfigDescriptor, (UKW_DEVICE, DWORD, LPVOID, DWORD, LPDWORD));
-DLL_DECLARE_FUNC(WINAPI, void, UkwCloseDriver, (HANDLE));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwCancelTransfer, (UKW_DEVICE, LPOVERLAPPED, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwIssueControlTransfer, (UKW_DEVICE, DWORD, LPUKW_CONTROL_HEADER, LPVOID, DWORD, LPDWORD, LPOVERLAPPED));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwClaimInterface, (UKW_DEVICE, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwReleaseInterface, (UKW_DEVICE, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwSetInterfaceAlternateSetting, (UKW_DEVICE, DWORD, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwClearHaltHost, (UKW_DEVICE, UCHAR));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwClearHaltDevice, (UKW_DEVICE, UCHAR));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwGetConfig, (UKW_DEVICE, PUCHAR));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwSetConfig, (UKW_DEVICE, UCHAR));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwResetDevice, (UKW_DEVICE));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwKernelDriverActive, (UKW_DEVICE, DWORD, PBOOL));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwAttachKernelDriver, (UKW_DEVICE, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwDetachKernelDriver, (UKW_DEVICE, DWORD));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwIssueBulkTransfer, (UKW_DEVICE, DWORD, UCHAR, LPVOID, DWORD, LPDWORD, LPOVERLAPPED));
-DLL_DECLARE_FUNC(WINAPI, BOOL, UkwIsPipeHalted, (UKW_DEVICE, UCHAR, LPBOOL));
-
-// Used to determine if an endpoint status really is halted on a failed transfer.
-#define STATUS_HALT_FLAG 0x1
-
-struct wince_device_priv {
- UKW_DEVICE dev;
- UKW_DEVICE_DESCRIPTOR desc;
-};
-
-struct wince_transfer_priv {
- struct winfd pollable_fd;
- uint8_t interface_number;
-};
-
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h
deleted file mode 100644
index 55344ca..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_common.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Windows backend common header for libusb 1.0
- *
- * This file brings together header code common between
- * the desktop Windows and Windows CE backends.
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * 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
-
-// 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
-
-#define EPOCH_TIME UINT64_C(116444736000000000) // 1970.01.01 00:00:000 in MS Filetime
-
-#if defined(__CYGWIN__ )
-#define _stricmp strcasecmp
-#define _strdup strdup
-// _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, (LPDWORD)f)
-#endif
-
-#define safe_free(p) do {if (p != NULL) {free((void *)p); p = NULL;}} while (0)
-
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-#define ERR_BUFFER_SIZE 256
-
-/*
- * API macros - leveraged from libusb-win32 1.x
- */
-#ifndef _WIN32_WCE
-#define DLL_STRINGIFY(s) #s
-#define DLL_LOAD_LIBRARY(name) LoadLibraryA(DLL_STRINGIFY(name))
-#else
-#define DLL_STRINGIFY(s) L#s
-#define DLL_LOAD_LIBRARY(name) LoadLibrary(DLL_STRINGIFY(name))
-#endif
-
-/*
- * Macros for handling DLL themselves
- */
-#define DLL_DECLARE_HANDLE(name) \
- static HMODULE __dll_##name##_handle = NULL
-
-#define DLL_GET_HANDLE(name) \
- do { \
- __dll_##name##_handle = DLL_LOAD_LIBRARY(name); \
- if (!__dll_##name##_handle) \
- return LIBUSB_ERROR_OTHER; \
- } while (0)
-
-#define DLL_FREE_HANDLE(name) \
- do { \
- if (__dll_##name##_handle) { \
- FreeLibrary(__dll_##name##_handle); \
- __dll_##name##_handle = NULL; \
- } \
- } while(0)
-
-
-/*
- * Macros for handling functions within a DLL
- */
-#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args) \
- typedef ret (api * __dll_##name##_func_t)args; \
- static __dll_##name##_func_t prefixname = NULL
-
-#define DLL_DECLARE_FUNC(api, ret, name, args) \
- DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)
-#define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args) \
- DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args)
-
-#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure) \
- do { \
- HMODULE h = __dll_##dll##_handle; \
- prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
- DLL_STRINGIFY(name)); \
- if (prefixname) \
- break; \
- prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
- DLL_STRINGIFY(name) DLL_STRINGIFY(A)); \
- if (prefixname) \
- break; \
- prefixname = (__dll_##name##_func_t)GetProcAddress(h, \
- DLL_STRINGIFY(name) DLL_STRINGIFY(W)); \
- if (prefixname) \
- break; \
- if (ret_on_failure) \
- return LIBUSB_ERROR_NOT_FOUND; \
- } while(0)
-
-#define DLL_LOAD_FUNC(dll, name, ret_on_failure) \
- DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)
-#define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure) \
- DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c
deleted file mode 100644
index d935394..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
- * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
- * 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
- */
-
-#include <config.h>
-
-#include <inttypes.h>
-#include <process.h>
-#include <stdio.h>
-
-#include "libusbi.h"
-#include "windows_common.h"
-#include "windows_nt_common.h"
-
-// Global variables for clock_gettime mechanism
-static uint64_t hires_ticks_to_ps;
-static uint64_t hires_frequency;
-
-#define TIMER_REQUEST_RETRY_MS 100
-#define WM_TIMER_REQUEST (WM_USER + 1)
-#define WM_TIMER_EXIT (WM_USER + 2)
-
-// used for monotonic clock_gettime()
-struct timer_request {
- struct timespec *tp;
- HANDLE event;
-};
-
-// Timer thread
-static HANDLE timer_thread = NULL;
-static DWORD timer_thread_id = 0;
-
-/* User32 dependencies */
-DLL_DECLARE_HANDLE(User32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, GetMessageA, (LPMSG, HWND, UINT, UINT));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PeekMessageA, (LPMSG, HWND, UINT, UINT, UINT));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, PostThreadMessageA, (DWORD, UINT, WPARAM, LPARAM));
-
-static unsigned __stdcall windows_clock_gettime_threaded(void *param);
-
-/*
-* Converts a windows error to human readable string
-* uses retval as errorcode, or, if 0, use GetLastError()
-*/
-#if defined(ENABLE_LOGGING)
-const char *windows_error_str(DWORD error_code)
-{
- static char err_string[ERR_BUFFER_SIZE];
-
- DWORD size;
- int len;
-
- if (error_code == 0)
- error_code = GetLastError();
-
- len = sprintf(err_string, "[%u] ", (unsigned int)error_code);
-
- // Translate codes returned by SetupAPI. The ones we are dealing with are either
- // in 0x0000xxxx or 0xE000xxxx and can be distinguished from standard error codes.
- // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff545011.aspx
- switch (error_code & 0xE0000000) {
- case 0:
- error_code = HRESULT_FROM_WIN32(error_code); // Still leaves ERROR_SUCCESS unmodified
- break;
- case 0xE0000000:
- error_code = 0x80000000 | (FACILITY_SETUPAPI << 16) | (error_code & 0x0000FFFF);
- break;
- default:
- break;
- }
-
- size = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- &err_string[len], ERR_BUFFER_SIZE - len, NULL);
- if (size == 0) {
- DWORD format_error = GetLastError();
- if (format_error)
- snprintf(err_string, ERR_BUFFER_SIZE,
- "Windows error code %u (FormatMessage error code %u)",
- (unsigned int)error_code, (unsigned int)format_error);
- else
- snprintf(err_string, ERR_BUFFER_SIZE, "Unknown error code %u", (unsigned int)error_code);
- } else {
- // Remove CRLF from end of message, if present
- size_t pos = len + size - 2;
- if (err_string[pos] == '\r')
- err_string[pos] = '\0';
- }
-
- return err_string;
-}
-#endif
-
-/* 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) */
-
-#define HTAB_SIZE 1021UL // *MUST* be a prime number!!
-
-typedef struct htab_entry {
- unsigned long used;
- char *str;
-} htab_entry;
-
-static htab_entry *htab_table = NULL;
-static usbi_mutex_t htab_mutex = NULL;
-static unsigned long htab_filled;
-
-/* 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 bool htab_create(struct libusb_context *ctx)
-{
- if (htab_table != NULL) {
- usbi_err(ctx, "hash table already allocated");
- return true;
- }
-
- // Create a mutex
- usbi_mutex_init(&htab_mutex);
-
- usbi_dbg("using %lu entries hash table", HTAB_SIZE);
- htab_filled = 0;
-
- // allocate memory and zero out.
- htab_table = calloc(HTAB_SIZE + 1, sizeof(htab_entry));
- if (htab_table == NULL) {
- usbi_err(ctx, "could not allocate space for hash table");
- return false;
- }
-
- return true;
-}
-
-/* After using the hash table it has to be destroyed. */
-static void htab_destroy(void)
-{
- unsigned long i;
-
- if (htab_table == NULL)
- return;
-
- for (i = 0; i < HTAB_SIZE; i++)
- free(htab_table[i].str);
-
- safe_free(htab_table);
-
- usbi_mutex_destroy(&htab_mutex);
-}
-
-/* This is the search function. It uses double hashing with open addressing.
- We use a 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. */
-unsigned long htab_hash(const char *str)
-{
- unsigned long hval, hval2;
- unsigned long idx;
- unsigned long r = 5381;
- int c;
- const char *sz = str;
-
- if (str == NULL)
- return 0;
-
- // Compute main hash value (algorithm suggested by Nokia)
- while ((c = *sz++) != 0)
- 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;
-
- // Mutually exclusive access (R/W lock would be better)
- usbi_mutex_lock(&htab_mutex);
-
- if (htab_table[idx].used) {
- if ((htab_table[idx].used == hval) && (strcmp(str, htab_table[idx].str) == 0))
- goto out_unlock; // existing hash
-
- 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) && (strcmp(str, htab_table[idx].str) == 0))
- goto out_unlock;
- } 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 (%lu entries)", HTAB_SIZE);
- idx = 0;
- goto out_unlock;
- }
-
- htab_table[idx].str = _strdup(str);
- if (htab_table[idx].str == NULL) {
- usbi_err(NULL, "could not duplicate string for hash table");
- idx = 0;
- goto out_unlock;
- }
-
- htab_table[idx].used = hval;
- ++htab_filled;
-
-out_unlock:
- usbi_mutex_unlock(&htab_mutex);
-
- return idx;
-}
-
-static int windows_init_dlls(void)
-{
- DLL_GET_HANDLE(User32);
- DLL_LOAD_FUNC_PREFIXED(User32, p, GetMessageA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(User32, p, PeekMessageA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(User32, p, PostThreadMessageA, TRUE);
-
- return LIBUSB_SUCCESS;
-}
-
-static void windows_exit_dlls(void)
-{
- DLL_FREE_HANDLE(User32);
-}
-
-static bool windows_init_clock(struct libusb_context *ctx)
-{
- DWORD_PTR affinity, dummy;
- HANDLE event = NULL;
- LARGE_INTEGER li_frequency;
- int i;
-
- if (QueryPerformanceFrequency(&li_frequency)) {
- // Load DLL imports
- if (windows_init_dlls() != LIBUSB_SUCCESS) {
- usbi_err(ctx, "could not resolve DLL functions");
- return false;
- }
-
- // 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_frequency = li_frequency.QuadPart;
- hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency;
- usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
-
- // 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 available core always to prevent timing discrepancies.
- if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy) || (affinity == 0)) {
- usbi_err(ctx, "could not get process affinity: %s", windows_error_str(0));
- return false;
- }
-
- // The process affinity mask is a bitmask where each set bit represents a core on
- // which this process is allowed to run, so we find the first set bit
- for (i = 0; !(affinity & (DWORD_PTR)(1 << i)); i++);
- affinity = (DWORD_PTR)(1 << i);
-
- usbi_dbg("timer thread will run on core #%d", i);
-
- event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (event == NULL) {
- usbi_err(ctx, "could not create event: %s", windows_error_str(0));
- return false;
- }
-
- timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, (void *)event,
- 0, (unsigned int *)&timer_thread_id);
- if (timer_thread == NULL) {
- usbi_err(ctx, "unable to create timer thread - aborting");
- CloseHandle(event);
- return false;
- }
-
- if (!SetThreadAffinityMask(timer_thread, affinity))
- usbi_warn(ctx, "unable to set timer thread affinity, timer discrepancies may arise");
-
- // Wait for timer thread to init before continuing.
- if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
- usbi_err(ctx, "failed to wait for timer thread to become ready - aborting");
- CloseHandle(event);
- return false;
- }
-
- CloseHandle(event);
- } else {
- usbi_dbg("no hires timer available on this platform");
- hires_frequency = 0;
- hires_ticks_to_ps = UINT64_C(0);
- }
-
- return true;
-}
-
-void windows_destroy_clock(void)
-{
- if (timer_thread) {
- // actually the signal to quit the thread.
- if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_EXIT, 0, 0)
- || (WaitForSingleObject(timer_thread, INFINITE) != WAIT_OBJECT_0)) {
- usbi_dbg("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;
- timer_thread_id = 0;
- }
-}
-
-/*
-* Monotonic and real time functions
-*/
-static unsigned __stdcall windows_clock_gettime_threaded(void *param)
-{
- struct timer_request *request;
- LARGE_INTEGER hires_counter;
- MSG msg;
-
- // The following call will create this thread's message queue
- // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644946.aspx
- pPeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
-
- // Signal windows_init_clock() that we're ready to service requests
- if (!SetEvent((HANDLE)param))
- usbi_dbg("SetEvent failed for timer init event: %s", windows_error_str(0));
- param = NULL;
-
- // Main loop - wait for requests
- while (1) {
- if (pGetMessageA(&msg, NULL, WM_TIMER_REQUEST, WM_TIMER_EXIT) == -1) {
- usbi_err(NULL, "GetMessage failed for timer thread: %s", windows_error_str(0));
- return 1;
- }
-
- switch (msg.message) {
- case WM_TIMER_REQUEST:
- // Requests to this thread are for hires always
- // Microsoft says that this function always succeeds on XP and later
- // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904.aspx
- request = (struct timer_request *)msg.lParam;
- QueryPerformanceCounter(&hires_counter);
- request->tp->tv_sec = (long)(hires_counter.QuadPart / hires_frequency);
- request->tp->tv_nsec = (long)(((hires_counter.QuadPart % hires_frequency) / 1000) * hires_ticks_to_ps);
- if (!SetEvent(request->event))
- usbi_err(NULL, "SetEvent failed for timer request: %s", windows_error_str(0));
- break;
- case WM_TIMER_EXIT:
- usbi_dbg("timer thread quitting");
- return 0;
- }
- }
-}
-
-int windows_clock_gettime(int clk_id, struct timespec *tp)
-{
- struct timer_request request;
-#if !defined(_MSC_VER) || (_MSC_VER < 1900)
- FILETIME filetime;
- ULARGE_INTEGER rtime;
-#endif
- DWORD r;
-
- switch (clk_id) {
- case USBI_CLOCK_MONOTONIC:
- if (timer_thread) {
- request.tp = tp;
- request.event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (request.event == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- if (!pPostThreadMessageA(timer_thread_id, WM_TIMER_REQUEST, 0, (LPARAM)&request)) {
- usbi_err(NULL, "PostThreadMessage failed for timer thread: %s", windows_error_str(0));
- CloseHandle(request.event);
- return LIBUSB_ERROR_OTHER;
- }
-
- do {
- r = WaitForSingleObject(request.event, TIMER_REQUEST_RETRY_MS);
- if (r == WAIT_TIMEOUT)
- usbi_dbg("could not obtain a timer value within reasonable timeframe - too much load?");
- else if (r == WAIT_FAILED)
- usbi_err(NULL, "WaitForSingleObject failed: %s", windows_error_str(0));
- } while (r == WAIT_TIMEOUT);
- CloseHandle(request.event);
-
- if (r == WAIT_OBJECT_0)
- return LIBUSB_SUCCESS;
- else
- return LIBUSB_ERROR_OTHER;
- }
- // Fall through and return real-time if monotonic was not detected @ timer init
- case USBI_CLOCK_REALTIME:
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
- timespec_get(tp, TIME_UTC);
-#else
- // 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);
-#endif
- return LIBUSB_SUCCESS;
- default:
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
-{
- int status, istatus;
-
- usbi_dbg("handling I/O completion with errcode %u, size %u", io_result, io_size);
-
- switch (io_result) {
- case NO_ERROR:
- status = windows_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:
- istatus = windows_copy_transfer_data(itransfer, io_size);
- if (istatus != LIBUSB_TRANSFER_COMPLETED)
- usbi_dbg("Failed to copy partial data in aborted operation: %d", istatus);
-
- usbi_dbg("detected operation aborted");
- status = LIBUSB_TRANSFER_CANCELLED;
- break;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "detected I/O error %u: %s", io_result, windows_error_str(io_result));
- status = LIBUSB_TRANSFER_ERROR;
- break;
- }
- windows_clear_transfer_priv(itransfer); // Cancel polling
- if (status == LIBUSB_TRANSFER_CANCELLED)
- usbi_handle_transfer_cancellation(itransfer);
- else
- usbi_handle_transfer_completion(itransfer, (enum libusb_transfer_status)status);
-}
-
-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;
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- usbi_warn(ITRANSFER_CTX(itransfer), "bulk stream transfers are not yet supported on this platform");
- break;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- }
-}
-
-int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready)
-{
- POLL_NFDS_TYPE i;
- bool found = false;
- struct usbi_transfer *transfer;
- struct winfd *pollable_fd = NULL;
- DWORD io_size, io_result;
- int r = LIBUSB_SUCCESS;
-
- 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);
- found = false;
- list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
- pollable_fd = windows_get_fd(transfer);
- if (pollable_fd->fd == fds[i].fd) {
- found = true;
- break;
- }
- }
- usbi_mutex_unlock(&ctx->flying_transfers_lock);
-
- if (found) {
- windows_get_overlapped_result(transfer, pollable_fd, &io_result, &io_size);
-
- usbi_remove_pollfd(ctx, 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 %d", fds[i]);
- r = LIBUSB_ERROR_NOT_FOUND;
- break;
- }
- }
- usbi_mutex_unlock(&ctx->open_devs_lock);
-
- return r;
-}
-
-int windows_common_init(struct libusb_context *ctx)
-{
- if (!windows_init_clock(ctx))
- goto error_roll_back;
-
- if (!htab_create(ctx))
- goto error_roll_back;
-
- return LIBUSB_SUCCESS;
-
-error_roll_back:
- windows_common_exit();
- return LIBUSB_ERROR_NO_MEM;
-}
-
-void windows_common_exit(void)
-{
- htab_destroy();
- windows_destroy_clock();
- windows_exit_dlls();
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h
deleted file mode 100644
index 52ea870..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_nt_common.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Windows backend common header for libusb 1.0
- *
- * This file brings together header code common between
- * the desktop Windows backends.
- * Copyright © 2012-2013 RealVNC Ltd.
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * 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
-
-// Missing from MinGW
-#if !defined(FACILITY_SETUPAPI)
-#define FACILITY_SETUPAPI 15
-#endif
-
-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 libusb_device_descriptor USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
-
-int windows_common_init(struct libusb_context *ctx);
-void windows_common_exit(void);
-
-unsigned long htab_hash(const char *str);
-int windows_clock_gettime(int clk_id, struct timespec *tp);
-
-void windows_clear_transfer_priv(struct usbi_transfer *itransfer);
-int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size);
-struct winfd *windows_get_fd(struct usbi_transfer *transfer);
-void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size);
-
-void windows_handle_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size);
-int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL_NFDS_TYPE nfds, int num_ready);
-
-#if defined(ENABLE_LOGGING)
-const char *windows_error_str(DWORD error_code);
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c
deleted file mode 100644
index 7cc5793..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.c
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
- * windows UsbDk backend for libusb 1.0
- * Copyright © 2014 Red Hat, Inc.
-
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Pavel Gurvich <pavel@daynix.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>
-
-#if defined(USE_USBDK)
-
-#include <windows.h>
-#include <cfgmgr32.h>
-#include <stdio.h>
-
-#include "libusbi.h"
-#include "windows_common.h"
-#include "windows_nt_common.h"
-
-#define ULONG64 uint64_t
-#define PVOID64 uint64_t
-
-typedef CONST WCHAR *PCWCHAR;
-#define wcsncpy_s wcsncpy
-
-#include "windows_usbdk.h"
-
-#if !defined(STATUS_SUCCESS)
-typedef LONG NTSTATUS;
-#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
-#endif
-
-#if !defined(STATUS_CANCELLED)
-#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
-#endif
-
-#if !defined(STATUS_REQUEST_CANCELED)
-#define STATUS_REQUEST_CANCELED ((NTSTATUS)0xC0000703L)
-#endif
-
-#if !defined(USBD_SUCCESS)
-typedef int32_t USBD_STATUS;
-#define USBD_SUCCESS(Status) ((USBD_STATUS) (Status) >= 0)
-#define USBD_PENDING(Status) ((ULONG) (Status) >> 30 == 1)
-#define USBD_ERROR(Status) ((USBD_STATUS) (Status) < 0)
-#define USBD_STATUS_STALL_PID ((USBD_STATUS) 0xc0000004)
-#define USBD_STATUS_ENDPOINT_HALTED ((USBD_STATUS) 0xc0000030)
-#define USBD_STATUS_BAD_START_FRAME ((USBD_STATUS) 0xc0000a00)
-#define USBD_STATUS_TIMEOUT ((USBD_STATUS) 0xc0006000)
-#define USBD_STATUS_CANCELED ((USBD_STATUS) 0xc0010000)
-#endif
-
-static int concurrent_usage = -1;
-
-struct usbdk_device_priv {
- USB_DK_DEVICE_INFO info;
- PUSB_CONFIGURATION_DESCRIPTOR *config_descriptors;
- HANDLE redirector_handle;
- uint8_t active_configuration;
-};
-
-struct usbdk_transfer_priv {
- USB_DK_TRANSFER_REQUEST request;
- struct winfd pollable_fd;
- PULONG64 IsochronousPacketsArray;
- PUSB_DK_ISO_TRANSFER_RESULT IsochronousResultsArray;
-};
-
-static inline struct usbdk_device_priv *_usbdk_device_priv(struct libusb_device *dev)
-{
- return (struct usbdk_device_priv *)dev->os_priv;
-}
-
-static inline struct usbdk_transfer_priv *_usbdk_transfer_priv(struct usbi_transfer *itransfer)
-{
- return (struct usbdk_transfer_priv *)usbi_transfer_get_os_priv(itransfer);
-}
-
-static struct {
- HMODULE module;
-
- USBDK_GET_DEVICES_LIST GetDevicesList;
- USBDK_RELEASE_DEVICES_LIST ReleaseDevicesList;
- USBDK_START_REDIRECT StartRedirect;
- USBDK_STOP_REDIRECT StopRedirect;
- USBDK_GET_CONFIGURATION_DESCRIPTOR GetConfigurationDescriptor;
- USBDK_RELEASE_CONFIGURATION_DESCRIPTOR ReleaseConfigurationDescriptor;
- USBDK_READ_PIPE ReadPipe;
- USBDK_WRITE_PIPE WritePipe;
- USBDK_ABORT_PIPE AbortPipe;
- USBDK_RESET_PIPE ResetPipe;
- USBDK_SET_ALTSETTING SetAltsetting;
- USBDK_RESET_DEVICE ResetDevice;
- USBDK_GET_REDIRECTOR_SYSTEM_HANDLE GetRedirectorSystemHandle;
-} usbdk_helper;
-
-static FARPROC get_usbdk_proc_addr(struct libusb_context *ctx, LPCSTR api_name)
-{
- FARPROC api_ptr = GetProcAddress(usbdk_helper.module, api_name);
-
- if (api_ptr == NULL)
- usbi_err(ctx, "UsbDkHelper API %s not found, error %d", api_name, GetLastError());
-
- return api_ptr;
-}
-
-static void unload_usbdk_helper_dll(void)
-{
- if (usbdk_helper.module != NULL) {
- FreeLibrary(usbdk_helper.module);
- usbdk_helper.module = NULL;
- }
-}
-
-static int load_usbdk_helper_dll(struct libusb_context *ctx)
-{
- usbdk_helper.module = LoadLibraryA("UsbDkHelper");
- if (usbdk_helper.module == NULL) {
- usbi_err(ctx, "Failed to load UsbDkHelper.dll, error %d", GetLastError());
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbdk_helper.GetDevicesList = (USBDK_GET_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_GetDevicesList");
- if (usbdk_helper.GetDevicesList == NULL)
- goto error_unload;
-
- usbdk_helper.ReleaseDevicesList = (USBDK_RELEASE_DEVICES_LIST)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseDevicesList");
- if (usbdk_helper.ReleaseDevicesList == NULL)
- goto error_unload;
-
- usbdk_helper.StartRedirect = (USBDK_START_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StartRedirect");
- if (usbdk_helper.StartRedirect == NULL)
- goto error_unload;
-
- usbdk_helper.StopRedirect = (USBDK_STOP_REDIRECT)get_usbdk_proc_addr(ctx, "UsbDk_StopRedirect");
- if (usbdk_helper.StopRedirect == NULL)
- goto error_unload;
-
- usbdk_helper.GetConfigurationDescriptor = (USBDK_GET_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_GetConfigurationDescriptor");
- if (usbdk_helper.GetConfigurationDescriptor == NULL)
- goto error_unload;
-
- usbdk_helper.ReleaseConfigurationDescriptor = (USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)get_usbdk_proc_addr(ctx, "UsbDk_ReleaseConfigurationDescriptor");
- if (usbdk_helper.ReleaseConfigurationDescriptor == NULL)
- goto error_unload;
-
- usbdk_helper.ReadPipe = (USBDK_READ_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ReadPipe");
- if (usbdk_helper.ReadPipe == NULL)
- goto error_unload;
-
- usbdk_helper.WritePipe = (USBDK_WRITE_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_WritePipe");
- if (usbdk_helper.WritePipe == NULL)
- goto error_unload;
-
- usbdk_helper.AbortPipe = (USBDK_ABORT_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_AbortPipe");
- if (usbdk_helper.AbortPipe == NULL)
- goto error_unload;
-
- usbdk_helper.ResetPipe = (USBDK_RESET_PIPE)get_usbdk_proc_addr(ctx, "UsbDk_ResetPipe");
- if (usbdk_helper.ResetPipe == NULL)
- goto error_unload;
-
- usbdk_helper.SetAltsetting = (USBDK_SET_ALTSETTING)get_usbdk_proc_addr(ctx, "UsbDk_SetAltsetting");
- if (usbdk_helper.SetAltsetting == NULL)
- goto error_unload;
-
- usbdk_helper.ResetDevice = (USBDK_RESET_DEVICE)get_usbdk_proc_addr(ctx, "UsbDk_ResetDevice");
- if (usbdk_helper.ResetDevice == NULL)
- goto error_unload;
-
- usbdk_helper.GetRedirectorSystemHandle = (USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)get_usbdk_proc_addr(ctx, "UsbDk_GetRedirectorSystemHandle");
- if (usbdk_helper.GetRedirectorSystemHandle == NULL)
- goto error_unload;
-
- return LIBUSB_SUCCESS;
-
-error_unload:
- FreeLibrary(usbdk_helper.module);
- usbdk_helper.module = NULL;
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-static int usbdk_init(struct libusb_context *ctx)
-{
- int r;
-
- if (++concurrent_usage == 0) { // First init?
- r = load_usbdk_helper_dll(ctx);
- if (r)
- goto init_exit;
-
- init_polling();
-
- r = windows_common_init(ctx);
- if (r)
- goto init_exit;
- }
- // At this stage, either we went through full init successfully, or didn't need to
- r = LIBUSB_SUCCESS;
-
-init_exit:
- if (!concurrent_usage && r != LIBUSB_SUCCESS) { // First init failed?
- exit_polling();
- windows_common_exit();
- unload_usbdk_helper_dll();
- }
-
- if (r != LIBUSB_SUCCESS)
- --concurrent_usage; // Not expected to call libusb_exit if we failed.
-
- return r;
-}
-
-static int usbdk_get_session_id_for_device(struct libusb_context *ctx,
- PUSB_DK_DEVICE_ID id, unsigned long *session_id)
-{
- char dev_identity[ARRAYSIZE(id->DeviceID) + ARRAYSIZE(id->InstanceID)];
-
- if (sprintf(dev_identity, "%S%S", id->DeviceID, id->InstanceID) == -1) {
- usbi_warn(ctx, "cannot form device identity", id->DeviceID);
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- *session_id = htab_hash(dev_identity);
-
- return LIBUSB_SUCCESS;
-}
-
-static void usbdk_release_config_descriptors(struct usbdk_device_priv *p, uint8_t count)
-{
- uint8_t i;
-
- for (i = 0; i < count; i++)
- usbdk_helper.ReleaseConfigurationDescriptor(p->config_descriptors[i]);
-
- free(p->config_descriptors);
- p->config_descriptors = NULL;
-}
-
-static int usbdk_cache_config_descriptors(struct libusb_context *ctx,
- struct usbdk_device_priv *p, PUSB_DK_DEVICE_INFO info)
-{
- uint8_t i;
- USB_DK_CONFIG_DESCRIPTOR_REQUEST Request;
- Request.ID = info->ID;
-
- p->config_descriptors = calloc(info->DeviceDescriptor.bNumConfigurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
- if (p->config_descriptors == NULL) {
- usbi_err(ctx, "failed to allocate configuration descriptors holder");
- return LIBUSB_ERROR_NO_MEM;
- }
-
- for (i = 0; i < info->DeviceDescriptor.bNumConfigurations; i++) {
- ULONG Length;
-
- Request.Index = i;
- if (!usbdk_helper.GetConfigurationDescriptor(&Request, &p->config_descriptors[i], &Length)) {
- usbi_err(ctx, "failed to retrieve configuration descriptors");
- usbdk_release_config_descriptors(p, i);
- return LIBUSB_ERROR_OTHER;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static inline int usbdk_device_priv_init(struct libusb_context *ctx, struct libusb_device *dev, PUSB_DK_DEVICE_INFO info)
-{
- struct usbdk_device_priv *p = _usbdk_device_priv(dev);
-
- p->info = *info;
- p->active_configuration = 0;
-
- return usbdk_cache_config_descriptors(ctx, p, info);
-}
-
-static void usbdk_device_init(libusb_device *dev, PUSB_DK_DEVICE_INFO info)
-{
- dev->bus_number = (uint8_t)info->FilterID;
- dev->port_number = (uint8_t)info->Port;
- dev->parent_dev = NULL;
-
- //Addresses in libusb are 1-based
- dev->device_address = (uint8_t)(info->Port + 1);
-
- dev->num_configurations = info->DeviceDescriptor.bNumConfigurations;
- dev->device_descriptor = info->DeviceDescriptor;
-
- switch (info->Speed) {
- case LowSpeed:
- dev->speed = LIBUSB_SPEED_LOW;
- break;
- case FullSpeed:
- dev->speed = LIBUSB_SPEED_FULL;
- break;
- case HighSpeed:
- dev->speed = LIBUSB_SPEED_HIGH;
- break;
- case SuperSpeed:
- dev->speed = LIBUSB_SPEED_SUPER;
- break;
- case NoSpeed:
- default:
- dev->speed = LIBUSB_SPEED_UNKNOWN;
- break;
- }
-}
-
-static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
-{
- int r = LIBUSB_SUCCESS;
- ULONG i;
- struct discovered_devs *discdevs = NULL;
- ULONG dev_number;
- PUSB_DK_DEVICE_INFO devices;
-
- if(!usbdk_helper.GetDevicesList(&devices, &dev_number))
- return LIBUSB_ERROR_OTHER;
-
- for (i = 0; i < dev_number; i++) {
- unsigned long session_id;
- struct libusb_device *dev = NULL;
-
- if (usbdk_get_session_id_for_device(ctx, &devices[i].ID, &session_id))
- continue;
-
- dev = usbi_get_device_by_session_id(ctx, session_id);
- if (dev == NULL) {
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL) {
- usbi_err(ctx, "failed to allocate a new device structure");
- continue;
- }
-
- usbdk_device_init(dev, &devices[i]);
- if (usbdk_device_priv_init(ctx, dev, &devices[i]) != LIBUSB_SUCCESS) {
- libusb_unref_device(dev);
- continue;
- }
- }
-
- discdevs = discovered_devs_append(*_discdevs, dev);
- libusb_unref_device(dev);
- if (!discdevs) {
- usbi_err(ctx, "cannot append new device to list");
- r = LIBUSB_ERROR_NO_MEM;
- goto func_exit;
- }
-
- *_discdevs = discdevs;
- }
-
-func_exit:
- usbdk_helper.ReleaseDevicesList(devices);
- return r;
-}
-
-static void usbdk_exit(void)
-{
- if (--concurrent_usage < 0) {
- windows_common_exit();
- exit_polling();
- unload_usbdk_helper_dll();
- }
-}
-
-static int usbdk_get_device_descriptor(struct libusb_device *dev, unsigned char *buffer, int *host_endian)
-{
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
-
- memcpy(buffer, &priv->info.DeviceDescriptor, DEVICE_DESC_LENGTH);
- *host_endian = 0;
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, unsigned char *buffer, size_t len, int *host_endian)
-{
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- size_t size;
-
- if (config_index >= dev->num_configurations)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptors[config_index];
-
- size = min(config_header->wTotalLength, len);
- memcpy(buffer, config_header, size);
- *host_endian = 0;
-
- return (int)size;
-}
-
-static inline int usbdk_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
-{
- return usbdk_get_config_descriptor(dev, _usbdk_device_priv(dev)->active_configuration,
- buffer, len, host_endian);
-}
-
-static int usbdk_open(struct libusb_device_handle *dev_handle)
-{
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
-
- priv->redirector_handle = usbdk_helper.StartRedirect(&priv->info.ID);
- if (priv->redirector_handle == INVALID_HANDLE_VALUE) {
- usbi_err(DEVICE_CTX(dev_handle->dev), "Redirector startup failed");
- return LIBUSB_ERROR_OTHER;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static void usbdk_close(struct libusb_device_handle *dev_handle)
-{
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.StopRedirect(priv->redirector_handle)) {
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- usbi_err(ctx, "Redirector shutdown failed");
- }
-}
-
-static int usbdk_get_configuration(struct libusb_device_handle *dev_handle, int *config)
-{
- *config = _usbdk_device_priv(dev_handle->dev)->active_configuration;
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_set_configuration(struct libusb_device_handle *dev_handle, int config)
-{
- UNUSED(dev_handle);
- UNUSED(config);
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_claim_interface(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.SetAltsetting(priv->redirector_handle, iface, altsetting)) {
- usbi_err(ctx, "SetAltsetting failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_release_interface(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.ResetPipe(priv->redirector_handle, endpoint)) {
- usbi_err(ctx, "ResetPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_reset_device(struct libusb_device_handle *dev_handle)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
- struct usbdk_device_priv *priv = _usbdk_device_priv(dev_handle->dev);
-
- if (!usbdk_helper.ResetDevice(priv->redirector_handle)) {
- usbi_err(ctx, "ResetDevice failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_kernel_driver_active(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int usbdk_attach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int usbdk_detach_kernel_driver(struct libusb_device_handle *dev_handle, int iface)
-{
- UNUSED(dev_handle);
- UNUSED(iface);
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static void usbdk_destroy_device(struct libusb_device *dev)
-{
- struct usbdk_device_priv* p = _usbdk_device_priv(dev);
-
- if (p->config_descriptors != NULL)
- usbdk_release_config_descriptors(p, p->info.DeviceDescriptor.bNumConfigurations);
-}
-
-void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- usbi_free_fd(&transfer_priv->pollable_fd);
-
- if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- safe_free(transfer_priv->IsochronousPacketsArray);
- safe_free(transfer_priv->IsochronousResultsArray);
- }
-}
-
-static int usbdk_do_control_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct winfd wfd;
- ULONG Length;
- TransferResult transResult;
- HANDLE sysHandle;
-
- sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
-
- wfd = usbi_create_fd(sysHandle, RW_READ, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
- transfer_priv->request.BufferLength = transfer->length;
- transfer_priv->request.TransferType = ControlTransferType;
- transfer_priv->pollable_fd = INVALID_WINFD;
- Length = (ULONG)transfer->length;
-
- if (IS_XFERIN(transfer))
- transResult = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
- else
- transResult = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
-
- switch (transResult) {
- case TransferSuccess:
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = (DWORD)Length;
- break;
- case TransferSuccessAsync:
- break;
- case TransferFailure:
- usbi_err(ctx, "ControlTransfer failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- return LIBUSB_ERROR_IO;
- }
-
- // Use priv_transfer to store data needed for async polling
- transfer_priv->pollable_fd = wfd;
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_do_bulk_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct winfd wfd;
- TransferResult transferRes;
- HANDLE sysHandle;
-
- transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
- transfer_priv->request.BufferLength = transfer->length;
- transfer_priv->request.EndpointAddress = transfer->endpoint;
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_BULK:
- transfer_priv->request.TransferType = BulkTransferType;
- break;
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- transfer_priv->request.TransferType = IntertuptTransferType;
- break;
- default:
- usbi_err(ctx, "Wrong transfer type (%d) in usbdk_do_bulk_transfer. %s", transfer->type, windows_error_str(0));
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- transfer_priv->pollable_fd = INVALID_WINFD;
-
- sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
-
- wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- if (IS_XFERIN(transfer))
- transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
- else
- transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
-
- switch (transferRes) {
- case TransferSuccess:
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- break;
- case TransferSuccessAsync:
- break;
- case TransferFailure:
- usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- return LIBUSB_ERROR_IO;
- }
-
- transfer_priv->pollable_fd = wfd;
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_do_iso_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
- struct usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(itransfer);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- struct winfd wfd;
- TransferResult transferRes;
- int i;
- HANDLE sysHandle;
-
- transfer_priv->request.Buffer = (PVOID64)(uintptr_t)transfer->buffer;
- transfer_priv->request.BufferLength = transfer->length;
- transfer_priv->request.EndpointAddress = transfer->endpoint;
- transfer_priv->request.TransferType = IsochronousTransferType;
- transfer_priv->request.IsochronousPacketsArraySize = transfer->num_iso_packets;
- transfer_priv->IsochronousPacketsArray = malloc(transfer->num_iso_packets * sizeof(ULONG64));
- transfer_priv->request.IsochronousPacketsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousPacketsArray;
- if (!transfer_priv->IsochronousPacketsArray) {
- usbi_err(ctx, "Allocation of IsochronousPacketsArray is failed, %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- transfer_priv->IsochronousResultsArray = malloc(transfer->num_iso_packets * sizeof(USB_DK_ISO_TRANSFER_RESULT));
- transfer_priv->request.Result.IsochronousResultsArray = (PVOID64)(uintptr_t)transfer_priv->IsochronousResultsArray;
- if (!transfer_priv->IsochronousResultsArray) {
- usbi_err(ctx, "Allocation of isochronousResultsArray is failed, %s", windows_error_str(0));
- free(transfer_priv->IsochronousPacketsArray);
- return LIBUSB_ERROR_IO;
- }
-
- for (i = 0; i < transfer->num_iso_packets; i++)
- transfer_priv->IsochronousPacketsArray[i] = transfer->iso_packet_desc[i].length;
-
- transfer_priv->pollable_fd = INVALID_WINFD;
-
- sysHandle = usbdk_helper.GetRedirectorSystemHandle(priv->redirector_handle);
-
- wfd = usbi_create_fd(sysHandle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0) {
- free(transfer_priv->IsochronousPacketsArray);
- free(transfer_priv->IsochronousResultsArray);
- return LIBUSB_ERROR_NO_MEM;
- }
-
- if (IS_XFERIN(transfer))
- transferRes = usbdk_helper.ReadPipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
- else
- transferRes = usbdk_helper.WritePipe(priv->redirector_handle, &transfer_priv->request, wfd.overlapped);
-
- switch (transferRes) {
- case TransferSuccess:
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- break;
- case TransferSuccessAsync:
- break;
- case TransferFailure:
- usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- free(transfer_priv->IsochronousPacketsArray);
- free(transfer_priv->IsochronousResultsArray);
- return LIBUSB_ERROR_IO;
- }
-
- transfer_priv->pollable_fd = wfd;
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, IS_XFERIN(transfer) ? POLLIN : POLLOUT);
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_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 usbdk_do_control_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
- return LIBUSB_ERROR_NOT_SUPPORTED; //TODO: Check whether we can support this in UsbDk
- else
- return usbdk_do_bulk_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return usbdk_do_iso_transfer(itransfer);
- default:
- usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-static int usbdk_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 usbdk_device_priv *priv = _usbdk_device_priv(transfer->dev_handle->dev);
-
- if (!usbdk_helper.AbortPipe(priv->redirector_handle, transfer->endpoint)) {
- usbi_err(ctx, "AbortPipe failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int usbdk_cancel_transfer(struct usbi_transfer *itransfer)
-{
- struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-
- switch (transfer->type) {
- case LIBUSB_TRANSFER_TYPE_CONTROL:
- // Control transfers cancelled by IoCancelXXX() API
- // No special treatment needed
- return LIBUSB_SUCCESS;
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return usbdk_abort_transfers(itransfer);
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-int windows_copy_transfer_data(struct usbi_transfer *itransfer, uint32_t io_size)
-{
- itransfer->transferred += io_size;
- return LIBUSB_TRANSFER_COMPLETED;
-}
-
-struct winfd *windows_get_fd(struct usbi_transfer *transfer)
-{
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
- return &transfer_priv->pollable_fd;
-}
-
-static DWORD usbdk_translate_usbd_status(USBD_STATUS UsbdStatus)
-{
- if (USBD_SUCCESS(UsbdStatus))
- return NO_ERROR;
-
- switch (UsbdStatus) {
- case USBD_STATUS_STALL_PID:
- case USBD_STATUS_ENDPOINT_HALTED:
- case USBD_STATUS_BAD_START_FRAME:
- return ERROR_GEN_FAILURE;
- case USBD_STATUS_TIMEOUT:
- return ERROR_SEM_TIMEOUT;
- case USBD_STATUS_CANCELED:
- return ERROR_OPERATION_ABORTED;
- default:
- return ERROR_FUNCTION_FAILED;
- }
-}
-
-void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
-{
- if (HasOverlappedIoCompletedSync(pollable_fd->overlapped) // Handle async requests that completed synchronously first
- || GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) { // Regular async overlapped
- struct libusb_transfer *ltransfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer);
- struct usbdk_transfer_priv *transfer_priv = _usbdk_transfer_priv(transfer);
-
- if (ltransfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
- int i;
- for (i = 0; i < transfer_priv->request.IsochronousPacketsArraySize; i++) {
- struct libusb_iso_packet_descriptor *lib_desc = &ltransfer->iso_packet_desc[i];
-
- switch (transfer_priv->IsochronousResultsArray[i].TransferResult) {
- case STATUS_SUCCESS:
- case STATUS_CANCELLED:
- case STATUS_REQUEST_CANCELED:
- lib_desc->status = LIBUSB_TRANSFER_COMPLETED; // == ERROR_SUCCESS
- break;
- default:
- lib_desc->status = LIBUSB_TRANSFER_ERROR; // ERROR_UNKNOWN_EXCEPTION;
- break;
- }
-
- lib_desc->actual_length = (unsigned int)transfer_priv->IsochronousResultsArray[i].ActualLength;
- }
- }
-
- *io_size = (DWORD) transfer_priv->request.Result.GenResult.BytesTransferred;
- *io_result = usbdk_translate_usbd_status((USBD_STATUS) transfer_priv->request.Result.GenResult.UsbdStatus);
- }
- else {
- *io_result = GetLastError();
- }
-}
-
-static int usbdk_clock_gettime(int clk_id, struct timespec *tp)
-{
- return windows_clock_gettime(clk_id, tp);
-}
-
-const struct usbi_os_backend usbdk_backend = {
- "Windows",
- USBI_CAP_HAS_HID_ACCESS,
- usbdk_init,
- usbdk_exit,
-
- usbdk_get_device_list,
- NULL,
- usbdk_open,
- usbdk_close,
-
- usbdk_get_device_descriptor,
- usbdk_get_active_config_descriptor,
- usbdk_get_config_descriptor,
- NULL,
-
- usbdk_get_configuration,
- usbdk_set_configuration,
- usbdk_claim_interface,
- usbdk_release_interface,
-
- usbdk_set_interface_altsetting,
- usbdk_clear_halt,
- usbdk_reset_device,
-
- NULL,
- NULL,
-
- NULL, // dev_mem_alloc()
- NULL, // dev_mem_free()
-
- usbdk_kernel_driver_active,
- usbdk_detach_kernel_driver,
- usbdk_attach_kernel_driver,
-
- usbdk_destroy_device,
-
- usbdk_submit_transfer,
- usbdk_cancel_transfer,
- windows_clear_transfer_priv,
-
- windows_handle_events,
- NULL,
-
- usbdk_clock_gettime,
-#if defined(USBI_TIMERFD_AVAILABLE)
- NULL,
-#endif
- sizeof(struct usbdk_device_priv),
- 0,
- sizeof(struct usbdk_transfer_priv),
-};
-
-#endif /* USE_USBDK */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h
deleted file mode 100644
index 04a9787..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_usbdk.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-* windows UsbDk backend for libusb 1.0
-* Copyright © 2014 Red Hat, Inc.
-
-* Authors:
-* Dmitry Fleytman <dmitry@daynix.com>
-* Pavel Gurvich <pavel@daynix.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
-*/
-
-#pragma once
-
-typedef struct tag_USB_DK_DEVICE_ID {
- WCHAR DeviceID[MAX_DEVICE_ID_LEN];
- WCHAR InstanceID[MAX_DEVICE_ID_LEN];
-} USB_DK_DEVICE_ID, *PUSB_DK_DEVICE_ID;
-
-static inline void UsbDkFillIDStruct(USB_DK_DEVICE_ID *ID, PCWCHAR DeviceID, PCWCHAR InstanceID)
-{
- wcsncpy_s(ID->DeviceID, DeviceID, MAX_DEVICE_ID_LEN);
- wcsncpy_s(ID->InstanceID, InstanceID, MAX_DEVICE_ID_LEN);
-}
-
-typedef struct tag_USB_DK_DEVICE_INFO {
- USB_DK_DEVICE_ID ID;
- ULONG64 FilterID;
- ULONG64 Port;
- ULONG64 Speed;
- USB_DEVICE_DESCRIPTOR DeviceDescriptor;
-} USB_DK_DEVICE_INFO, *PUSB_DK_DEVICE_INFO;
-
-typedef struct tag_USB_DK_CONFIG_DESCRIPTOR_REQUEST {
- USB_DK_DEVICE_ID ID;
- ULONG64 Index;
-} USB_DK_CONFIG_DESCRIPTOR_REQUEST, *PUSB_DK_CONFIG_DESCRIPTOR_REQUEST;
-
-typedef struct tag_USB_DK_ISO_TRANSFER_RESULT {
- ULONG64 ActualLength;
- ULONG64 TransferResult;
-} USB_DK_ISO_TRANSFER_RESULT, *PUSB_DK_ISO_TRANSFER_RESULT;
-
-typedef struct tag_USB_DK_GEN_TRANSFER_RESULT {
- ULONG64 BytesTransferred;
- ULONG64 UsbdStatus; // USBD_STATUS code
-} USB_DK_GEN_TRANSFER_RESULT, *PUSB_DK_GEN_TRANSFER_RESULT;
-
-typedef struct tag_USB_DK_TRANSFER_RESULT {
- USB_DK_GEN_TRANSFER_RESULT GenResult;
- PVOID64 IsochronousResultsArray; // array of USB_DK_ISO_TRANSFER_RESULT
-} USB_DK_TRANSFER_RESULT, *PUSB_DK_TRANSFER_RESULT;
-
-typedef struct tag_USB_DK_TRANSFER_REQUEST {
- ULONG64 EndpointAddress;
- PVOID64 Buffer;
- ULONG64 BufferLength;
- ULONG64 TransferType;
- ULONG64 IsochronousPacketsArraySize;
- PVOID64 IsochronousPacketsArray;
-
- USB_DK_TRANSFER_RESULT Result;
-} USB_DK_TRANSFER_REQUEST, *PUSB_DK_TRANSFER_REQUEST;
-
-typedef enum {
- TransferFailure = 0,
- TransferSuccess,
- TransferSuccessAsync
-} TransferResult;
-
-typedef enum {
- NoSpeed = 0,
- LowSpeed,
- FullSpeed,
- HighSpeed,
- SuperSpeed
-} USB_DK_DEVICE_SPEED;
-
-typedef enum {
- ControlTransferType,
- BulkTransferType,
- IntertuptTransferType,
- IsochronousTransferType
-} USB_DK_TRANSFER_TYPE;
-
-typedef BOOL (__cdecl *USBDK_GET_DEVICES_LIST)(
- PUSB_DK_DEVICE_INFO *DeviceInfo,
- PULONG DeviceNumber
-);
-typedef void (__cdecl *USBDK_RELEASE_DEVICES_LIST)(
- PUSB_DK_DEVICE_INFO DeviceInfo
-);
-typedef HANDLE (__cdecl *USBDK_START_REDIRECT)(
- PUSB_DK_DEVICE_ID DeviceId
-);
-typedef BOOL (__cdecl *USBDK_STOP_REDIRECT)(
- HANDLE DeviceHandle
-);
-typedef BOOL (__cdecl *USBDK_GET_CONFIGURATION_DESCRIPTOR)(
- PUSB_DK_CONFIG_DESCRIPTOR_REQUEST Request,
- PUSB_CONFIGURATION_DESCRIPTOR *Descriptor,
- PULONG Length
-);
-typedef void (__cdecl *USBDK_RELEASE_CONFIGURATION_DESCRIPTOR)(
- PUSB_CONFIGURATION_DESCRIPTOR Descriptor
-);
-typedef TransferResult (__cdecl *USBDK_WRITE_PIPE)(
- HANDLE DeviceHandle,
- PUSB_DK_TRANSFER_REQUEST Request,
- LPOVERLAPPED lpOverlapped
-);
-typedef TransferResult (__cdecl *USBDK_READ_PIPE)(
- HANDLE DeviceHandle,
- PUSB_DK_TRANSFER_REQUEST Request,
- LPOVERLAPPED lpOverlapped
-);
-typedef BOOL (__cdecl *USBDK_ABORT_PIPE)(
- HANDLE DeviceHandle,
- ULONG64 PipeAddress
-);
-typedef BOOL (__cdecl *USBDK_RESET_PIPE)(
- HANDLE DeviceHandle,
- ULONG64 PipeAddress
-);
-typedef BOOL (__cdecl *USBDK_SET_ALTSETTING)(
- HANDLE DeviceHandle,
- ULONG64 InterfaceIdx,
- ULONG64 AltSettingIdx
-);
-typedef BOOL (__cdecl *USBDK_RESET_DEVICE)(
- HANDLE DeviceHandle
-);
-typedef HANDLE (__cdecl *USBDK_GET_REDIRECTOR_SYSTEM_HANDLE)(
- HANDLE DeviceHandle
-);
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c
deleted file mode 100644
index 0dce0ea..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.c
+++ /dev/null
@@ -1,4290 +0,0 @@
-/*
- * windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * With contributions from Michael Plante, Orin Eman et al.
- * Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
- * HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
- * 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
- */
-
-#include <config.h>
-
-#if !defined(USE_USBDK)
-
-#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_winusb.h"
-
-#define HANDLE_VALID(h) (((h) != 0) && ((h) != INVALID_HANDLE_VALUE))
-
-// 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; \
- }
-
-// WinUSB-like API prototypes
-static int winusbx_init(int sub_api, struct libusb_context *ctx);
-static int winusbx_exit(int sub_api);
-static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
-static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int winusbx_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer);
-static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
-// HID API prototypes
-static int hid_init(int sub_api, struct libusb_context *ctx);
-static int hid_exit(int sub_api);
-static int hid_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void hid_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
-static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int hid_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
-// Composite API prototypes
-static int composite_init(int sub_api, struct libusb_context *ctx);
-static int composite_exit(int sub_api);
-static int composite_open(int sub_api, struct libusb_device_handle *dev_handle);
-static void composite_close(int sub_api, struct libusb_device_handle *dev_handle);
-static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
-static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface);
-static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
-static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
-static int composite_abort_transfers(int sub_api, struct usbi_transfer *itransfer);
-static int composite_abort_control(int sub_api, struct usbi_transfer *itransfer);
-static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
-static int composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size);
-
-
-// Global variables
-int windows_version = WINDOWS_UNDEFINED;
-static char windows_version_str[128] = "Undefined";
-// Concurrency
-static int concurrent_usage = -1;
-static usbi_mutex_t autoclaim_lock;
-// API globals
-#define CHECK_WINUSBX_AVAILABLE(sub_api) \
- do { \
- if (sub_api == SUB_API_NOTSET) \
- sub_api = priv->sub_api; \
- if (!WinUSBX[sub_api].initialized) \
- return LIBUSB_ERROR_ACCESS; \
- } while(0)
-
-static HMODULE WinUSBX_handle = NULL;
-static struct winusb_interface WinUSBX[SUB_API_MAX];
-static const char *sub_api_name[SUB_API_MAX] = WINUSBX_DRV_NAMES;
-
-static bool api_hid_available = false;
-#define CHECK_HID_AVAILABLE \
- do { \
- if (!api_hid_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_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
-
-/*
- * 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;
- char *ret_path;
- size_t add_root = 0;
-
- if (path == NULL)
- return NULL;
-
- size = strlen(path) + 1;
-
- // Microsoft indiscriminately uses '\\?\', '\\.\', '##?#" or "##.#" for root prefixes.
- if (!((size > 3) && (((path[0] == '\\') && (path[1] == '\\') && (path[3] == '\\'))
- || ((path[0] == '#') && (path[1] == '#') && (path[3] == '#'))))) {
- add_root = sizeof(root_prefix);
- size += add_root;
- }
-
- ret_path = malloc(size);
- if (ret_path == NULL)
- return NULL;
-
- strcpy(&ret_path[add_root], path);
-
- // Ensure consistency with root prefix
- memcpy(ret_path, root_prefix, sizeof(root_prefix));
-
- // Same goes for '\' and '#' after the root prefix. Ensure '#' is used
- for (j = sizeof(root_prefix); 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_GET_HANDLE(Cfgmgr32);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Sibling, TRUE);
- DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Device_IDA, TRUE);
-
- // Prefixed to avoid conflict with header files
- DLL_GET_HANDLE(AdvAPI32);
- DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE);
- DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE);
-
- DLL_GET_HANDLE(Kernel32);
- DLL_LOAD_FUNC_PREFIXED(Kernel32, p, IsWow64Process, FALSE);
-
- DLL_GET_HANDLE(OLE32);
- DLL_LOAD_FUNC_PREFIXED(OLE32, p, CLSIDFromString, TRUE);
-
- DLL_GET_HANDLE(SetupAPI);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE);
- DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE);
-
- return LIBUSB_SUCCESS;
-}
-
-static void exit_dlls(void)
-{
- DLL_FREE_HANDLE(Cfgmgr32);
- DLL_FREE_HANDLE(AdvAPI32);
- DLL_FREE_HANDLE(Kernel32);
- DLL_FREE_HANDLE(OLE32);
- DLL_FREE_HANDLE(SetupAPI);
-}
-
-/*
- * 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, const 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;
- 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;
- }
-
- dev_interface_details = calloc(1, size);
- if (dev_interface_details == 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;
-}
-
-/* For libusb0 filter */
-static SP_DEVICE_INTERFACE_DETAIL_DATA_A *get_interface_details_filter(struct libusb_context *ctx,
- HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const GUID *guid, unsigned _index, char *filter_path)
-{
- SP_DEVICE_INTERFACE_DATA dev_interface_data;
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details;
- 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;
- }
-
- dev_interface_details = calloc(1, size);
- if (dev_interface_details == 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));
-
- // [trobinso] lookup the libusb0 symbolic index.
- if (dev_interface_details) {
- HKEY hkey_device_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ);
- if (hkey_device_interface != INVALID_HANDLE_VALUE) {
- DWORD libusb0_symboliclink_index = 0;
- DWORD value_length = sizeof(DWORD);
- DWORD value_type = 0;
- LONG status;
-
- status = pRegQueryValueExW(hkey_device_interface, L"LUsb0", NULL, &value_type,
- (LPBYTE)&libusb0_symboliclink_index, &value_length);
- if (status == ERROR_SUCCESS) {
- if (libusb0_symboliclink_index < 256) {
- // libusb0.sys is connected to this device instance.
- // If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter.
- sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index);
- usbi_dbg("assigned libusb0 symbolic link %s", filter_path);
- } else {
- // libusb0.sys was connected to this device instance at one time; but not anymore.
- }
- }
- pRegCloseKey(hkey_device_interface);
- }
- }
-
- return dev_interface_details;
-
-err_exit:
- pSetupDiDestroyDeviceInfoList(*dev_info);
- *dev_info = INVALID_HANDLE_VALUE;
- return NULL;
-}
-
-/*
- * 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;
- char *sanitized_path;
- 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);
- free(sanitized_path);
- return session_id;
-}
-
-/*
- * Determine which interface the given endpoint address belongs to
- */
-static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep)
-{
- const struct libusb_interface *intf;
- const struct libusb_interface_descriptor *intf_desc;
- int i, j, k;
-
- for (i = 0; i < conf_desc->bNumInterfaces; i++) {
- intf = &conf_desc->interface[i];
- for (j = 0; j < intf->num_altsetting; j++) {
- intf_desc = &intf->altsetting[j];
- for (k = 0; k < intf_desc->bNumEndpoints; k++) {
- if (intf_desc->endpoint[k].bEndpointAddress == ep) {
- usbi_dbg("found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i);
- return intf_desc->bInterfaceNumber;
- }
- }
- }
- }
-
- usbi_dbg("endpoint %02X not found on any interface", ep);
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/*
- * 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_active_config_descriptor(dev_handle->dev, &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);
- libusb_free_config_descriptor(conf_desc);
- return LIBUSB_SUCCESS;
- }
-
- priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
- if (priv->usb_interface[iface].endpoint == NULL) {
- libusb_free_config_descriptor(conf_desc);
- 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 may be required to configure endpoints
- return priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface);
-}
-
-// Lookup for a match in the list of API driver names
-// return -1 if not found, driver match number otherwise
-static int get_sub_api(char *driver, int api)
-{
- int i;
- const char sep_str[2] = {LIST_SEPARATOR, 0};
- char *tok, *tmp_str;
- size_t len = strlen(driver);
-
- if (len == 0)
- return SUB_API_NOTSET;
-
- tmp_str = _strdup(driver);
- if (tmp_str == NULL)
- return SUB_API_NOTSET;
-
- tok = strtok(tmp_str, sep_str);
- while (tok != NULL) {
- for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) {
- if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) {
- free(tmp_str);
- return i;
- }
- }
- tok = strtok(NULL, sep_str);
- }
-
- free(tmp_str);
- return SUB_API_NOTSET;
-}
-
-/*
- * auto-claiming and auto-release helper functions
- */
-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;
-
- switch(api_type) {
- case USB_API_WINUSBX:
- case USB_API_HID:
- break;
- default:
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- 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 = 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 (%s)",
- transfer_priv->interface_number, libusb_error_name((enum libusb_error)r));
- }
- }
- usbi_mutex_unlock(&autoclaim_lock);
-}
-
-/* Windows version dtection */
-static BOOL is_x64(void)
-{
- BOOL ret = FALSE;
-
- // Detect if we're running a 32 or 64 bit system
- if (sizeof(uintptr_t) < 8) {
- if (pIsWow64Process != NULL)
- pIsWow64Process(GetCurrentProcess(), &ret);
- } else {
- ret = TRUE;
- }
-
- return ret;
-}
-
-static void get_windows_version(void)
-{
- OSVERSIONINFOEXA vi, vi2;
- const char *arch, *w = NULL;
- unsigned major, minor;
- ULONGLONG major_equal, minor_equal;
- BOOL ws;
-
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(vi);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
- memset(&vi, 0, sizeof(vi));
- vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
- if (!GetVersionExA((OSVERSIONINFOA *)&vi))
- return;
- }
-
- if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
- if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
- // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
- // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
-
- major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
- for (major = vi.dwMajorVersion; major <= 9; major++) {
- memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMajorVersion = major;
- if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
- continue;
-
- if (vi.dwMajorVersion < major) {
- vi.dwMajorVersion = major;
- vi.dwMinorVersion = 0;
- }
-
- minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
- for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
- memset(&vi2, 0, sizeof(vi2));
- vi2.dwOSVersionInfoSize = sizeof(vi2);
- vi2.dwMinorVersion = minor;
- if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
- continue;
-
- vi.dwMinorVersion = minor;
- break;
- }
-
- break;
- }
- }
-
- if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
- ws = (vi.wProductType <= VER_NT_WORKSTATION);
- windows_version = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
- switch (windows_version) {
- case 0x50: w = "2000"; break;
- case 0x51: w = "XP"; break;
- case 0x52: w = "2003"; break;
- case 0x60: w = (ws ? "Vista" : "2008"); break;
- case 0x61: w = (ws ? "7" : "2008_R2"); break;
- case 0x62: w = (ws ? "8" : "2012"); break;
- case 0x63: w = (ws ? "8.1" : "2012_R2"); break;
- case 0x64: w = (ws ? "10" : "2015"); break;
- default:
- if (windows_version < 0x50)
- windows_version = WINDOWS_UNSUPPORTED;
- else
- w = "11 or later";
- break;
- }
- }
- }
-
- arch = is_x64() ? "64-bit" : "32-bit";
-
- if (w == NULL)
- snprintf(windows_version_str, sizeof(windows_version_str), "%s %u.%u %s",
- (vi.dwPlatformId == VER_PLATFORM_WIN32_NT ? "NT" : "??"),
- (unsigned int)vi.dwMajorVersion, (unsigned int)vi.dwMinorVersion, arch);
- else if (vi.wServicePackMinor)
- snprintf(windows_version_str, sizeof(windows_version_str), "%s SP%u.%u %s",
- w, vi.wServicePackMajor, vi.wServicePackMinor, arch);
- else if (vi.wServicePackMajor)
- snprintf(windows_version_str, sizeof(windows_version_str), "%s SP%u %s",
- w, vi.wServicePackMajor, arch);
- else
- snprintf(windows_version_str, sizeof(windows_version_str), "%s %s",
- w, arch);
-}
-
-/*
- * 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;
- HANDLE semaphore;
- char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-
- 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?
- get_windows_version();
- usbi_dbg("Windows %s", windows_version_str);
-
- if (windows_version == WINDOWS_UNSUPPORTED) {
- usbi_err(ctx, "This version of Windows is NOT supported");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- goto init_exit;
- }
-
- // We need a lock for proper auto-release
- usbi_mutex_init(&autoclaim_lock);
-
- // Initialize pollable file descriptors
- init_polling();
-
- // Load DLL imports
- if (init_dlls() != LIBUSB_SUCCESS) {
- usbi_err(ctx, "could not resolve DLL functions");
- goto init_exit;
- }
-
- // 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(SUB_API_NOTSET, ctx);
-
- r = windows_common_init(ctx);
- if (r)
- goto init_exit;
- }
- // 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?
- for (i = 0; i < USB_API_MAX; i++)
- usb_api_backend[i].exit(SUB_API_NOTSET);
- exit_dlls();
- exit_polling();
- windows_common_exit();
- usbi_mutex_destroy(&autoclaim_lock);
- }
-
- 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 (dev->parent_dev == NULL) {
- usbi_err(ctx, "program assertion failed - HCD hub has no parent");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- parent_priv = _device_priv(dev->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 = calloc(dev->num_configurations, sizeof(unsigned char *));
- 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 = 0;
- cd_buf_short.req.SetupPacket.wLength = (USHORT)(size - sizeof(USB_DESCRIPTOR_REQUEST));
-
- // Dummy call to get the required data size. Initial failures are reported as info rather
- // than error as they can occur for non-penalizing situations, such as with some hubs.
- // coverity[tainted_data_argument]
- if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size,
- &cd_buf_short, size, &ret_size, NULL)) {
- usbi_info(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_info(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;
- cd_buf_actual = calloc(1, size);
- if (cd_buf_actual == NULL) {
- usbi_err(ctx, "could not allocate configuration descriptor buffer for '%s'.", device_id);
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
-
- // 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 = 0;
- 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=%u, %u 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)
- LOOP_BREAK(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;
- USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
- struct windows_device_priv *priv, *parent_priv;
- struct libusb_context *ctx;
- struct libusb_device *tmp_dev;
- unsigned long tmp_id;
- unsigned i;
-
- if ((dev == NULL) || (parent_dev == NULL))
- return LIBUSB_ERROR_NOT_FOUND;
-
- ctx = DEVICE_CTX(dev);
- 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_id = get_ancestor_session_id(devinst, i);
- if (tmp_id == 0)
- break;
-
- tmp_dev = usbi_get_device_by_session_id(ctx, tmp_id);
- if (tmp_dev == NULL)
- continue;
-
- if (tmp_dev->bus_number != 0) {
- usbi_dbg("got bus number from ancestor #%u", i);
- parent_dev->bus_number = tmp_dev->bus_number;
- libusb_unref_device(tmp_dev);
- break;
- }
-
- libusb_unref_device(tmp_dev);
- }
- }
-
- 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;
- dev->port_number = port_number;
- priv->depth = parent_priv->depth + 1;
- dev->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;
- // coverity[tainted_data_argument]
- 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));
- CloseHandle(handle);
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- if (conn_info.ConnectionStatus == NoDeviceConnected) {
- usbi_err(ctx, "device '%s' is no longer connected!", device_id);
- 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 %u configurations (active conf: %u)", 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;
- }
-
- // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
- if (windows_version >= WINDOWS_8) {
- memset(&conn_info_v2, 0, sizeof(conn_info_v2));
- size = sizeof(conn_info_v2);
- conn_info_v2.ConnectionIndex = (ULONG)port_number;
- conn_info_v2.Length = size;
- conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
- if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
- &conn_info_v2, size, &conn_info_v2, size, &size, NULL)) {
- usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s",
- device_id, windows_error_str(0));
- } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
- conn_info.Speed = 3;
- }
- }
-
- 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 + 1;
- if (dev->device_address == 1)
- usbi_err(ctx, "program assertion failed: device address collision with root hub");
-
- 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;
- case 3: dev->speed = LIBUSB_SPEED_SUPER; break;
- default:
- usbi_warn(ctx, "Got unknown device speed %u", conn_info.Speed);
- break;
- }
- } else {
- dev->device_address = 1; // root hubs are set to use device number 1
- force_hcd_device_descriptor(dev);
- }
-
- usbi_sanitize_device(dev);
-
- usbi_dbg("(bus: %u, addr: %u, depth: %u, port: %u): '%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 void get_api_type(struct libusb_context *ctx, HDEVINFO *dev_info,
- SP_DEVINFO_DATA *dev_info_data, int *api, int *sub_api)
-{
- // 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;
- int i, j;
-
- *api = USB_API_UNSUPPORTED;
- *sub_api = SUB_API_NOTSET;
-
- // 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,
- &reg_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[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;
- }
- 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 (i = 1; i < USB_API_MAX; i++) {
- for (k = 0; k < 3; k++) {
- j = get_sub_api(lookup[k].list, i);
- if (j >= 0) {
- usbi_dbg("matched %s name against %s", lookup[k].designation,
- (i != USB_API_WINUSBX) ? usb_api_backend[i].designation : sub_api_name[j]);
- *api = i;
- *sub_api = j;
- return;
- }
- }
- }
-}
-
-static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev,
- char *dev_interface_path, char *device_id, int api, int sub_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) {
- if (api == USB_API_HID) {
- // HID devices can have multiple collections (COL##) for each MI_## interface
- usbi_dbg("interface[%d] already set - ignoring HID collection: %s",
- interface_number, device_id);
- return LIBUSB_ERROR_ACCESS;
- }
- // In other cases, just use the latest data
- safe_free(priv->usb_interface[interface_number].path);
- }
-
- 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->usb_interface[interface_number].sub_api = sub_api;
- if ((api == USB_API_HID) && (priv->hid == NULL)) {
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL)
- return LIBUSB_ERROR_NO_MEM;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
- char *dev_interface_path)
-{
- int i;
- struct windows_device_priv *priv = _device_priv(dev);
-
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed: parent is not HID");
- return LIBUSB_ERROR_NO_DEVICE;
- } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
- usbi_err(ctx, "program assertion failed: max USB interfaces reached for HID device");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- for (i = 0; i < priv->hid->nb_interfaces; i++) {
- if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
- usbi_dbg("interface[%d] already set to %s", i, dev_interface_path);
- return LIBUSB_ERROR_ACCESS;
- }
- }
-
- priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
- priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
- usbi_dbg("interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path);
- priv->hid->nb_interfaces++;
- 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;
- HDEVINFO dev_info = { 0 };
- const char *usb_class[] = {"USB", "NUSB3", "IUSB3", "IARUSB3"};
- SP_DEVINFO_DATA dev_info_data = { 0 };
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
- GUID hid_guid;
-#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
-#define HID_PASS 4
- int r = LIBUSB_SUCCESS;
- int api, sub_api;
- size_t 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;
- HKEY key;
- WCHAR guid_string_w[MAX_GUID_STRING_LENGTH];
- GUID *if_guid;
- LONG s;
- // Keep a list of newly allocated devs to unref
- libusb_device **unref_list, **new_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 (including HID) 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;
- HidD_GetHidGuid(&hid_guid);
- guid[HID_PASS] = &hid_guid;
- nb_guids = HID_PASS + 1;
-
- unref_list = calloc(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
-#if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG)
- const char *passname[] = { "HCD", "HUB", "GEN", "DEV", "HID", "EXT" };
- usbi_dbg("#### PROCESSING %ss %s", passname[(pass <= HID_PASS) ? pass : (HID_PASS + 1)],
- (pass != GEN_PASS) ? guid_to_string(guid[pass]) : "");
-#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);
- 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;
-
- 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".
- // The Intel USB 3.0 driver behaves similar, but uses "IUSB3"
- // The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3"
- for (; class_index < ARRAYSIZE(usb_class); class_index++) {
- if (get_devinfo_data(ctx, &dev_info, &dev_info_data, usb_class[class_index], i))
- break;
- i = 0;
- }
- if (class_index >= ARRAYSIZE(usb_class))
- 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",
- (unsigned int)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",
- (unsigned int)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,
- &reg_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;
- sub_api = SUB_API_NOTSET;
- 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,
- &reg_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, &reg_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));
- if (if_guid == NULL) {
- usbi_err(ctx, "could not calloc for if_guid: not enough memory");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- }
- pCLSIDFromString(guid_string_w, if_guid);
- guid[nb_guids++] = if_guid;
- usbi_dbg("extra GUID: %s", guid_to_string(if_guid));
- }
- }
- break;
- case HID_PASS:
- api = USB_API_HID;
- break;
- default:
- // Get the API type (after checking that the driver installation is OK)
- if ((!pSetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
- &reg_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: %u) - skipping",
- dev_id_path, (unsigned int)install_state);
- continue;
- }
- get_api_type(ctx, &dev_info, &dev_info_data, &api, &sub_api);
- 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' (non USB HID, 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)) {
- libusb_unref_device(parent_dev);
- 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 [%lX]", session_id);
- dev = usbi_alloc_device(ctx, session_id);
- if (dev == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
-
- priv = windows_device_priv_init(dev);
- } else {
- usbi_dbg("found existing device for session [%lX] (%u.%u)",
- session_id, dev->bus_number, dev->device_address);
-
- priv = _device_priv(dev);
- if ((parent_dev != NULL) && (dev->parent_dev != NULL)) {
- if (dev->parent_dev != parent_dev) {
- // It is possible for the actual parent device to not have existed at the
- // time of enumeration, so the currently assigned parent may in fact be a
- // grandparent. If the devices differ, we assume the "new" parent device
- // is in fact closer to the device.
- usbi_dbg("updating parent device [session %lX -> %lX]",
- dev->parent_dev->session_data, parent_dev->session_data);
- libusb_unref_device(dev->parent_dev);
- dev->parent_dev = parent_dev;
- } else {
- // We hold a reference to parent_dev instance, but this device already
- // has a parent_dev reference (only one per child)
- libusb_unref_device(parent_dev);
- }
- }
- }
-
- // Keep track of devices that need unref
- unref_list[unref_cur++] = dev;
- if (unref_cur >= unref_size) {
- unref_size += 64;
- new_unref_list = usbi_reallocf(unref_list, unref_size * sizeof(libusb_device *));
- if (new_unref_list == NULL) {
- usbi_err(ctx, "could not realloc list for unref - aborting.");
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
- } else {
- unref_list = new_unref_list;
- }
- }
- }
-
- // Setup device
- switch (pass) {
- case HCD_PASS:
- // If the hcd has already been setup, don't do it again
- if (priv->path != NULL)
- break;
- 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->sub_api = SUB_API_NOTSET;
- 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];
- priv->sub_api = sub_api;
- switch(api) {
- case USB_API_COMPOSITE:
- case USB_API_HUB:
- break;
- case USB_API_HID:
- priv->hid = calloc(1, sizeof(struct hid_device_priv));
- if (priv->hid == NULL)
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
-
- priv->hid->nb_interfaces = 0;
- break;
- default:
- // For other devices, the first interface is the same as the device
- priv->usb_interface[0].path = _strdup(priv->path);
- if (priv->usb_interface[0].path == NULL)
- usbi_warn(ctx, "could not duplicate interface path '%s'", 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: // HID_PASS and later
- if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) {
- if (parent_priv->apib->id == USB_API_HID) {
- usbi_dbg("setting HID interface for [%lX]:", parent_dev->session_data);
- r = set_hid_interface(ctx, parent_dev, dev_interface_path);
- } else {
- usbi_dbg("setting composite interface for [%lX]:", parent_dev->session_data);
- r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id_path, api, sub_api);
- }
- switch (r) {
- 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
- r = LIBUSB_SUCCESS;
- break;
- default:
- LOOP_BREAK(r);
- break;
- }
- }
- libusb_unref_device(parent_dev);
- break;
- }
- }
- }
-
- // Free any additional GUIDs
- for (pass = HID_PASS + 1; pass < nb_guids; pass++)
- free((void *)guid[pass]);
-
- // Unref newly allocated devs
- for (i = 0; i < unref_cur; i++)
- libusb_unref_device(unref_list[i]);
- free(unref_list);
-
- return r;
-}
-
-/*
- * exit: libusb backend deinitialization function
- */
-static void windows_exit(void)
-{
- int i;
- HANDLE semaphore;
- char sem_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
-
- 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(SUB_API_NOTSET);
- exit_dlls();
- exit_polling();
- windows_common_exit();
- usbi_mutex_destroy(&autoclaim_lock);
- }
-
- 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);
- *host_endian = 0;
-
- return (int)size;
-}
-
-static int windows_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
- unsigned char **buffer, int *host_endian)
-{
- struct windows_device_priv *priv = _device_priv(dev);
- PUSB_CONFIGURATION_DESCRIPTOR config_header;
- uint8_t index;
-
- *buffer = NULL;
- *host_endian = 0;
-
- if (priv->config_descriptor == NULL)
- return LIBUSB_ERROR_NOT_FOUND;
-
- for (index = 0; index < dev->num_configurations; index++) {
- config_header = (PUSB_CONFIGURATION_DESCRIPTOR)priv->config_descriptor[index];
- if (config_header->bConfigurationValue == bConfigurationValue) {
- *buffer = priv->config_descriptor[index];
- return (int)config_header->wTotalLength;
- }
- }
-
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-/*
- * 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);
- unsigned char *config_desc;
- int r;
-
- if (priv->active_config == 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- r = windows_get_config_descriptor_by_value(dev, priv->active_config, &config_desc, host_endian);
- if (r < 0)
- return r;
-
- len = MIN((size_t)r, len);
- memcpy(buffer, config_desc, len);
- return (int)len;
-}
-
-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(SUB_API_NOTSET, 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(SUB_API_NOTSET, 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);
-
- safe_free(priv->usb_interface[iface].endpoint);
- priv->usb_interface[iface].nb_endpoints = 0;
-
- r = priv->apib->claim_interface(SUB_API_NOTSET, 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(SUB_API_NOTSET, 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(SUB_API_NOTSET, 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(SUB_API_NOTSET, 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(SUB_API_NOTSET, 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);
-}
-
-void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
-
- usbi_free_fd(&transfer_priv->pollable_fd);
- safe_free(transfer_priv->hid_buffer);
- // When auto claim is in use, attempt to release the auto-claimed interface
- auto_release(itransfer);
-}
-
-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 = 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(SUB_API_NOTSET, itransfer);
- if (r != LIBUSB_SUCCESS)
- return r;
-
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
- (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
-
- 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 = 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(SUB_API_NOTSET, itransfer);
- if (r != LIBUSB_SUCCESS)
- return r;
-
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd,
- (short)(IS_XFERIN(transfer) ? POLLIN : POLLOUT));
-
- 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 = 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(SUB_API_NOTSET, itransfer);
- if (r != LIBUSB_SUCCESS)
- return r;
-
- usbi_add_pollfd(ctx, transfer_priv->pollable_fd.fd, POLLIN);
-
- 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:
- if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
- return LIBUSB_ERROR_NOT_SUPPORTED;
- return submit_bulk_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return submit_iso_transfer(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- return LIBUSB_ERROR_NOT_SUPPORTED;
- 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(SUB_API_NOTSET, 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(SUB_API_NOTSET, itransfer);
-}
-
-static int windows_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 windows_abort_control(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK:
- case LIBUSB_TRANSFER_TYPE_INTERRUPT:
- case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return windows_abort_transfers(itransfer);
- case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
- return LIBUSB_ERROR_NOT_SUPPORTED;
- default:
- usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-}
-
-int windows_copy_transfer_data(struct usbi_transfer *itransfer, 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);
- return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, io_size);
-}
-
-struct winfd *windows_get_fd(struct usbi_transfer *transfer)
-{
- struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(transfer);
- return &transfer_priv->pollable_fd;
-}
-
-void windows_get_overlapped_result(struct usbi_transfer *transfer, struct winfd *pollable_fd, DWORD *io_result, DWORD *io_size)
-{
- if (HasOverlappedIoCompletedSync(pollable_fd->overlapped)) {
- *io_result = NO_ERROR;
- *io_size = (DWORD)pollable_fd->overlapped->InternalHigh;
- } else if (GetOverlappedResult(pollable_fd->handle, pollable_fd->overlapped, io_size, false)) {
- // Regular async overlapped
- *io_result = NO_ERROR;
- } else {
- *io_result = GetLastError();
- }
-}
-
-// NB: MSVC6 does not support named initializers.
-const struct usbi_os_backend windows_backend = {
- "Windows",
- USBI_CAP_HAS_HID_ACCESS,
- windows_init,
- windows_exit,
-
- windows_get_device_list,
- NULL, /* hotplug_poll */
- windows_open,
- windows_close,
-
- windows_get_device_descriptor,
- windows_get_active_config_descriptor,
- windows_get_config_descriptor,
- windows_get_config_descriptor_by_value,
-
- windows_get_configuration,
- windows_set_configuration,
- windows_claim_interface,
- windows_release_interface,
-
- windows_set_interface_altsetting,
- windows_clear_halt,
- windows_reset_device,
-
- NULL, /* alloc_streams */
- NULL, /* free_streams */
-
- NULL, /* dev_mem_alloc */
- NULL, /* dev_mem_free */
-
- 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,
- NULL,
-
- 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),
-};
-
-
-/*
- * USB API backends
- */
-static int unsupported_init(int sub_api, struct libusb_context *ctx)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int unsupported_exit(int sub_api)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int unsupported_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- PRINT_UNSUPPORTED_API(open);
-}
-
-static void unsupported_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- usbi_dbg("unsupported API call for 'close'");
-}
-
-static int unsupported_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- PRINT_UNSUPPORTED_API(configure_endpoints);
-}
-
-static int unsupported_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- PRINT_UNSUPPORTED_API(claim_interface);
-}
-
-static int unsupported_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- PRINT_UNSUPPORTED_API(set_interface_altsetting);
-}
-
-static int unsupported_release_interface(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- PRINT_UNSUPPORTED_API(release_interface);
-}
-
-static int unsupported_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
-{
- PRINT_UNSUPPORTED_API(clear_halt);
-}
-
-static int unsupported_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- PRINT_UNSUPPORTED_API(reset_device);
-}
-
-static int unsupported_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(submit_bulk_transfer);
-}
-
-static int unsupported_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(submit_iso_transfer);
-}
-
-static int unsupported_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(submit_control_transfer);
-}
-
-static int unsupported_abort_control(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(abort_control);
-}
-
-static int unsupported_abort_transfers(int sub_api, struct usbi_transfer *itransfer)
-{
- PRINT_UNSUPPORTED_API(abort_transfers);
-}
-
-static int unsupported_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- PRINT_UNSUPPORTED_API(copy_transfer_data);
-}
-
-static int common_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_SUCCESS;
-}
-
-// These names must be uppercase
-static const char *hub_driver_names[] = {"USBHUB", "USBHUB3", "USB3HUB", "NUSB3HUB", "RUSB3HUB", "FLXHCIH", "TIHUB3", "ETRONHUB3", "VIAHUB3", "ASMTHUB3", "IUSB3HUB", "VUSB3HUB", "AMDHUB30", "VHHUB", "AUSB3HUB"};
-static const char *composite_driver_names[] = {"USBCCGP"};
-static const char *winusbx_driver_names[] = WINUSBX_DRV_NAMES;
-static const char *hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
-const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
- {
- USB_API_UNSUPPORTED,
- "Unsupported API",
- NULL,
- 0,
- unsupported_init,
- unsupported_exit,
- unsupported_open,
- unsupported_close,
- unsupported_configure_endpoints,
- 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",
- hub_driver_names,
- ARRAYSIZE(hub_driver_names),
- unsupported_init,
- unsupported_exit,
- unsupported_open,
- unsupported_close,
- unsupported_configure_endpoints,
- 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",
- composite_driver_names,
- ARRAYSIZE(composite_driver_names),
- composite_init,
- composite_exit,
- composite_open,
- composite_close,
- common_configure_endpoints,
- 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_WINUSBX,
- "WinUSB-like APIs",
- winusbx_driver_names,
- ARRAYSIZE(winusbx_driver_names),
- winusbx_init,
- winusbx_exit,
- winusbx_open,
- winusbx_close,
- winusbx_configure_endpoints,
- winusbx_claim_interface,
- winusbx_set_interface_altsetting,
- winusbx_release_interface,
- winusbx_clear_halt,
- winusbx_reset_device,
- winusbx_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- winusbx_submit_control_transfer,
- winusbx_abort_control,
- winusbx_abort_transfers,
- winusbx_copy_transfer_data,
- },
- {
- USB_API_HID,
- "HID API",
- hid_driver_names,
- ARRAYSIZE(hid_driver_names),
- hid_init,
- hid_exit,
- hid_open,
- hid_close,
- common_configure_endpoints,
- hid_claim_interface,
- hid_set_interface_altsetting,
- hid_release_interface,
- hid_clear_halt,
- hid_reset_device,
- hid_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- hid_submit_control_transfer,
- hid_abort_transfers,
- hid_abort_transfers,
- hid_copy_transfer_data,
- },
-};
-
-
-/*
- * WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions
- */
-#define WinUSBX_Set(fn) \
- do { \
- if (native_winusb) \
- WinUSBX[i].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \
- else \
- pLibK_GetProcAddress((PVOID *)&WinUSBX[i].fn, i, KUSB_FNID_##fn); \
- } while (0)
-
-static int winusbx_init(int sub_api, struct libusb_context *ctx)
-{
- HMODULE h;
- bool native_winusb;
- int i;
- KLIB_VERSION LibK_Version;
- LibK_GetProcAddress_t pLibK_GetProcAddress = NULL;
- LibK_GetVersion_t pLibK_GetVersion;
-
- h = LoadLibraryA("libusbK");
-
- if (h == NULL) {
- usbi_info(ctx, "libusbK DLL is not available, will use native WinUSB");
- h = LoadLibraryA("WinUSB");
-
- if (h == NULL) {
- usbi_warn(ctx, "WinUSB DLL is not available either, "
- "you will not be able to access devices outside of enumeration");
- return LIBUSB_ERROR_NOT_FOUND;
- }
- } else {
- usbi_dbg("using libusbK DLL for universal access");
- pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(h, "LibK_GetVersion");
- if (pLibK_GetVersion != NULL) {
- pLibK_GetVersion(&LibK_Version);
- usbi_dbg("libusbK version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
- LibK_Version.Micro, LibK_Version.Nano);
- }
- pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(h, "LibK_GetProcAddress");
- if (pLibK_GetProcAddress == NULL) {
- usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL");
- FreeLibrary(h);
- return LIBUSB_ERROR_NOT_FOUND;
- }
- }
-
- native_winusb = (pLibK_GetProcAddress == NULL);
- for (i = SUB_API_LIBUSBK; i < SUB_API_MAX; i++) {
- WinUSBX_Set(AbortPipe);
- WinUSBX_Set(ControlTransfer);
- WinUSBX_Set(FlushPipe);
- WinUSBX_Set(Free);
- WinUSBX_Set(GetAssociatedInterface);
- WinUSBX_Set(GetCurrentAlternateSetting);
- WinUSBX_Set(GetDescriptor);
- WinUSBX_Set(GetOverlappedResult);
- WinUSBX_Set(GetPipePolicy);
- WinUSBX_Set(GetPowerPolicy);
- WinUSBX_Set(Initialize);
- WinUSBX_Set(QueryDeviceInformation);
- WinUSBX_Set(QueryInterfaceSettings);
- WinUSBX_Set(QueryPipe);
- WinUSBX_Set(ReadPipe);
- WinUSBX_Set(ResetPipe);
- WinUSBX_Set(SetCurrentAlternateSetting);
- WinUSBX_Set(SetPipePolicy);
- WinUSBX_Set(SetPowerPolicy);
- WinUSBX_Set(WritePipe);
- if (!native_winusb)
- WinUSBX_Set(ResetDevice);
-
- if (WinUSBX[i].Initialize != NULL) {
- WinUSBX[i].initialized = true;
- usbi_dbg("initalized sub API %s", sub_api_name[i]);
- } else {
- usbi_warn(ctx, "Failed to initalize sub API %s", sub_api_name[i]);
- WinUSBX[i].initialized = false;
- }
- }
-
- WinUSBX_handle = h;
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_exit(int sub_api)
-{
- if (WinUSBX_handle != NULL) {
- FreeLibrary(WinUSBX_handle);
- WinUSBX_handle = NULL;
-
- /* Reset the WinUSBX API structures */
- memset(&WinUSBX, 0, sizeof(WinUSBX));
- }
-
- 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 winusbx_open(int sub_api, 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_WINUSBX_AVAILABLE(sub_api);
-
- // WinUSB requires a separate 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_WINUSBX)) {
- 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 winusbx_close(int sub_api, 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 handle;
- int i;
-
- if (sub_api == SUB_API_NOTSET)
- sub_api = priv->sub_api;
-
- if (!WinUSBX[sub_api].initialized)
- return;
-
- if (priv->apib->id == USB_API_COMPOSITE) {
- // If this is a composite device, just free and close all WinUSB-like
- // interfaces directly (each is independent and not associated with another)
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
- handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
-
- handle = handle_priv->interface_handle[i].dev_handle;
- if (HANDLE_VALID(handle))
- CloseHandle(handle);
- }
- }
- } else {
- // If this is a WinUSB device, free all interfaces above interface 0,
- // then free and close interface 0 last
- for (i = 1; i < USB_MAXINTERFACES; i++) {
- handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
- }
- handle = handle_priv->interface_handle[0].api_handle;
- if (HANDLE_VALID(handle))
- WinUSBX[sub_api].Free(handle);
-
- handle = handle_priv->interface_handle[0].dev_handle;
- if (HANDLE_VALID(handle))
- CloseHandle(handle);
- }
-}
-
-static int winusbx_configure_endpoints(int sub_api, 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_WINUSBX_AVAILABLE(sub_api);
-
- // 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 (!WinUSBX[sub_api].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) || (sub_api == SUB_API_LIBUSB0))
- continue; // Other policies don't apply to control endpoint or libusb0
-
- policy = false;
- if (!WinUSBX[sub_api].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 (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy))
- usbi_dbg("failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address);
-
- policy = true;
- /* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See:
- https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */
- if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
- ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy))
- usbi_dbg("failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address);
-
- if (!WinUSBX[sub_api].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 winusbx_claim_interface(int sub_api, 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);
- SP_DEVICE_INTERFACE_DETAIL_DATA_A *dev_interface_details = NULL;
- HDEVINFO dev_info = INVALID_HANDLE_VALUE;
- SP_DEVINFO_DATA dev_info_data;
- char *dev_path_no_guid = NULL;
- char filter_path[] = "\\\\.\\libusb0-0000";
- bool found_filter = false;
- HANDLE file_handle, winusb_handle;
- DWORD err;
- int i;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- // If the device is composite, but using the default Windows composite parent driver (usbccgp)
- // or if it's the first WinUSB-like interface, we get a handle through Initialize().
- if ((is_using_usbccgp) || (iface == 0)) {
- // composite device (independent interfaces) or interface 0
- file_handle = handle_priv->interface_handle[iface].dev_handle;
- if (!HANDLE_VALID(file_handle))
- return LIBUSB_ERROR_NOT_FOUND;
-
- if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
- err = GetLastError();
- switch(err) {
- case ERROR_BAD_COMMAND:
- // The device was disconnected
- usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_NO_DEVICE;
- default:
- // it may be that we're using the libusb0 filter driver.
- // TODO: can we move this whole business into the K/0 DLL?
- for (i = 0; ; i++) {
- safe_free(dev_interface_details);
- safe_free(dev_path_no_guid);
-
- dev_interface_details = get_interface_details_filter(ctx, &dev_info, &dev_info_data, &GUID_DEVINTERFACE_LIBUSB0_FILTER, i, filter_path);
- if ((found_filter) || (dev_interface_details == NULL))
- break;
-
- // ignore GUID part
- dev_path_no_guid = sanitize_path(strtok(dev_interface_details->DevicePath, "{"));
- if (dev_path_no_guid == NULL)
- continue;
-
- if (strncmp(dev_path_no_guid, priv->usb_interface[iface].path, strlen(dev_path_no_guid)) == 0) {
- file_handle = CreateFileA(filter_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) {
- if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
- // Replace the existing file handle with the working one
- CloseHandle(handle_priv->interface_handle[iface].dev_handle);
- handle_priv->interface_handle[iface].dev_handle = file_handle;
- found_filter = true;
- } else {
- usbi_err(ctx, "could not initialize filter driver for %s", filter_path);
- CloseHandle(file_handle);
- }
- } else {
- usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0));
- }
- }
- }
- free(dev_interface_details);
- if (!found_filter) {
- usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(err));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- }
- handle_priv->interface_handle[iface].api_handle = winusb_handle;
- } else {
- // For all other interfaces, use GetAssociatedInterface()
- winusb_handle = handle_priv->interface_handle[0].api_handle;
- // It is a requirement for multiple interface devices on Windows that, to you
- // must first claim the first interface before you claim the others
- if (!HANDLE_VALID(winusb_handle)) {
- file_handle = handle_priv->interface_handle[0].dev_handle;
- if (WinUSBX[sub_api].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): %s", iface, windows_error_str(0));
- return LIBUSB_ERROR_ACCESS;
- }
- }
- if (!WinUSBX[sub_api].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 winusbx_release_interface(int sub_api, 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;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- winusb_handle = handle_priv->interface_handle[iface].api_handle;
- if (!HANDLE_VALID(winusb_handle))
- return LIBUSB_ERROR_NOT_FOUND;
-
- WinUSBX[sub_api].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 get_valid_interface(struct libusb_device_handle *dev_handle, int api_id)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int i;
-
- if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
- usbi_dbg("unsupported API ID");
- return -1;
- }
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle)
- && HANDLE_VALID(handle_priv->interface_handle[i].api_handle)
- && (priv->usb_interface[i].apib->id == api_id))
- 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_VALID(handle_priv->interface_handle[i].api_handle))
- 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 winusbx_submit_control_transfer(int sub_api, 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 = 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_WINUSBX_AVAILABLE(sub_api);
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- // Windows places upper limits on the control transfer size
- // See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff538112.aspx
- if (size > MAX_CTRL_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX);
- if (current_interface < 0) {
- if (auto_claim(transfer, &current_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("will use interface %d", current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- wfd = usbi_create_fd(winusb_handle, RW_READ, NULL, NULL);
- // 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);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = 0;
- } else {
- if (!WinUSBX[sub_api].ControlTransfer(wfd.handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, NULL, wfd.overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_warn(ctx, "ControlTransfer failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- 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 winusbx_set_interface_altsetting(int sub_api, 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);
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- HANDLE winusb_handle;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- if (altsetting > 255)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- winusb_handle = handle_priv->interface_handle[iface].api_handle;
- if (!HANDLE_VALID(winusb_handle)) {
- usbi_err(ctx, "interface must be claimed first");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, (UCHAR)altsetting)) {
- usbi_err(ctx, "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
- return LIBUSB_ERROR_IO;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_submit_bulk_transfer(int sub_api, 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 = 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 ret;
- int current_interface;
- struct winfd wfd;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- 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;
-
- wfd = usbi_create_fd(winusb_handle, IS_XFERIN(transfer) ? RW_READ : RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- if (IS_XFERIN(transfer)) {
- usbi_dbg("reading %d bytes", transfer->length);
- ret = WinUSBX[sub_api].ReadPipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
- } else {
- usbi_dbg("writing %d bytes", transfer->length);
- ret = WinUSBX[sub_api].WritePipe(wfd.handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, wfd.overlapped);
- }
-
- if (!ret) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_err(ctx, "ReadPipe/WritePipe failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- 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 winusbx_clear_halt(int sub_api, 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_WINUSBX_AVAILABLE(sub_api);
-
- 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 (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) {
- usbi_err(ctx, "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 winusbx_abort_control(int sub_api, struct usbi_transfer *itransfer)
-{
- // Cancelling of the I/O is done in the parent
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_abort_transfers(int sub_api, 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);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- HANDLE winusb_handle;
- int current_interface;
-
- CHECK_WINUSBX_AVAILABLE(sub_api);
-
- 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 (!WinUSBX[sub_api].AbortPipe(winusb_handle, transfer->endpoint)) {
- usbi_err(ctx, "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 winusbx_reset_device(int sub_api, 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_WINUSBX_AVAILABLE(sub_api);
-
- // 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);
- wfd = handle_to_winfd(winusb_handle);
- }
-
- if (HANDLE_VALID(winusb_handle)) {
- for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
- usbi_dbg("resetting ep %02X", priv->usb_interface[i].endpoint[j]);
- if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
- usbi_err(ctx, "AbortPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
-
- // FlushPipe seems to fail on OUT pipes
- if (IS_EPIN(priv->usb_interface[i].endpoint[j])
- && (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])))
- usbi_err(ctx, "FlushPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
-
- if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
- usbi_err(ctx, "ResetPipe (pipe address %02X) failed: %s",
- priv->usb_interface[i].endpoint[j], windows_error_str(0));
- }
- }
- }
-
- // libusbK & libusb0 have the ability to issue an actual device reset
- if (WinUSBX[sub_api].ResetDevice != NULL) {
- winusb_handle = handle_priv->interface_handle[0].api_handle;
- if (HANDLE_VALID(winusb_handle))
- WinUSBX[sub_api].ResetDevice(winusb_handle);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- itransfer->transferred += io_size;
- return LIBUSB_TRANSFER_COMPLETED;
-}
-
-/*
- * Internal HID Support functions (from libusb-win32)
- * Note that functions that complete data transfer synchronously must return
- * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS
- */
-static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size);
-static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size);
-
-static int _hid_wcslen(WCHAR *str)
-{
- int i = 0;
-
- while (str[i] && (str[i] != 0x409))
- i++;
-
- return i;
-}
-
-static int _hid_get_device_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- struct libusb_device_descriptor d;
-
- d.bLength = LIBUSB_DT_DEVICE_SIZE;
- d.bDescriptorType = LIBUSB_DT_DEVICE;
- d.bcdUSB = 0x0200; /* 2.00 */
- d.bDeviceClass = 0;
- d.bDeviceSubClass = 0;
- d.bDeviceProtocol = 0;
- d.bMaxPacketSize0 = 64; /* fix this! */
- d.idVendor = (uint16_t)dev->vid;
- d.idProduct = (uint16_t)dev->pid;
- d.bcdDevice = 0x0100;
- d.iManufacturer = dev->string_index[0];
- d.iProduct = dev->string_index[1];
- d.iSerialNumber = dev->string_index[2];
- d.bNumConfigurations = 1;
-
- if (*size > LIBUSB_DT_DEVICE_SIZE)
- *size = LIBUSB_DT_DEVICE_SIZE;
- memcpy(data, &d, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_config_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- char num_endpoints = 0;
- size_t config_total_len = 0;
- char tmp[HID_MAX_CONFIG_DESC_SIZE];
- struct libusb_config_descriptor *cd;
- struct libusb_interface_descriptor *id;
- struct libusb_hid_descriptor *hd;
- struct libusb_endpoint_descriptor *ed;
- size_t tmp_size;
-
- if (dev->input_report_size)
- num_endpoints++;
- if (dev->output_report_size)
- num_endpoints++;
-
- config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE
- + LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE;
-
- cd = (struct libusb_config_descriptor *)tmp;
- id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE);
- hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
- + LIBUSB_DT_INTERFACE_SIZE);
- ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
- + LIBUSB_DT_INTERFACE_SIZE
- + LIBUSB_DT_HID_SIZE);
-
- cd->bLength = LIBUSB_DT_CONFIG_SIZE;
- cd->bDescriptorType = LIBUSB_DT_CONFIG;
- cd->wTotalLength = (uint16_t)config_total_len;
- cd->bNumInterfaces = 1;
- cd->bConfigurationValue = 1;
- cd->iConfiguration = 0;
- cd->bmAttributes = 1 << 7; /* bus powered */
- cd->MaxPower = 50;
-
- id->bLength = LIBUSB_DT_INTERFACE_SIZE;
- id->bDescriptorType = LIBUSB_DT_INTERFACE;
- id->bInterfaceNumber = 0;
- id->bAlternateSetting = 0;
- id->bNumEndpoints = num_endpoints;
- id->bInterfaceClass = 3;
- id->bInterfaceSubClass = 0;
- id->bInterfaceProtocol = 0;
- id->iInterface = 0;
-
- tmp_size = LIBUSB_DT_HID_SIZE;
- _hid_get_hid_descriptor(dev, hd, &tmp_size);
-
- if (dev->input_report_size) {
- ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
- ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
- ed->bEndpointAddress = HID_IN_EP;
- ed->bmAttributes = 3;
- ed->wMaxPacketSize = dev->input_report_size - 1;
- ed->bInterval = 10;
- ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE);
- }
-
- if (dev->output_report_size) {
- ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
- ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
- ed->bEndpointAddress = HID_OUT_EP;
- ed->bmAttributes = 3;
- ed->wMaxPacketSize = dev->output_report_size - 1;
- ed->bInterval = 10;
- }
-
- if (*size > config_total_len)
- *size = config_total_len;
- memcpy(data, tmp, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_string_descriptor(struct hid_device_priv *dev, int _index,
- void *data, size_t *size)
-{
- void *tmp = NULL;
- size_t tmp_size = 0;
- int i;
-
- /* language ID, EN-US */
- char string_langid[] = {0x09, 0x04};
-
- if ((*size < 2) || (*size > 255))
- return LIBUSB_ERROR_OVERFLOW;
-
- if (_index == 0) {
- tmp = string_langid;
- tmp_size = sizeof(string_langid) + 2;
- } else {
- for (i = 0; i < 3; i++) {
- if (_index == (dev->string_index[i])) {
- tmp = dev->string[i];
- tmp_size = (_hid_wcslen(dev->string[i]) + 1) * sizeof(WCHAR);
- break;
- }
- }
-
- if (i == 3) // not found
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- if (!tmp_size)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (tmp_size < *size)
- *size = tmp_size;
-
- // 2 byte header
- ((uint8_t *)data)[0] = (uint8_t)*size;
- ((uint8_t *)data)[1] = LIBUSB_DT_STRING;
- memcpy((uint8_t *)data + 2, tmp, *size - 2);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- struct libusb_hid_descriptor d;
- uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE];
- size_t report_len = MAX_HID_DESCRIPTOR_SIZE;
-
- _hid_get_report_descriptor(dev, tmp, &report_len);
-
- d.bLength = LIBUSB_DT_HID_SIZE;
- d.bDescriptorType = LIBUSB_DT_HID;
- d.bcdHID = 0x0110; /* 1.10 */
- d.bCountryCode = 0;
- d.bNumDescriptors = 1;
- d.bClassDescriptorType = LIBUSB_DT_REPORT;
- d.wClassDescriptorLength = (uint16_t)report_len;
-
- if (*size > LIBUSB_DT_HID_SIZE)
- *size = LIBUSB_DT_HID_SIZE;
- memcpy(data, &d, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size)
-{
- uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
- size_t i = 0;
-
- /* usage page (0xFFA0 == vendor defined) */
- d[i++] = 0x06; d[i++] = 0xA0; d[i++] = 0xFF;
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x01;
- /* start collection (application) */
- d[i++] = 0xA1; d[i++] = 0x01;
- /* input report */
- if (dev->input_report_size) {
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x01;
- /* logical minimum (0) */
- d[i++] = 0x15; d[i++] = 0x00;
- /* logical maximum (255) */
- d[i++] = 0x25; d[i++] = 0xFF;
- /* report size (8 bits) */
- d[i++] = 0x75; d[i++] = 0x08;
- /* report count */
- d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1;
- /* input (data, variable, absolute) */
- d[i++] = 0x81; d[i++] = 0x00;
- }
- /* output report */
- if (dev->output_report_size) {
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x02;
- /* logical minimum (0) */
- d[i++] = 0x15; d[i++] = 0x00;
- /* logical maximum (255) */
- d[i++] = 0x25; d[i++] = 0xFF;
- /* report size (8 bits) */
- d[i++] = 0x75; d[i++] = 0x08;
- /* report count */
- d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1;
- /* output (data, variable, absolute) */
- d[i++] = 0x91; d[i++] = 0x00;
- }
- /* feature report */
- if (dev->feature_report_size) {
- /* usage (vendor defined) */
- d[i++] = 0x09; d[i++] = 0x03;
- /* logical minimum (0) */
- d[i++] = 0x15; d[i++] = 0x00;
- /* logical maximum (255) */
- d[i++] = 0x25; d[i++] = 0xFF;
- /* report size (8 bits) */
- d[i++] = 0x75; d[i++] = 0x08;
- /* report count */
- d[i++] = 0x95; d[i++] = (uint8_t)dev->feature_report_size - 1;
- /* feature (data, variable, absolute) */
- d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01;
- }
-
- /* end collection */
- d[i++] = 0xC0;
-
- if (*size > i)
- *size = i;
- memcpy(data, d, *size);
-
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_get_descriptor(struct hid_device_priv *dev, HANDLE hid_handle, int recipient,
- int type, int _index, void *data, size_t *size)
-{
- switch(type) {
- case LIBUSB_DT_DEVICE:
- usbi_dbg("LIBUSB_DT_DEVICE");
- return _hid_get_device_descriptor(dev, data, size);
- case LIBUSB_DT_CONFIG:
- usbi_dbg("LIBUSB_DT_CONFIG");
- if (!_index)
- return _hid_get_config_descriptor(dev, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_STRING:
- usbi_dbg("LIBUSB_DT_STRING");
- return _hid_get_string_descriptor(dev, _index, data, size);
- case LIBUSB_DT_HID:
- usbi_dbg("LIBUSB_DT_HID");
- if (!_index)
- return _hid_get_hid_descriptor(dev, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_REPORT:
- usbi_dbg("LIBUSB_DT_REPORT");
- if (!_index)
- return _hid_get_report_descriptor(dev, data, size);
- return LIBUSB_ERROR_INVALID_PARAM;
- case LIBUSB_DT_PHYSICAL:
- usbi_dbg("LIBUSB_DT_PHYSICAL");
- if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size))
- return LIBUSB_COMPLETED;
- return LIBUSB_ERROR_OTHER;
- }
-
- usbi_dbg("unsupported");
- return LIBUSB_ERROR_NOT_SUPPORTED;
-}
-
-static int _hid_get_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data,
- struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type)
-{
- uint8_t *buf;
- DWORD ioctl_code, read_size, expected_size = (DWORD)*size;
- int r = LIBUSB_SUCCESS;
-
- if (tp->hid_buffer != NULL)
- usbi_dbg("program assertion failed: hid_buffer is not NULL");
-
- if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
- usbi_dbg("invalid size (%u)", *size);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- switch (report_type) {
- case HID_REPORT_TYPE_INPUT:
- ioctl_code = IOCTL_HID_GET_INPUT_REPORT;
- break;
- case HID_REPORT_TYPE_FEATURE:
- ioctl_code = IOCTL_HID_GET_FEATURE;
- break;
- default:
- usbi_dbg("unknown HID report type %d", report_type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- // Add a trailing byte to detect overflows
- buf = calloc(1, expected_size + 1);
- if (buf == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- buf[0] = (uint8_t)id; // Must be set always
- usbi_dbg("report ID: 0x%02X", buf[0]);
-
- tp->hid_expected_size = expected_size;
- read_size = expected_size;
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1,
- buf, expected_size + 1, &read_size, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_dbg("Failed to Read HID Report: %s", windows_error_str(0));
- free(buf);
- return LIBUSB_ERROR_IO;
- }
- // Asynchronous wait
- tp->hid_buffer = buf;
- tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer
- return LIBUSB_SUCCESS;
- }
-
- // Transfer completed synchronously => copy and discard extra buffer
- if (read_size == 0) {
- usbi_warn(NULL, "program assertion failed - read completed synchronously, but no data was read");
- *size = 0;
- } else {
- if (buf[0] != id)
- usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
-
- if ((size_t)read_size > expected_size) {
- r = LIBUSB_ERROR_OVERFLOW;
- usbi_dbg("OVERFLOW!");
- } else {
- r = LIBUSB_COMPLETED;
- }
-
- *size = MIN((size_t)read_size, *size);
- if (id == 0)
- memcpy(data, buf + 1, *size); // Discard report ID
- else
- memcpy(data, buf, *size);
- }
-
- free(buf);
- return r;
-}
-
-static int _hid_set_report(struct hid_device_priv *dev, HANDLE hid_handle, int id, void *data,
- struct windows_transfer_priv *tp, size_t *size, OVERLAPPED *overlapped, int report_type)
-{
- uint8_t *buf = NULL;
- DWORD ioctl_code, write_size = (DWORD)*size;
-
- if (tp->hid_buffer != NULL)
- usbi_dbg("program assertion failed: hid_buffer is not NULL");
-
- if ((*size == 0) || (*size > MAX_HID_REPORT_SIZE)) {
- usbi_dbg("invalid size (%u)", *size);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- switch (report_type) {
- case HID_REPORT_TYPE_OUTPUT:
- ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT;
- break;
- case HID_REPORT_TYPE_FEATURE:
- ioctl_code = IOCTL_HID_SET_FEATURE;
- break;
- default:
- usbi_dbg("unknown HID report type %d", report_type);
- return LIBUSB_ERROR_INVALID_PARAM;
- }
-
- usbi_dbg("report ID: 0x%02X", id);
- // When report IDs are not used (i.e. when id == 0), we must add
- // a null report ID. Otherwise, we just use original data buffer
- if (id == 0)
- write_size++;
-
- buf = malloc(write_size);
- if (buf == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- if (id == 0) {
- buf[0] = 0;
- memcpy(buf + 1, data, *size);
- } else {
- // This seems like a waste, but if we don't duplicate the
- // data, we'll get issues when freeing hid_buffer
- memcpy(buf, data, *size);
- if (buf[0] != id)
- usbi_warn(NULL, "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
- }
-
- // NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
- if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size,
- buf, write_size, &write_size, overlapped)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_dbg("Failed to Write HID Output Report: %s", windows_error_str(0));
- free(buf);
- return LIBUSB_ERROR_IO;
- }
- tp->hid_buffer = buf;
- tp->hid_dest = NULL;
- return LIBUSB_SUCCESS;
- }
-
- // Transfer completed synchronously
- *size = write_size;
- if (write_size == 0)
- usbi_dbg("program assertion failed - write completed synchronously, but no data was written");
-
- free(buf);
- return LIBUSB_COMPLETED;
-}
-
-static int _hid_class_request(struct hid_device_priv *dev, HANDLE hid_handle, int request_type,
- int request, int value, int _index, void *data, struct windows_transfer_priv *tp,
- size_t *size, OVERLAPPED *overlapped)
-{
- int report_type = (value >> 8) & 0xFF;
- int report_id = value & 0xFF;
-
- if ((LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE)
- && (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE))
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT)
- return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
-
- if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT)
- return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
-
- return LIBUSB_ERROR_INVALID_PARAM;
-}
-
-
-/*
- * HID API functions
- */
-static int hid_init(int sub_api, struct libusb_context *ctx)
-{
- DLL_GET_HANDLE(hid);
- DLL_LOAD_FUNC(hid, HidD_GetAttributes, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetHidGuid, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, TRUE);
- DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetProductString, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, TRUE);
- DLL_LOAD_FUNC(hid, HidP_GetCaps, TRUE);
- DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, TRUE);
- DLL_LOAD_FUNC(hid, HidD_SetFeature, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetFeature, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, TRUE);
- DLL_LOAD_FUNC(hid, HidD_GetInputReport, FALSE);
- DLL_LOAD_FUNC(hid, HidD_SetOutputReport, FALSE);
- DLL_LOAD_FUNC(hid, HidD_FlushQueue, TRUE);
- DLL_LOAD_FUNC(hid, HidP_GetValueCaps, TRUE);
-
- api_hid_available = true;
- return LIBUSB_SUCCESS;
-}
-
-static int hid_exit(int sub_api)
-{
- DLL_FREE_HANDLE(hid);
-
- 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 hid_open(int sub_api, 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);
- HIDD_ATTRIBUTES hid_attributes;
- PHIDP_PREPARSED_DATA preparsed_data = NULL;
- HIDP_CAPS capabilities;
- HIDP_VALUE_CAPS *value_caps;
- HANDLE hid_handle = INVALID_HANDLE_VALUE;
- int i, j;
- // report IDs handling
- ULONG size[3];
- int nb_ids[2]; // zero and nonzero report IDs
-#if defined(ENABLE_LOGGING)
- const char *type[3] = {"input", "output", "feature"};
-#endif
-
- CHECK_HID_AVAILABLE;
-
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed - private HID structure is unitialized");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if ((priv->usb_interface[i].path != NULL)
- && (priv->usb_interface[i].apib->id == USB_API_HID)) {
- hid_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);
- /*
- * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
- * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
- * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not
- * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and
- * HidD_GetFeature (if the device supports Feature reports)."
- */
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
- hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not open device %s (interface %d): %s", priv->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;
- }
- }
- priv->usb_interface[i].restricted_functionality = true;
- }
- handle_priv->interface_handle[i].api_handle = hid_handle;
- }
- }
-
- hid_attributes.Size = sizeof(hid_attributes);
- do {
- if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
- usbi_err(ctx, "could not gain access to HID top collection (HidD_GetAttributes)");
- break;
- }
-
- priv->hid->vid = hid_attributes.VendorID;
- priv->hid->pid = hid_attributes.ProductID;
-
- // Set the maximum available input buffer size
- for (i = 32; HidD_SetNumInputBuffers(hid_handle, i); i *= 2);
- usbi_dbg("set maximum input buffer size to %d", i / 2);
-
- // Get the maximum input and output report size
- if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
- usbi_err(ctx, "could not read HID preparsed data (HidD_GetPreparsedData)");
- break;
- }
- if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
- usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)");
- break;
- }
-
- // Find out if interrupt will need report IDs
- size[0] = capabilities.NumberInputValueCaps;
- size[1] = capabilities.NumberOutputValueCaps;
- size[2] = capabilities.NumberFeatureValueCaps;
- for (j = HidP_Input; j <= HidP_Feature; j++) {
- usbi_dbg("%u HID %s report value(s) found", (unsigned int)size[j], type[j]);
- priv->hid->uses_report_ids[j] = false;
- if (size[j] > 0) {
- value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS));
- if ((value_caps != NULL)
- && (HidP_GetValueCaps((HIDP_REPORT_TYPE)j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS)
- && (size[j] >= 1)) {
- nb_ids[0] = 0;
- nb_ids[1] = 0;
- for (i = 0; i < (int)size[j]; i++) {
- usbi_dbg(" Report ID: 0x%02X", value_caps[i].ReportID);
- if (value_caps[i].ReportID != 0)
- nb_ids[1]++;
- else
- nb_ids[0]++;
- }
- if (nb_ids[1] != 0) {
- if (nb_ids[0] != 0)
- usbi_warn(ctx, "program assertion failed: zero and nonzero report IDs used for %s",
- type[j]);
- priv->hid->uses_report_ids[j] = true;
- }
- } else {
- usbi_warn(ctx, " could not process %s report IDs", type[j]);
- }
- free(value_caps);
- }
- }
-
- // Set the report sizes
- priv->hid->input_report_size = capabilities.InputReportByteLength;
- priv->hid->output_report_size = capabilities.OutputReportByteLength;
- priv->hid->feature_report_size = capabilities.FeatureReportByteLength;
-
- // Fetch string descriptors
- priv->hid->string_index[0] = priv->dev_descriptor.iManufacturer;
- if (priv->hid->string_index[0] != 0)
- HidD_GetManufacturerString(hid_handle, priv->hid->string[0], sizeof(priv->hid->string[0]));
- else
- priv->hid->string[0][0] = 0;
-
- priv->hid->string_index[1] = priv->dev_descriptor.iProduct;
- if (priv->hid->string_index[1] != 0)
- HidD_GetProductString(hid_handle, priv->hid->string[1], sizeof(priv->hid->string[1]));
- else
- priv->hid->string[1][0] = 0;
-
- priv->hid->string_index[2] = priv->dev_descriptor.iSerialNumber;
- if (priv->hid->string_index[2] != 0)
- HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], sizeof(priv->hid->string[2]));
- else
- priv->hid->string[2][0] = 0;
- } while(0);
-
- if (preparsed_data)
- HidD_FreePreparsedData(preparsed_data);
-
- return LIBUSB_SUCCESS;
-}
-
-static void hid_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- 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;
-
- if (!api_hid_available)
- return;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->usb_interface[i].apib->id == USB_API_HID) {
- file_handle = handle_priv->interface_handle[i].api_handle;
- if (HANDLE_VALID(file_handle))
- CloseHandle(file_handle);
- }
- }
-}
-
-static int hid_claim_interface(int sub_api, 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);
-
- CHECK_HID_AVAILABLE;
-
- // NB: Disconnection detection is not possible in this function
- if (priv->usb_interface[iface].path == NULL)
- return LIBUSB_ERROR_NOT_FOUND; // invalid iface
-
- // We use dev_handle as a flag for interface claimed
- if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED)
- return LIBUSB_ERROR_BUSY; // already claimed
-
-
- handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED;
-
- usbi_dbg("claimed interface %d", iface);
- handle_priv->active_interface = iface;
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_release_interface(int sub_api, 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);
-
- CHECK_HID_AVAILABLE;
-
- if (priv->usb_interface[iface].path == NULL)
- return LIBUSB_ERROR_NOT_FOUND; // invalid iface
-
- if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED)
- return LIBUSB_ERROR_NOT_FOUND; // invalid iface
-
- handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE;
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting)
-{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
-
- CHECK_HID_AVAILABLE;
-
- if (altsetting > 255)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- if (altsetting != 0) {
- usbi_err(ctx, "set interface altsetting not supported for altsetting >0");
- return LIBUSB_ERROR_NOT_SUPPORTED;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_submit_control_transfer(int sub_api, 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_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- struct windows_device_priv *priv = _device_priv(transfer->dev_handle->dev);
- struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- HANDLE hid_handle;
- struct winfd wfd;
- int current_interface, config;
- size_t size;
- int r = LIBUSB_ERROR_INVALID_PARAM;
-
- CHECK_HID_AVAILABLE;
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- safe_free(transfer_priv->hid_buffer);
- transfer_priv->hid_dest = NULL;
- size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
-
- if (size > MAX_CTRL_BUFFER_LENGTH)
- return LIBUSB_ERROR_INVALID_PARAM;
-
- current_interface = get_valid_interface(transfer->dev_handle, USB_API_HID);
- if (current_interface < 0) {
- if (auto_claim(transfer, &current_interface, USB_API_HID) != LIBUSB_SUCCESS)
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_dbg("will use interface %d", current_interface);
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- wfd = usbi_create_fd(hid_handle, RW_READ, NULL, NULL);
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NOT_FOUND;
-
- switch(LIBUSB_REQ_TYPE(setup->request_type)) {
- case LIBUSB_REQUEST_TYPE_STANDARD:
- switch(setup->request) {
- case LIBUSB_REQUEST_GET_DESCRIPTOR:
- r = _hid_get_descriptor(priv->hid, wfd.handle, LIBUSB_REQ_RECIPIENT(setup->request_type),
- (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
- break;
- case LIBUSB_REQUEST_GET_CONFIGURATION:
- r = windows_get_configuration(transfer->dev_handle, &config);
- if (r == LIBUSB_SUCCESS) {
- size = 1;
- ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = (uint8_t)config;
- r = LIBUSB_COMPLETED;
- }
- break;
- case LIBUSB_REQUEST_SET_CONFIGURATION:
- if (setup->value == priv->active_config) {
- r = LIBUSB_COMPLETED;
- } else {
- usbi_warn(ctx, "cannot set configuration other than the default one");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- }
- break;
- case LIBUSB_REQUEST_GET_INTERFACE:
- size = 1;
- ((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0;
- r = LIBUSB_COMPLETED;
- break;
- case LIBUSB_REQUEST_SET_INTERFACE:
- r = hid_set_interface_altsetting(0, transfer->dev_handle, setup->index, setup->value);
- if (r == LIBUSB_SUCCESS)
- r = LIBUSB_COMPLETED;
- break;
- default:
- usbi_warn(ctx, "unsupported HID control request");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
- break;
- case LIBUSB_REQUEST_TYPE_CLASS:
- r = _hid_class_request(priv->hid, wfd.handle, setup->request_type, setup->request, setup->value,
- setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
- &size, wfd.overlapped);
- break;
- default:
- usbi_warn(ctx, "unsupported HID control request");
- r = LIBUSB_ERROR_NOT_SUPPORTED;
- break;
- }
-
- if (r == LIBUSB_COMPLETED) {
- // Force request to be completed synchronously. Transferred size has been set by previous call
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx
- // set InternalHigh to the number of bytes transferred
- wfd.overlapped->InternalHigh = (DWORD)size;
- r = LIBUSB_SUCCESS;
- }
-
- if (r == LIBUSB_SUCCESS) {
- // Use priv_transfer to store data needed for async polling
- transfer_priv->pollable_fd = wfd;
- transfer_priv->interface_number = (uint8_t)current_interface;
- } else {
- usbi_free_fd(&wfd);
- }
-
- return r;
-}
-
-static int hid_submit_bulk_transfer(int sub_api, 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 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);
- struct winfd wfd;
- HANDLE hid_handle;
- bool direction_in, ret;
- int current_interface, length;
- DWORD size;
- int r = LIBUSB_SUCCESS;
-
- CHECK_HID_AVAILABLE;
-
- transfer_priv->pollable_fd = INVALID_WINFD;
- transfer_priv->hid_dest = NULL;
- safe_free(transfer_priv->hid_buffer);
-
- 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);
-
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
-
- wfd = usbi_create_fd(hid_handle, direction_in?RW_READ:RW_WRITE, NULL, NULL);
- // Always use the handle returned from usbi_create_fd (wfd.handle)
- if (wfd.fd < 0)
- return LIBUSB_ERROR_NO_MEM;
-
- // If report IDs are not in use, an extra prefix byte must be added
- if (((direction_in) && (!priv->hid->uses_report_ids[0]))
- || ((!direction_in) && (!priv->hid->uses_report_ids[1])))
- length = transfer->length + 1;
- else
- length = transfer->length;
-
- // Add a trailing byte to detect overflows on input
- transfer_priv->hid_buffer = calloc(1, length + 1);
- if (transfer_priv->hid_buffer == NULL)
- return LIBUSB_ERROR_NO_MEM;
-
- transfer_priv->hid_expected_size = length;
-
- if (direction_in) {
- transfer_priv->hid_dest = transfer->buffer;
- usbi_dbg("reading %d bytes (report ID: 0x00)", length);
- ret = ReadFile(wfd.handle, transfer_priv->hid_buffer, length + 1, &size, wfd.overlapped);
- } else {
- if (!priv->hid->uses_report_ids[1])
- memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length);
- else
- // We could actually do without the calloc and memcpy in this case
- memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length);
-
- usbi_dbg("writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
- ret = WriteFile(wfd.handle, transfer_priv->hid_buffer, length, &size, wfd.overlapped);
- }
-
- if (!ret) {
- if (GetLastError() != ERROR_IO_PENDING) {
- usbi_err(ctx, "HID transfer failed: %s", windows_error_str(0));
- usbi_free_fd(&wfd);
- safe_free(transfer_priv->hid_buffer);
- return LIBUSB_ERROR_IO;
- }
- } else {
- // Only write operations that completed synchronously need to free up
- // hid_buffer. For reads, copy_transfer_data() handles that process.
- if (!direction_in)
- safe_free(transfer_priv->hid_buffer);
-
- if (size == 0) {
- usbi_err(ctx, "program assertion failed - no data was transferred");
- size = 1;
- }
- if (size > (size_t)length) {
- usbi_err(ctx, "OVERFLOW!");
- r = LIBUSB_ERROR_OVERFLOW;
- }
- wfd.overlapped->Internal = STATUS_COMPLETED_SYNCHRONOUSLY;
- wfd.overlapped->InternalHigh = size;
- }
-
- transfer_priv->pollable_fd = wfd;
- transfer_priv->interface_number = (uint8_t)current_interface;
-
- return r;
-}
-
-static int hid_abort_transfers(int sub_api, 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_handle_priv *handle_priv = _device_handle_priv(transfer->dev_handle);
- HANDLE hid_handle;
- int current_interface;
-
- CHECK_HID_AVAILABLE;
-
- current_interface = transfer_priv->interface_number;
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- CancelIo(hid_handle);
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_handle_priv *handle_priv = _device_handle_priv(dev_handle);
- HANDLE hid_handle;
- int current_interface;
-
- CHECK_HID_AVAILABLE;
-
- // Flushing the queues on all interfaces is the best we can achieve
- for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
- if (HANDLE_VALID(hid_handle))
- HidD_FlushQueue(hid_handle);
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int hid_clear_halt(int sub_api, 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 hid_handle;
- int current_interface;
-
- CHECK_HID_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);
- hid_handle = handle_priv->interface_handle[current_interface].api_handle;
-
- // No endpoint selection with Microsoft's implementation, so we try to flush the
- // whole interface. Should be OK for most case scenarios
- if (!HidD_FlushQueue(hid_handle)) {
- usbi_err(ctx, "Flushing of HID queue failed: %s", windows_error_str(0));
- // Device was probably disconnected
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- return LIBUSB_SUCCESS;
-}
-
-// This extra function is only needed for HID
-static int hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, uint32_t io_size)
-{
- 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 = usbi_transfer_get_os_priv(itransfer);
- int r = LIBUSB_TRANSFER_COMPLETED;
- uint32_t corrected_size = io_size;
-
- if (transfer_priv->hid_buffer != NULL) {
- // If we have a valid hid_buffer, it means the transfer was async
- if (transfer_priv->hid_dest != NULL) { // Data readout
- if (corrected_size > 0) {
- // First, check for overflow
- if (corrected_size > transfer_priv->hid_expected_size) {
- usbi_err(ctx, "OVERFLOW!");
- corrected_size = (uint32_t)transfer_priv->hid_expected_size;
- r = LIBUSB_TRANSFER_OVERFLOW;
- }
-
- if (transfer_priv->hid_buffer[0] == 0) {
- // Discard the 1 byte report ID prefix
- corrected_size--;
- memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, corrected_size);
- } else {
- memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, corrected_size);
- }
- }
- transfer_priv->hid_dest = NULL;
- }
- // For write, we just need to free the hid buffer
- safe_free(transfer_priv->hid_buffer);
- }
-
- itransfer->transferred += corrected_size;
- return r;
-}
-
-
-/*
- * Composite API functions
- */
-static int composite_init(int sub_api, struct libusb_context *ctx)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int composite_exit(int sub_api)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int composite_open(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int r = LIBUSB_ERROR_NOT_FOUND;
- uint8_t i;
- // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
- bool available[SUB_API_MAX + 1] = { 0 };
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- switch (priv->usb_interface[i].apib->id) {
- case USB_API_WINUSBX:
- if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
- available[priv->usb_interface[i].sub_api] = true;
- break;
- case USB_API_HID:
- available[SUB_API_MAX] = true;
- break;
- default:
- break;
- }
- }
-
- for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
- if (available[i]) {
- r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
- }
- }
-
- if (available[SUB_API_MAX]) // HID driver
- r = hid_open(SUB_API_NOTSET, dev_handle);
-
- return r;
-}
-
-static void composite_close(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- uint8_t i;
- // SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
- bool available[SUB_API_MAX + 1] = { 0 };
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- switch (priv->usb_interface[i].apib->id) {
- case USB_API_WINUSBX:
- if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
- available[priv->usb_interface[i].sub_api] = true;
- break;
- case USB_API_HID:
- available[SUB_API_MAX] = true;
- break;
- default:
- break;
- }
- }
-
- for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
- if (available[i])
- usb_api_backend[USB_API_WINUSBX].close(i, dev_handle);
- }
-
- if (available[SUB_API_MAX]) // HID driver
- hid_close(SUB_API_NOTSET, dev_handle);
-}
-
-static int composite_claim_interface(int sub_api, 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(priv->usb_interface[iface].sub_api, dev_handle, iface);
-}
-
-static int composite_set_interface_altsetting(int sub_api, 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(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting);
-}
-
-static int composite_release_interface(int sub_api, 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(priv->usb_interface[iface].sub_api, dev_handle, iface);
-}
-
-static int composite_submit_control_transfer(int sub_api, 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 libusb_config_descriptor *conf_desc;
- WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
- int iface, pass, r;
-
- // Interface shouldn't matter for control, but it does in practice, with Windows'
- // restrictions with regards to accessing HID keyboards and mice. Try to target
- // a specific interface first, if possible.
- switch (LIBUSB_REQ_RECIPIENT(setup->request_type)) {
- case LIBUSB_RECIPIENT_INTERFACE:
- iface = setup->index & 0xFF;
- break;
- case LIBUSB_RECIPIENT_ENDPOINT:
- r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc);
- if (r == LIBUSB_SUCCESS) {
- iface = get_interface_by_endpoint(conf_desc, (setup->index & 0xFF));
- libusb_free_config_descriptor(conf_desc);
- break;
- }
- // Fall through if not able to determine interface
- default:
- iface = -1;
- break;
- }
-
- // Try and target a specific interface if the control setup indicates such
- if ((iface >= 0) && (iface < USB_MAXINTERFACES)) {
- usbi_dbg("attempting control transfer targeted to interface %d", iface);
- if (priv->usb_interface[iface].path != NULL) {
- r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
- if (r == LIBUSB_SUCCESS)
- return r;
- }
- }
-
- // Either not targeted to a specific interface or no luck in doing so.
- // Try a 2 pass approach with all interfaces.
- for (pass = 0; pass < 2; pass++) {
- for (iface = 0; iface < USB_MAXINTERFACES; iface++) {
- if (priv->usb_interface[iface].path != NULL) {
- if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) {
- usbi_dbg("trying to skip restricted interface #%d (HID keyboard or mouse?)", iface);
- continue;
- }
- usbi_dbg("using interface %d", iface);
- r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
- // If not supported on this API, it may be supported on another, so don't give up yet!!
- if (r == LIBUSB_ERROR_NOT_SUPPORTED)
- continue;
- return r;
- }
- }
- }
-
- usbi_err(ctx, "no libusb supported interfaces to complete request");
- return LIBUSB_ERROR_NOT_FOUND;
-}
-
-static int composite_submit_bulk_transfer(int sub_api, 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(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_submit_iso_transfer(int sub_api, 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(priv->usb_interface[current_interface].sub_api, itransfer);
-}
-
-static int composite_clear_halt(int sub_api, 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(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
-}
-
-static int composite_abort_control(int sub_api, 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(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer);
-}
-
-static int composite_abort_transfers(int sub_api, 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(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer);
-}
-
-static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
-{
- struct windows_device_priv *priv = _device_priv(dev_handle->dev);
- int r;
- uint8_t i;
- bool available[SUB_API_MAX];
-
- for (i = 0; i < SUB_API_MAX; i++)
- available[i] = false;
-
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX)
- && (priv->usb_interface[i].sub_api != SUB_API_NOTSET))
- available[priv->usb_interface[i].sub_api] = true;
- }
-
- for (i = 0; i < SUB_API_MAX; i++) {
- if (available[i]) {
- r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
- }
- }
-
- return LIBUSB_SUCCESS;
-}
-
-static int composite_copy_transfer_data(int sub_api, 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(priv->usb_interface[transfer_priv->interface_number].sub_api, itransfer, io_size);
-}
-
-#endif /* !USE_USBDK */
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h b/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h
deleted file mode 100644
index b7b9cd9..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/os/windows_winusb.h
+++ /dev/null
@@ -1,937 +0,0 @@
-/*
- * Windows backend for libusb 1.0
- * Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
- * 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
-
-#include "windows_common.h"
-#include "windows_nt_common.h"
-
-#if defined(_MSC_VER)
-// disable /W4 MSVC warnings that are benign
-#pragma warning(disable:4100) // unreferenced formal parameter
-#pragma warning(disable:4127) // conditional expression is constant
-#pragma warning(disable:4201) // nameless struct/union
-#pragma warning(disable:4214) // bit field types other than int
-#pragma warning(disable:4996) // deprecated API calls
-#pragma warning(disable:28159) // more deprecated API calls
-#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
-
-#define MAX_CTRL_BUFFER_LENGTH 4096
-#define MAX_USB_DEVICES 256
-#define MAX_USB_STRING_LENGTH 128
-#define MAX_HID_REPORT_SIZE 1024
-#define MAX_HID_DESCRIPTOR_SIZE 256
-#define MAX_GUID_STRING_LENGTH 40
-#define MAX_PATH_LENGTH 128
-#define MAX_KEY_LENGTH 256
-#define LIST_SEPARATOR ';'
-
-// Handle code for HID interface that have been claimed ("dibs")
-#define INTERFACE_CLAIMED ((HANDLE)(intptr_t)0xD1B5)
-// Additional return code for HID operations that completed synchronously
-#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1)
-
-// 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
-#if !defined(GUID_DEVINTERFACE_LIBUSB0_FILTER)
-const GUID GUID_DEVINTERFACE_LIBUSB0_FILTER = { 0xF9F3FF14, 0xAE21, 0x48A0, {0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9} };
-#endif
-
-
-/*
- * Multiple USB API backend support
- */
-#define USB_API_UNSUPPORTED 0
-#define USB_API_HUB 1
-#define USB_API_COMPOSITE 2
-#define USB_API_WINUSBX 3
-#define USB_API_HID 4
-#define USB_API_MAX 5
-// The following is used to indicate if the HID or composite extra props have already been set.
-#define USB_API_SET (1 << USB_API_MAX)
-
-// Sub-APIs for WinUSB-like driver APIs (WinUSB, libusbK, libusb-win32 through the libusbK DLL)
-// Must have the same values as the KUSB_DRVID enum from libusbk.h
-#define SUB_API_NOTSET -1
-#define SUB_API_LIBUSBK 0
-#define SUB_API_LIBUSB0 1
-#define SUB_API_WINUSB 2
-#define SUB_API_MAX 3
-
-#define WINUSBX_DRV_NAMES {"libusbK", "libusb0", "WinUSB"}
-
-struct windows_usb_api_backend {
- const uint8_t id;
- const char *designation;
- const char **driver_name_list; // Driver name, without .sys, e.g. "usbccgp"
- const uint8_t nb_driver_names;
- int (*init)(int sub_api, struct libusb_context *ctx);
- int (*exit)(int sub_api);
- int (*open)(int sub_api, struct libusb_device_handle *dev_handle);
- void (*close)(int sub_api, struct libusb_device_handle *dev_handle);
- int (*configure_endpoints)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
- int (*claim_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
- int (*set_interface_altsetting)(int sub_api, struct libusb_device_handle *dev_handle, int iface, int altsetting);
- int (*release_interface)(int sub_api, struct libusb_device_handle *dev_handle, int iface);
- int (*clear_halt)(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
- int (*reset_device)(int sub_api, struct libusb_device_handle *dev_handle);
- int (*submit_bulk_transfer)(int sub_api, struct usbi_transfer *itransfer);
- int (*submit_iso_transfer)(int sub_api, struct usbi_transfer *itransfer);
- int (*submit_control_transfer)(int sub_api, struct usbi_transfer *itransfer);
- int (*abort_control)(int sub_api, struct usbi_transfer *itransfer);
- int (*abort_transfers)(int sub_api, struct usbi_transfer *itransfer);
- int (*copy_transfer_data)(int sub_api, 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
- */
-
-// TODO (v2+): move hid desc to libusb.h?
-struct libusb_hid_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint16_t bcdHID;
- uint8_t bCountryCode;
- uint8_t bNumDescriptors;
- uint8_t bClassDescriptorType;
- uint16_t wClassDescriptorLength;
-};
-
-#define LIBUSB_DT_HID_SIZE 9
-#define HID_MAX_CONFIG_DESC_SIZE (LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE \
- + LIBUSB_DT_HID_SIZE + 2 * LIBUSB_DT_ENDPOINT_SIZE)
-#define HID_MAX_REPORT_SIZE 1024
-#define HID_IN_EP 0x81
-#define HID_OUT_EP 0x02
-#define LIBUSB_REQ_RECIPIENT(request_type) ((request_type) & 0x1F)
-#define LIBUSB_REQ_TYPE(request_type) ((request_type) & (0x03 << 5))
-#define LIBUSB_REQ_IN(request_type) ((request_type) & LIBUSB_ENDPOINT_IN)
-#define LIBUSB_REQ_OUT(request_type) (!LIBUSB_REQ_IN(request_type))
-
-// The following are used for HID reports IOCTLs
-#define HID_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_NEITHER, FILE_ANY_ACCESS)
-#define HID_BUFFER_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define HID_IN_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_IN_DIRECT, FILE_ANY_ACCESS)
-#define HID_OUT_CTL_CODE(id) \
- CTL_CODE (FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
-
-#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
-#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
-#define IOCTL_HID_SET_FEATURE HID_IN_CTL_CODE(100)
-#define IOCTL_HID_SET_OUTPUT_REPORT HID_IN_CTL_CODE(101)
-
-enum libusb_hid_request_type {
- HID_REQ_GET_REPORT = 0x01,
- HID_REQ_GET_IDLE = 0x02,
- HID_REQ_GET_PROTOCOL = 0x03,
- HID_REQ_SET_REPORT = 0x09,
- HID_REQ_SET_IDLE = 0x0A,
- HID_REQ_SET_PROTOCOL = 0x0B
-};
-
-enum libusb_hid_report_type {
- HID_REPORT_TYPE_INPUT = 0x01,
- HID_REPORT_TYPE_OUTPUT = 0x02,
- HID_REPORT_TYPE_FEATURE = 0x03
-};
-
-struct hid_device_priv {
- uint16_t vid;
- uint16_t pid;
- uint8_t config;
- uint8_t nb_interfaces;
- bool uses_report_ids[3]; // input, ouptput, feature
- uint16_t input_report_size;
- uint16_t output_report_size;
- uint16_t feature_report_size;
- WCHAR string[3][MAX_USB_STRING_LENGTH];
- uint8_t string_index[3]; // man, prod, ser
-};
-
-struct windows_device_priv {
- uint8_t depth; // distance to HCD
- uint8_t port; // port number on the hub
- uint8_t active_config;
- struct windows_usb_api_backend const *apib;
- char *path; // device interface path
- int sub_api; // for WinUSB-like APIs
- struct {
- char *path; // each interface needs a device interface path,
- struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
- int sub_api;
- int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
- uint8_t *endpoint;
- bool restricted_functionality; // indicates if the interface functionality is restricted
- // by Windows (eg. HID keyboards or mice cannot do R/W)
- } usb_interface[USB_MAXINTERFACES];
- struct hid_device_priv *hid;
- 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 struct windows_device_priv *windows_device_priv_init(struct libusb_device *dev)
-{
- struct windows_device_priv *p = _device_priv(dev);
- int i;
-
- p->apib = &usb_api_backend[USB_API_UNSUPPORTED];
- p->sub_api = SUB_API_NOTSET;
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- p->usb_interface[i].apib = &usb_api_backend[USB_API_UNSUPPORTED];
- p->usb_interface[i].sub_api = SUB_API_NOTSET;
- }
-
- return p;
-}
-
-static inline void windows_device_priv_release(struct libusb_device *dev)
-{
- struct windows_device_priv *p = _device_priv(dev);
- int i;
-
- free(p->path);
- if ((dev->num_configurations > 0) && (p->config_descriptor != NULL)) {
- for (i = 0; i < dev->num_configurations; i++)
- free(p->config_descriptor[i]);
- }
- free(p->config_descriptor);
- free(p->hid);
- for (i = 0; i < USB_MAXINTERFACES; i++) {
- free(p->usb_interface[i].path);
- 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];
- int autoclaim_count[USB_MAXINTERFACES]; // For auto-release
-};
-
-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;
- uint8_t *hid_buffer; // 1 byte extended data buffer, required for HID
- uint8_t *hid_dest; // transfer buffer destination, required for HID
- size_t hid_expected_size;
-};
-
-// 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 retrieve list
- const char* designation; // internal designation (for debug output)
-};
-
-/* OLE32 dependency */
-DLL_DECLARE_HANDLE(OLE32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HRESULT, p, CLSIDFromString, (LPCOLESTR, LPCLSID));
-
-/* Kernel32 dependencies */
-DLL_DECLARE_HANDLE(Kernel32);
-/* This call is only available from XP SP2 */
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, IsWow64Process, (HANDLE, PBOOL));
-
-/* SetupAPI dependencies */
-DLL_DECLARE_HANDLE(SetupAPI);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (const GUID*, PCSTR, HWND, DWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInfo, (HDEVINFO, DWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiEnumDeviceInterfaces, (HDEVINFO, PSP_DEVINFO_DATA,
- const GUID*, DWORD, PSP_DEVICE_INTERFACE_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceInterfaceDetailA, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA,
- PSP_DEVICE_INTERFACE_DETAIL_DATA_A, DWORD, PDWORD, PSP_DEVINFO_DATA));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiDestroyDeviceInfoList, (HDEVINFO));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDevRegKey, (HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, BOOL, p, SetupDiGetDeviceRegistryPropertyA, (HDEVINFO,
- PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD));
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, HKEY, p, SetupDiOpenDeviceInterfaceRegKey, (HDEVINFO, PSP_DEVICE_INTERFACE_DATA, DWORD, DWORD));
-
-/* AdvAPI32 dependencies */
-DLL_DECLARE_HANDLE(AdvAPI32);
-DLL_DECLARE_FUNC_PREFIXED(WINAPI, LONG, p, RegQueryValueExW, (HKEY, LPCWSTR, LPDWORD, LPDWORD, LPBYTE, LPDWORD));
-DLL_DECLARE_FUNC_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
-#if !defined(USB_GET_NODE_CONNECTION_INFORMATION_EX_V2)
-#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279
-#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_HANDLE(Cfgmgr32);
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Parent, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Child, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(WINAPI, CONFIGRET, CM_Get_Sibling, (PDEVINST, DEVINST, ULONG));
-DLL_DECLARE_FUNC(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_INFORMATION_EX_V2 \
- CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, 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_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 union _USB_PROTOCOLS {
- ULONG ul;
- struct {
- ULONG Usb110:1;
- ULONG Usb200:1;
- ULONG Usb300:1;
- ULONG ReservedMBZ:29;
- };
-} USB_PROTOCOLS, *PUSB_PROTOCOLS;
-
-typedef union _USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS {
- ULONG ul;
- struct {
- ULONG DeviceIsOperatingAtSuperSpeedOrHigher:1;
- ULONG DeviceIsSuperSpeedCapableOrHigher:1;
- ULONG ReservedMBZ:30;
- };
-} USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS;
-
-typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
- ULONG ConnectionIndex;
- ULONG Length;
- USB_PROTOCOLS SupportedUsbProtocols;
- USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags;
-} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2;
-
-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;
-
-typedef BOOL (WINAPI *WinUsb_AbortPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID
-);
-typedef BOOL (WINAPI *WinUsb_ControlTransfer_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- WINUSB_SETUP_PACKET SetupPacket,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_FlushPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID
-);
-typedef BOOL (WINAPI *WinUsb_Free_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle
-);
-typedef BOOL (WINAPI *WinUsb_GetAssociatedInterface_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AssociatedInterfaceIndex,
- PWINUSB_INTERFACE_HANDLE AssociatedInterfaceHandle
-);
-typedef BOOL (WINAPI *WinUsb_GetCurrentAlternateSetting_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- PUCHAR AlternateSetting
-);
-typedef BOOL (WINAPI *WinUsb_GetDescriptor_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR DescriptorType,
- UCHAR Index,
- USHORT LanguageID,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred
-);
-typedef BOOL (WINAPI *WinUsb_GetOverlappedResult_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- LPOVERLAPPED lpOverlapped,
- LPDWORD lpNumberOfBytesTransferred,
- BOOL bWait
-);
-typedef BOOL (WINAPI *WinUsb_GetPipePolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- ULONG PolicyType,
- PULONG ValueLength,
- PVOID Value
-);
-typedef BOOL (WINAPI *WinUsb_GetPowerPolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- ULONG PolicyType,
- PULONG ValueLength,
- PVOID Value
-);
-typedef BOOL (WINAPI *WinUsb_Initialize_t)(
- HANDLE DeviceHandle,
- PWINUSB_INTERFACE_HANDLE InterfaceHandle
-);
-typedef BOOL (WINAPI *WinUsb_QueryDeviceInformation_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- ULONG InformationType,
- PULONG BufferLength,
- PVOID Buffer
-);
-typedef BOOL (WINAPI *WinUsb_QueryInterfaceSettings_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateSettingNumber,
- PUSB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor
-);
-typedef BOOL (WINAPI *WinUsb_QueryPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateInterfaceNumber,
- UCHAR PipeIndex,
- PWINUSB_PIPE_INFORMATION PipeInformation
-);
-typedef BOOL (WINAPI *WinUsb_ReadPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_ResetPipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID
-);
-typedef BOOL (WINAPI *WinUsb_SetCurrentAlternateSetting_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR AlternateSetting
-);
-typedef BOOL (WINAPI *WinUsb_SetPipePolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- ULONG PolicyType,
- ULONG ValueLength,
- PVOID Value
-);
-typedef BOOL (WINAPI *WinUsb_SetPowerPolicy_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- ULONG PolicyType,
- ULONG ValueLength,
- PVOID Value
-);
-typedef BOOL (WINAPI *WinUsb_WritePipe_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle,
- UCHAR PipeID,
- PUCHAR Buffer,
- ULONG BufferLength,
- PULONG LengthTransferred,
- LPOVERLAPPED Overlapped
-);
-typedef BOOL (WINAPI *WinUsb_ResetDevice_t)(
- WINUSB_INTERFACE_HANDLE InterfaceHandle
-);
-
-/* /!\ These must match the ones from the official libusbk.h */
-typedef enum _KUSB_FNID {
- KUSB_FNID_Init,
- KUSB_FNID_Free,
- KUSB_FNID_ClaimInterface,
- KUSB_FNID_ReleaseInterface,
- KUSB_FNID_SetAltInterface,
- KUSB_FNID_GetAltInterface,
- KUSB_FNID_GetDescriptor,
- KUSB_FNID_ControlTransfer,
- KUSB_FNID_SetPowerPolicy,
- KUSB_FNID_GetPowerPolicy,
- KUSB_FNID_SetConfiguration,
- KUSB_FNID_GetConfiguration,
- KUSB_FNID_ResetDevice,
- KUSB_FNID_Initialize,
- KUSB_FNID_SelectInterface,
- KUSB_FNID_GetAssociatedInterface,
- KUSB_FNID_Clone,
- KUSB_FNID_QueryInterfaceSettings,
- KUSB_FNID_QueryDeviceInformation,
- KUSB_FNID_SetCurrentAlternateSetting,
- KUSB_FNID_GetCurrentAlternateSetting,
- KUSB_FNID_QueryPipe,
- KUSB_FNID_SetPipePolicy,
- KUSB_FNID_GetPipePolicy,
- KUSB_FNID_ReadPipe,
- KUSB_FNID_WritePipe,
- KUSB_FNID_ResetPipe,
- KUSB_FNID_AbortPipe,
- KUSB_FNID_FlushPipe,
- KUSB_FNID_IsoReadPipe,
- KUSB_FNID_IsoWritePipe,
- KUSB_FNID_GetCurrentFrameNumber,
- KUSB_FNID_GetOverlappedResult,
- KUSB_FNID_GetProperty,
- KUSB_FNID_COUNT,
-} KUSB_FNID;
-
-typedef struct _KLIB_VERSION {
- INT Major;
- INT Minor;
- INT Micro;
- INT Nano;
-} KLIB_VERSION;
-typedef KLIB_VERSION* PKLIB_VERSION;
-
-typedef BOOL (WINAPI *LibK_GetProcAddress_t)(
- PVOID *ProcAddress,
- ULONG DriverID,
- ULONG FunctionID
-);
-
-typedef VOID (WINAPI *LibK_GetVersion_t)(
- PKLIB_VERSION Version
-);
-
-struct winusb_interface {
- bool initialized;
- WinUsb_AbortPipe_t AbortPipe;
- WinUsb_ControlTransfer_t ControlTransfer;
- WinUsb_FlushPipe_t FlushPipe;
- WinUsb_Free_t Free;
- WinUsb_GetAssociatedInterface_t GetAssociatedInterface;
- WinUsb_GetCurrentAlternateSetting_t GetCurrentAlternateSetting;
- WinUsb_GetDescriptor_t GetDescriptor;
- WinUsb_GetOverlappedResult_t GetOverlappedResult;
- WinUsb_GetPipePolicy_t GetPipePolicy;
- WinUsb_GetPowerPolicy_t GetPowerPolicy;
- WinUsb_Initialize_t Initialize;
- WinUsb_QueryDeviceInformation_t QueryDeviceInformation;
- WinUsb_QueryInterfaceSettings_t QueryInterfaceSettings;
- WinUsb_QueryPipe_t QueryPipe;
- WinUsb_ReadPipe_t ReadPipe;
- WinUsb_ResetPipe_t ResetPipe;
- WinUsb_SetCurrentAlternateSetting_t SetCurrentAlternateSetting;
- WinUsb_SetPipePolicy_t SetPipePolicy;
- WinUsb_SetPowerPolicy_t SetPowerPolicy;
- WinUsb_WritePipe_t WritePipe;
- WinUsb_ResetDevice_t ResetDevice;
-};
-
-/* hid.dll interface */
-
-#define HIDP_STATUS_SUCCESS 0x110000
-typedef void * PHIDP_PREPARSED_DATA;
-
-#pragma pack(1)
-typedef struct {
- ULONG Size;
- USHORT VendorID;
- USHORT ProductID;
- USHORT VersionNumber;
-} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
-#pragma pack()
-
-typedef USHORT USAGE;
-typedef struct {
- USAGE Usage;
- USAGE UsagePage;
- USHORT InputReportByteLength;
- USHORT OutputReportByteLength;
- USHORT FeatureReportByteLength;
- USHORT Reserved[17];
- USHORT NumberLinkCollectionNodes;
- USHORT NumberInputButtonCaps;
- USHORT NumberInputValueCaps;
- USHORT NumberInputDataIndices;
- USHORT NumberOutputButtonCaps;
- USHORT NumberOutputValueCaps;
- USHORT NumberOutputDataIndices;
- USHORT NumberFeatureButtonCaps;
- USHORT NumberFeatureValueCaps;
- USHORT NumberFeatureDataIndices;
-} HIDP_CAPS, *PHIDP_CAPS;
-
-typedef enum _HIDP_REPORT_TYPE {
- HidP_Input,
- HidP_Output,
- HidP_Feature
-} HIDP_REPORT_TYPE;
-
-typedef struct _HIDP_VALUE_CAPS {
- USAGE UsagePage;
- UCHAR ReportID;
- BOOLEAN IsAlias;
- USHORT BitField;
- USHORT LinkCollection;
- USAGE LinkUsage;
- USAGE LinkUsagePage;
- BOOLEAN IsRange;
- BOOLEAN IsStringRange;
- BOOLEAN IsDesignatorRange;
- BOOLEAN IsAbsolute;
- BOOLEAN HasNull;
- UCHAR Reserved;
- USHORT BitSize;
- USHORT ReportCount;
- USHORT Reserved2[5];
- ULONG UnitsExp;
- ULONG Units;
- LONG LogicalMin, LogicalMax;
- LONG PhysicalMin, PhysicalMax;
- union {
- struct {
- USAGE UsageMin, UsageMax;
- USHORT StringMin, StringMax;
- USHORT DesignatorMin, DesignatorMax;
- USHORT DataIndexMin, DataIndexMax;
- } Range;
- struct {
- USAGE Usage, Reserved1;
- USHORT StringIndex, Reserved2;
- USHORT DesignatorIndex, Reserved3;
- USHORT DataIndex, Reserved4;
- } NotRange;
- } u;
-} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
-
-DLL_DECLARE_HANDLE(hid);
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
-DLL_DECLARE_FUNC(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, LONG, HidP_GetCaps, (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidD_FlushQueue, (HANDLE));
-DLL_DECLARE_FUNC(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); \ No newline at end of file
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/strerror.c b/vendor/github.com/karalabe/hid/libusb/libusb/strerror.c
deleted file mode 100644
index d2be0e2..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/strerror.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * libusb strerror code
- * Copyright © 2013 Hans de Goede <hdegoede@redhat.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 <locale.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(HAVE_STRINGS_H)
-#include <strings.h>
-#endif
-
-#include "libusbi.h"
-
-#if defined(_MSC_VER)
-#define strncasecmp _strnicmp
-#endif
-
-static size_t usbi_locale = 0;
-
-/** \ingroup libusb_misc
- * How to add a new \ref libusb_strerror() translation:
- * <ol>
- * <li> Download the latest \c strerror.c from:<br>
- * https://raw.github.com/libusb/libusb/master/libusb/sterror.c </li>
- * <li> Open the file in an UTF-8 capable editor </li>
- * <li> Add the 2 letter <a href="http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">ISO 639-1</a>
- * code for your locale at the end of \c usbi_locale_supported[]<br>
- * Eg. for Chinese, you would add "zh" so that:
- * \code... usbi_locale_supported[] = { "en", "nl", "fr" };\endcode
- * becomes:
- * \code... usbi_locale_supported[] = { "en", "nl", "fr", "zh" };\endcode </li>
- * <li> Copy the <tt>{ / * English (en) * / ... }</tt> section and add it at the end of \c usbi_localized_errors<br>
- * Eg. for Chinese, the last section of \c usbi_localized_errors could look like:
- * \code
- * }, { / * Chinese (zh) * /
- * "Success",
- * ...
- * "Other error",
- * }
- * };\endcode </li>
- * <li> Translate each of the English messages from the section you copied into your language </li>
- * <li> Save the file (in UTF-8 format) and send it to \c libusb-devel\@lists.sourceforge.net </li>
- * </ol>
- */
-
-static const char* usbi_locale_supported[] = { "en", "nl", "fr", "ru" };
-static const char* usbi_localized_errors[ARRAYSIZE(usbi_locale_supported)][LIBUSB_ERROR_COUNT] = {
- { /* English (en) */
- "Success",
- "Input/Output Error",
- "Invalid parameter",
- "Access denied (insufficient permissions)",
- "No such device (it may have been disconnected)",
- "Entity not found",
- "Resource busy",
- "Operation timed out",
- "Overflow",
- "Pipe error",
- "System call interrupted (perhaps due to signal)",
- "Insufficient memory",
- "Operation not supported or unimplemented on this platform",
- "Other error",
- }, { /* Dutch (nl) */
- "Gelukt",
- "Invoer-/uitvoerfout",
- "Ongeldig argument",
- "Toegang geweigerd (onvoldoende toegangsrechten)",
- "Apparaat bestaat niet (verbinding met apparaat verbroken?)",
- "Niet gevonden",
- "Apparaat of hulpbron is bezig",
- "Bewerking verlopen",
- "Waarde is te groot",
- "Gebroken pijp",
- "Onderbroken systeemaanroep",
- "Onvoldoende geheugen beschikbaar",
- "Bewerking wordt niet ondersteund",
- "Andere fout",
- }, { /* French (fr) */
- "Succès",
- "Erreur d'entrée/sortie",
- "Paramètre invalide",
- "Accès refusé (permissions insuffisantes)",
- "Périphérique introuvable (peut-être déconnecté)",
- "Elément introuvable",
- "Resource déjà occupée",
- "Operation expirée",
- "Débordement",
- "Erreur de pipe",
- "Appel système abandonné (peut-être à cause d’un signal)",
- "Mémoire insuffisante",
- "Opération non supportée or non implémentée sur cette plateforme",
- "Autre erreur",
- }, { /* Russian (ru) */
- "Успех",
- "Ошибка ввода/вывода",
- "Неверный параметр",
- "Доступ запрещён (не хватает прав)",
- "Устройство отсутствует (возможно, оно было отсоединено)",
- "Элемент не найден",
- "Ресурс занят",
- "Истекло время ожидания операции",
- "Переполнение",
- "Ошибка канала",
- "Системный вызов прерван (возможно, сигналом)",
- "Память исчерпана",
- "Операция не поддерживается данной платформой",
- "Неизвестная ошибка"
- }
-};
-
-/** \ingroup libusb_misc
- * Set the language, and only the language, not the encoding! used for
- * translatable libusb messages.
- *
- * This takes a locale string in the default setlocale format: lang[-region]
- * or lang[_country_region][.codeset]. Only the lang part of the string is
- * used, and only 2 letter ISO 639-1 codes are accepted for it, such as "de".
- * The optional region, country_region or codeset parts are ignored. This
- * means that functions which return translatable strings will NOT honor the
- * specified encoding.
- * All strings returned are encoded as UTF-8 strings.
- *
- * If libusb_setlocale() is not called, all messages will be in English.
- *
- * The following functions return translatable strings: libusb_strerror().
- * Note that the libusb log messages controlled through libusb_set_debug()
- * are not translated, they are always in English.
- *
- * For POSIX UTF-8 environments if you want libusb to follow the standard
- * locale settings, call libusb_setlocale(setlocale(LC_MESSAGES, NULL)),
- * after your app has done its locale setup.
- *
- * \param locale locale-string in the form of lang[_country_region][.codeset]
- * or lang[-region], where lang is a 2 letter ISO 639-1 code
- * \returns LIBUSB_SUCCESS on success
- * \returns LIBUSB_ERROR_INVALID_PARAM if the locale doesn't meet the requirements
- * \returns LIBUSB_ERROR_NOT_FOUND if the requested language is not supported
- * \returns a LIBUSB_ERROR code on other errors
- */
-
-int API_EXPORTED libusb_setlocale(const char *locale)
-{
- size_t i;
-
- if ( (locale == NULL) || (strlen(locale) < 2)
- || ((strlen(locale) > 2) && (locale[2] != '-') && (locale[2] != '_') && (locale[2] != '.')) )
- return LIBUSB_ERROR_INVALID_PARAM;
-
- for (i=0; i<ARRAYSIZE(usbi_locale_supported); i++) {
- if (strncasecmp(usbi_locale_supported[i], locale, 2) == 0)
- break;
- }
- if (i >= ARRAYSIZE(usbi_locale_supported)) {
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- usbi_locale = i;
-
- return LIBUSB_SUCCESS;
-}
-
-/** \ingroup libusb_misc
- * Returns a constant string with a short description of the given error code,
- * this description is intended for displaying to the end user and will be in
- * the language set by libusb_setlocale().
- *
- * The returned string is encoded in UTF-8.
- *
- * The messages always start with a capital letter and end without any dot.
- * The caller must not free() the returned string.
- *
- * \param errcode the error code whose description is desired
- * \returns a short description of the error code in UTF-8 encoding
- */
-DEFAULT_VISIBILITY const char* LIBUSB_CALL libusb_strerror(enum libusb_error errcode)
-{
- int errcode_index = -errcode;
-
- if ((errcode_index < 0) || (errcode_index >= LIBUSB_ERROR_COUNT)) {
- /* "Other Error", which should always be our last message, is returned */
- errcode_index = LIBUSB_ERROR_COUNT - 1;
- }
-
- return usbi_localized_errors[usbi_locale][errcode_index];
-}
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/sync.c b/vendor/github.com/karalabe/hid/libusb/libusb/sync.c
deleted file mode 100644
index a609f65..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/sync.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Synchronous I/O functions for libusb
- * Copyright © 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 libusb_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 libusb_asyncio "asynchronous I/O API" instead.
- */
-
-static void LIBUSB_CALL sync_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 */
-}
-
-static void sync_transfer_wait_for_completion(struct libusb_transfer *transfer)
-{
- int r, *completed = transfer->user_data;
- struct libusb_context *ctx = HANDLE_CTX(transfer->dev_handle);
-
- while (!*completed) {
- r = libusb_handle_events_completed(ctx, completed);
- if (r < 0) {
- if (r == LIBUSB_ERROR_INTERRUPTED)
- continue;
- usbi_err(ctx, "libusb_handle_events failed: %s, cancelling transfer and retrying",
- libusb_error_name(r));
- libusb_cancel_transfer(transfer);
- continue;
- }
- }
-}
-
-/** \ingroup libusb_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 LIBUSB_ERROR_BUSY if called from event handling context
- * \returns LIBUSB_ERROR_INVALID_PARAM if the transfer size is larger than
- * the operating system and/or hardware can support
- * \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;
- unsigned char *buffer;
- int completed = 0;
- int r;
-
- if (usbi_handling_events(HANDLE_CTX(dev_handle)))
- return LIBUSB_ERROR_BUSY;
-
- transfer = libusb_alloc_transfer(0);
- if (!transfer)
- return LIBUSB_ERROR_NO_MEM;
-
- buffer = (unsigned char*) 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,
- sync_transfer_cb, &completed, timeout);
- transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
- r = libusb_submit_transfer(transfer);
- if (r < 0) {
- libusb_free_transfer(transfer);
- return r;
- }
-
- sync_transfer_wait_for_completion(transfer);
-
- 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;
- case LIBUSB_TRANSFER_ERROR:
- case LIBUSB_TRANSFER_CANCELLED:
- r = LIBUSB_ERROR_IO;
- 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 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;
- int completed = 0;
- int r;
-
- if (usbi_handling_events(HANDLE_CTX(dev_handle)))
- return LIBUSB_ERROR_BUSY;
-
- transfer = libusb_alloc_transfer(0);
- if (!transfer)
- return LIBUSB_ERROR_NO_MEM;
-
- libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
- sync_transfer_cb, &completed, timeout);
- transfer->type = type;
-
- r = libusb_submit_transfer(transfer);
- if (r < 0) {
- libusb_free_transfer(transfer);
- return r;
- }
-
- sync_transfer_wait_for_completion(transfer);
-
- if (transferred)
- *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;
- case LIBUSB_TRANSFER_ERROR:
- case LIBUSB_TRANSFER_CANCELLED:
- r = LIBUSB_ERROR_IO;
- 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 libusb_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. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105),
- * it is legal to pass a NULL pointer if you do not wish to receive this
- * information.
- * \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 libusb_packetoverflow
- * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
- * \returns LIBUSB_ERROR_BUSY if called from event handling context
- * \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 libusb_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. Since version 1.0.21 (\ref LIBUSB_API_VERSION >= 0x01000105),
- * it is legal to pass a NULL pointer if you do not wish to receive this
- * information.
- * \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 libusb_packetoverflow
- * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected
- * \returns LIBUSB_ERROR_BUSY if called from event handling context
- * \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/vendor/github.com/karalabe/hid/libusb/libusb/version.h b/vendor/github.com/karalabe/hid/libusb/libusb/version.h
deleted file mode 100644
index 6ce48a7..0000000
--- a/vendor/github.com/karalabe/hid/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. */
-#include "version_nano.h"
-#ifndef LIBUSB_MAJOR
-#define LIBUSB_MAJOR 1
-#endif
-#ifndef LIBUSB_MINOR
-#define LIBUSB_MINOR 0
-#endif
-#ifndef LIBUSB_MICRO
-#define LIBUSB_MICRO 21
-#endif
-#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 ""
-#endif
diff --git a/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h b/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h
deleted file mode 100644
index 0a5d1c9..0000000
--- a/vendor/github.com/karalabe/hid/libusb/libusb/version_nano.h
+++ /dev/null
@@ -1 +0,0 @@
-#define LIBUSB_NANO 11182