mirror of
https://github.com/bettercap/bettercap
synced 2025-07-30 03:29:57 -07:00
misc: added gousb dependency
This commit is contained in:
parent
c1729ab578
commit
6458a438db
25 changed files with 3248 additions and 0 deletions
17
Gopkg.lock
generated
17
Gopkg.lock
generated
|
@ -26,6 +26,14 @@
|
|||
pruneopts = "UT"
|
||||
revision = "1353e80bee488dc02d1f7e42759c1352492bf18b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c93fdd8820c13c2e2000d3064c510dde1397edca5ca1533fd15943402dab92b0"
|
||||
name = "github.com/bettercap/nrf24"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "aa37e6d0e0eb125cee9ec71ed694db2ad58b509a"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b95738a1e6ace058b5b8544303c0871fc01d224ef0d672f778f696265d0f2917"
|
||||
name = "github.com/bettercap/readline"
|
||||
|
@ -120,6 +128,14 @@
|
|||
pruneopts = "UT"
|
||||
revision = "v1.1.16"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2ef895ea08a0af10ad6f1e1faf631c82fa5413dcf0ada93eb62ab5ad02df4979"
|
||||
name = "github.com/google/gousb"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "d0c05ab7f70d6f6dc60ecd184517cb5e25860657"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ca59b1175189b3f0e9f1793d2c350114be36eaabbe5b9f554b35edee1de50aea"
|
||||
name = "github.com/gorilla/mux"
|
||||
|
@ -277,6 +293,7 @@
|
|||
input-imports = [
|
||||
"github.com/adrianmo/go-nmea",
|
||||
"github.com/bettercap/gatt",
|
||||
"github.com/bettercap/nrf24",
|
||||
"github.com/bettercap/readline",
|
||||
"github.com/chifflier/nfqueue-go/nfqueue",
|
||||
"github.com/dustin/go-humanize",
|
||||
|
|
2
vendor/github.com/google/gousb/.gitignore
generated
vendored
Normal file
2
vendor/github.com/google/gousb/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.sw[op]
|
||||
.idea/
|
30
vendor/github.com/google/gousb/.travis.yml
generated
vendored
Normal file
30
vendor/github.com/google/gousb/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
language: go
|
||||
dist: trusty
|
||||
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- tip
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
libusb-1.0-0-dev
|
||||
|
||||
install:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
# Golint requires Go 1.9 or later.
|
||||
- if ! [[ "$TRAVIS_GO_VERSION" =~ ^1\.7\.([0-9]+|x)$ || "$TRAVIS_GO_VERSION" =~ ^1\.8\.([0-9]+|x)$ ]]; then go get golang.org/x/lint/golint; fi
|
||||
- go get github.com/mattn/goveralls
|
||||
|
||||
script:
|
||||
# a workaround for go test not supporting coverage for multiple packages in a single invocation.
|
||||
# If goveralls upload fails, ignore the result.
|
||||
# Golint requires Go 1.9 or later.
|
||||
- if ! [[ "$TRAVIS_GO_VERSION" =~ ^1\.7\.([0-9]+|x)+$ || "$TRAVIS_GO_VERSION" =~ ^1\.8\.([0-9]+|x)$ ]]; then $HOME/gopath/bin/golint ./...; fi
|
||||
- |-
|
||||
echo 'mode: count' > coverage.merged && go list ./... | xargs -n1 -I{} sh -c ': > coverage.tmp; go test -v -covermode=count -coverprofile=coverage.tmp {} && tail -n +2 coverage.tmp >> coverage.merged' && rm coverage.tmp
|
||||
- |-
|
||||
$HOME/gopath/bin/goveralls -coverprofile=coverage.merged -service=travis-ci -ignore libusb.go,error.go || true
|
16
vendor/github.com/google/gousb/AUTHORS
generated
vendored
Normal file
16
vendor/github.com/google/gousb/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
This is the list of gousb authors for copyright purposes.
|
||||
#
|
||||
# This does not necessarily list everyone who has contributed code, since in
|
||||
# some cases, their employer may be the copyright holder. To see the full list
|
||||
# of contributors, see the revision history in source control.
|
||||
Google Inc.
|
||||
Kyle Lemons <kyle@kylelemons.net>
|
||||
Sebastian Zagrodzki <sebek@zagrodzki.net>
|
||||
Pieter Joost van de Sande <pj@born2code.net>
|
||||
Ivan Krasin <imkrasin@gmail.com>
|
||||
Jirawat I. <nodtem66@gmail.com>
|
||||
Thordur Bjornsson <thorduri@secnorth.net>
|
||||
Vincent Serpoul <vincent@serpoul.com>
|
||||
Josef Filzmaier <josef.filzmaier@gmail.com>
|
||||
Nico MT <nicovell3@gmail.com>
|
||||
Deomid "rojer" Ryabkov <rojer@rojer.me>
|
28
vendor/github.com/google/gousb/CONTRIBUTING.md
generated
vendored
Normal file
28
vendor/github.com/google/gousb/CONTRIBUTING.md
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
Want to contribute? Great! First, read this page (including the small print at
|
||||
the end).
|
||||
|
||||
### Before you contribute
|
||||
Before we can use your code, you must sign the
|
||||
[Google Individual Contributor License Agreement]
|
||||
(https://cla.developers.google.com/about/google-individual)
|
||||
(CLA), which you can do online. The CLA is necessary mainly because you own the
|
||||
copyright to your changes, even after your contribution becomes part of our
|
||||
codebase, so we need your permission to use and distribute your code. We also
|
||||
need to be sure of various other things—for instance that you'll tell us if you
|
||||
know that your code infringes on other people's patents. You don't have to sign
|
||||
the CLA until after you've submitted your code for review and a member has
|
||||
approved it, but you must do it before we can put your code into our codebase.
|
||||
Before you start working on a larger contribution, you should get in touch with
|
||||
us first through the issue tracker with your idea so that we can help out and
|
||||
possibly guide you. Coordinating up front makes it much easier to avoid
|
||||
frustration later on.
|
||||
|
||||
### Code reviews
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use Github pull requests for this purpose.
|
||||
|
||||
### The small print
|
||||
Contributions made by corporations are covered by a different agreement than
|
||||
the one above, the
|
||||
[Software Grant and Corporate Contributor License Agreement]
|
||||
(https://cla.developers.google.com/about/google-corporate).
|
202
vendor/github.com/google/gousb/LICENSE
generated
vendored
Normal file
202
vendor/github.com/google/gousb/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
87
vendor/github.com/google/gousb/README.md
generated
vendored
Normal file
87
vendor/github.com/google/gousb/README.md
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
[![Build Status][ciimg]][ci]
|
||||
[![GoDoc][docimg]][doc]
|
||||
[![Coverage Status][coverimg]][cover]
|
||||
[![Build status][appveimg]][appveyor]
|
||||
|
||||
|
||||
The gousb package is an attempt at wrapping the libusb library into a Go-like binding.
|
||||
|
||||
Supported platforms include:
|
||||
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
|
||||
This is the release 2.0 of the package [github.com/kylelemons/gousb](https://github.com/kylelemons/gousb).
|
||||
Its API is not backwards-compatible with version 1.0.
|
||||
As of 2017-07-13 the 2.0 API is considered stable and 1.0 is deprecated.
|
||||
|
||||
[coverimg]: https://coveralls.io/repos/github/google/gousb/badge.svg
|
||||
[cover]: https://coveralls.io/github/google/gousb
|
||||
[ciimg]: https://travis-ci.org/google/gousb.svg
|
||||
[ci]: https://travis-ci.org/google/gousb
|
||||
[docimg]: https://godoc.org/github.com/google/gousb?status.svg
|
||||
[doc]: https://godoc.org/github.com/google/gousb
|
||||
[appveimg]: https://ci.appveyor.com/api/projects/status/661qp7x33o3wqe4o?svg=true
|
||||
[appveyor]: https://ci.appveyor.com/project/zagrodzki/gousb
|
||||
|
||||
Documentation
|
||||
=============
|
||||
The documentation can be viewed via local godoc or via the excellent [godoc.org](http://godoc.org/):
|
||||
|
||||
- [usb](http://godoc.org/github.com/google/gousb)
|
||||
- [usbid](http://godoc.org/pkg/github.com/google/gousb/usbid)
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
You must first install [libusb-1.0]https://github.com/libusb/libusb/wiki). This is pretty straightforward on linux and darwin. The cgo package should be able to find it if you install it in the default manner or use your distribution's package manager. How to tell cgo how to find one installed in a non-default place is beyond the scope of this README.
|
||||
|
||||
*Note*: If you are installing this on darwin, you will probably need to run `fixlibusb_darwin.sh /usr/local/lib/libusb-1.0/libusb.h` because of an LLVM incompatibility. It shouldn't break C programs, though I haven't tried it in anger.
|
||||
|
||||
Example: lsusb
|
||||
--------------
|
||||
The gousb project provides a simple but useful example: lsusb. This binary will list the USB devices connected to your system and various interesting tidbits about them, their configurations, endpoints, etc. To install it, run the following command:
|
||||
|
||||
go get -v github.com/google/gousb/lsusb
|
||||
|
||||
gousb
|
||||
-----
|
||||
If you installed the lsusb example, both libraries below are already installed.
|
||||
|
||||
Installing the primary gousb package is really easy:
|
||||
|
||||
go get -v github.com/google/gousb
|
||||
|
||||
There is also a `usbid` package that will not be installed by default by this command, but which provides useful information including the human-readable vendor and product codes for detected hardware. It's not installed by default and not linked into the `gousb` package by default because it adds ~400kb to the resulting binary. If you want both, they can be installed thus:
|
||||
|
||||
go get -v github.com/google/gousb{,/usbid}
|
||||
|
||||
Notes for installation on Windows
|
||||
---------------------------------
|
||||
|
||||
You'll need:
|
||||
|
||||
- Gcc - tested on [Win-Builds](http://win-builds.org/) and MSYS/MINGW
|
||||
- pkg-config - see http://www.mingw.org/wiki/FAQ, "How do I get pkg-config installed?"
|
||||
- [libusb-1.0](http://sourceforge.net/projects/libusb/files/libusb-1.0/).
|
||||
|
||||
Make sure the `libusb-1.0.pc` pkg-config file from libusb was installed
|
||||
and that the result of the `pkg-config --cflags libusb-1.0` command shows the
|
||||
correct include path for installed libusb.
|
||||
|
||||
After that you can continue with instructions for lsusb/gousb above.
|
||||
|
||||
Contributing
|
||||
============
|
||||
Contributing to this project will require signing the [Google CLA][cla].
|
||||
This is the same agreement that is required for contributing to Go itself, so if you have
|
||||
already filled it out for that, you needn't fill it out again.
|
||||
|
||||
[cla]: https://cla.developers.google.com/
|
||||
|
8
vendor/github.com/google/gousb/appveyor.yml
generated
vendored
Normal file
8
vendor/github.com/google/gousb/appveyor.yml
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
platform: x64
|
||||
|
||||
clone_folder: C:\msys64\go\src\github.com\google\gousb
|
||||
|
||||
install:
|
||||
- C:\msys64\usr\bin\bash.exe -lc "cd /go/src/github.com/google/gousb/ && .appveyor/./install.sh"
|
||||
|
||||
build: off
|
140
vendor/github.com/google/gousb/config.go
generated
vendored
Normal file
140
vendor/github.com/google/gousb/config.go
generated
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ConfigDesc contains the information about a USB device configuration,
|
||||
// extracted from the device descriptor.
|
||||
type ConfigDesc struct {
|
||||
// Number is the configuration number.
|
||||
Number int
|
||||
// SelfPowered is true if the device is powered externally, i.e. not
|
||||
// drawing power from the USB bus.
|
||||
SelfPowered bool
|
||||
// RemoteWakeup is true if the device supports remote wakeup, i.e.
|
||||
// an external signal that will wake up a suspended USB device. An example
|
||||
// might be a keyboard that can wake up through a keypress after
|
||||
// the host put it in suspend mode. Note that gousb does not support
|
||||
// device power management, RemoteWakeup only refers to the reported device
|
||||
// capability.
|
||||
RemoteWakeup bool
|
||||
// MaxPower is the maximum current the device draws from the USB bus
|
||||
// in this configuration.
|
||||
MaxPower Milliamperes
|
||||
// Interfaces has a list of USB interfaces available in this configuration.
|
||||
Interfaces []InterfaceDesc
|
||||
|
||||
iConfiguration int // index of a string descriptor describing this configuration
|
||||
}
|
||||
|
||||
// String returns the human-readable description of the configuration descriptor.
|
||||
func (c ConfigDesc) String() string {
|
||||
return fmt.Sprintf("Configuration %d", c.Number)
|
||||
}
|
||||
|
||||
func (c ConfigDesc) intfDesc(num, alt int) (*InterfaceSetting, error) {
|
||||
if num < 0 || num >= len(c.Interfaces) {
|
||||
return nil, fmt.Errorf("interface %d not found, available interfaces 0..%d", num, len(c.Interfaces)-1)
|
||||
}
|
||||
ifInfo := c.Interfaces[num]
|
||||
if alt < 0 || alt >= len(ifInfo.AltSettings) {
|
||||
return nil, fmt.Errorf("alternate setting %d not found for %s, available alt settings 0..%d", alt, ifInfo, len(ifInfo.AltSettings)-1)
|
||||
}
|
||||
return &ifInfo.AltSettings[alt], nil
|
||||
}
|
||||
|
||||
// Config represents a USB device set to use a particular configuration.
|
||||
// Only one Config of a particular device can be used at any one time.
|
||||
// To access device endpoints, claim an interface and it's alternate
|
||||
// setting number through a call to Interface().
|
||||
type Config struct {
|
||||
Desc ConfigDesc
|
||||
|
||||
dev *Device
|
||||
|
||||
// Claimed interfaces
|
||||
mu sync.Mutex
|
||||
claimed map[int]bool
|
||||
}
|
||||
|
||||
// Close releases the underlying device, allowing the caller to switch the device to a different configuration.
|
||||
func (c *Config) Close() error {
|
||||
if c.dev == nil {
|
||||
return nil
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if len(c.claimed) > 0 {
|
||||
var ifs []int
|
||||
for k := range c.claimed {
|
||||
ifs = append(ifs, k)
|
||||
}
|
||||
return fmt.Errorf("failed to release %s, interfaces %v are still open", c, ifs)
|
||||
}
|
||||
c.dev.mu.Lock()
|
||||
defer c.dev.mu.Unlock()
|
||||
c.dev.claimed = nil
|
||||
c.dev = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the human-readable description of the configuration.
|
||||
func (c *Config) String() string {
|
||||
return fmt.Sprintf("%s,config=%d", c.dev.String(), c.Desc.Number)
|
||||
}
|
||||
|
||||
// Interface claims and returns an interface on a USB device.
|
||||
// num specifies the number of an interface to claim, and alt specifies the
|
||||
// alternate setting number for that interface.
|
||||
func (c *Config) Interface(num, alt int) (*Interface, error) {
|
||||
if c.dev == nil {
|
||||
return nil, fmt.Errorf("Interface(%d, %d) called on %s after Close", num, alt, c)
|
||||
}
|
||||
|
||||
altInfo, err := c.Desc.intfDesc(num, alt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("descriptor of interface (%d, %d) in %s: %v", num, alt, c, err)
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.claimed[num] {
|
||||
return nil, fmt.Errorf("interface %d on %s is already claimed", num, c)
|
||||
}
|
||||
|
||||
// Claim the interface
|
||||
if err := c.dev.ctx.libusb.claim(c.dev.handle, uint8(num)); err != nil {
|
||||
return nil, fmt.Errorf("failed to claim interface %d on %s: %v", num, c, err)
|
||||
}
|
||||
|
||||
// Select an alternate setting if needed (device has multiple alternate settings).
|
||||
if len(c.Desc.Interfaces[num].AltSettings) > 1 {
|
||||
if err := c.dev.ctx.libusb.setAlt(c.dev.handle, uint8(num), uint8(alt)); err != nil {
|
||||
c.dev.ctx.libusb.release(c.dev.handle, uint8(num))
|
||||
return nil, fmt.Errorf("failed to set alternate config %d on interface %d of %s: %v", alt, num, c, err)
|
||||
}
|
||||
}
|
||||
|
||||
c.claimed[num] = true
|
||||
return &Interface{
|
||||
Setting: *altInfo,
|
||||
config: c,
|
||||
}, nil
|
||||
}
|
276
vendor/github.com/google/gousb/constants.go
generated
vendored
Normal file
276
vendor/github.com/google/gousb/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,276 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
// #include <libusb.h>
|
||||
import "C"
|
||||
import "strconv"
|
||||
|
||||
// Class represents a USB-IF (Implementers Forum) class or subclass code.
|
||||
type Class uint8
|
||||
|
||||
// Standard classes defined by USB spec, see https://www.usb.org/defined-class-codes
|
||||
const (
|
||||
ClassPerInterface Class = 0x00
|
||||
ClassAudio Class = 0x01
|
||||
ClassComm Class = 0x02
|
||||
ClassHID Class = 0x03
|
||||
ClassPhysical Class = 0x05
|
||||
ClassImage Class = 0x06
|
||||
ClassPTP Class = ClassImage // legacy name for image
|
||||
ClassPrinter Class = 0x07
|
||||
ClassMassStorage Class = 0x08
|
||||
ClassHub Class = 0x09
|
||||
ClassData Class = 0x0a
|
||||
ClassSmartCard Class = 0x0b
|
||||
ClassContentSecurity Class = 0x0d
|
||||
ClassVideo Class = 0x0e
|
||||
ClassPersonalHealthcare Class = 0x0f
|
||||
ClassAudioVideo Class = 0x10
|
||||
ClassBillboard Class = 0x11
|
||||
ClassUSBTypeCBridge Class = 0x12
|
||||
ClassDiagnosticDevice Class = 0xdc
|
||||
ClassWireless Class = 0xe0
|
||||
ClassMiscellaneous Class = 0xef
|
||||
ClassApplication Class = 0xfe
|
||||
ClassVendorSpec Class = 0xff
|
||||
)
|
||||
|
||||
var classDescription = map[Class]string{
|
||||
ClassPerInterface: "per-interface",
|
||||
ClassAudio: "audio",
|
||||
ClassComm: "communications",
|
||||
ClassHID: "human interface device",
|
||||
ClassPhysical: "physical",
|
||||
ClassImage: "image",
|
||||
ClassPrinter: "printer",
|
||||
ClassMassStorage: "mass storage",
|
||||
ClassHub: "hub",
|
||||
ClassData: "data",
|
||||
ClassSmartCard: "smart card",
|
||||
ClassContentSecurity: "content security",
|
||||
ClassVideo: "video",
|
||||
ClassPersonalHealthcare: "personal healthcare",
|
||||
ClassAudioVideo: "audio/video",
|
||||
ClassBillboard: "billboard",
|
||||
ClassUSBTypeCBridge: "USB type-C bridge",
|
||||
ClassDiagnosticDevice: "diagnostic device",
|
||||
ClassWireless: "wireless",
|
||||
ClassMiscellaneous: "miscellaneous",
|
||||
ClassApplication: "application-specific",
|
||||
ClassVendorSpec: "vendor-specific",
|
||||
}
|
||||
|
||||
func (c Class) String() string {
|
||||
if d, ok := classDescription[c]; ok {
|
||||
return d
|
||||
}
|
||||
return strconv.Itoa(int(c))
|
||||
}
|
||||
|
||||
// Protocol is the interface class protocol, qualified by the values
|
||||
// of interface class and subclass.
|
||||
type Protocol uint8
|
||||
|
||||
func (p Protocol) String() string {
|
||||
return strconv.Itoa(int(p))
|
||||
}
|
||||
|
||||
// DescriptorType identifies the type of a USB descriptor.
|
||||
type DescriptorType uint8
|
||||
|
||||
// Descriptor types defined by the USB spec.
|
||||
const (
|
||||
DescriptorTypeDevice DescriptorType = C.LIBUSB_DT_DEVICE
|
||||
DescriptorTypeConfig DescriptorType = C.LIBUSB_DT_CONFIG
|
||||
DescriptorTypeString DescriptorType = C.LIBUSB_DT_STRING
|
||||
DescriptorTypeInterface DescriptorType = C.LIBUSB_DT_INTERFACE
|
||||
DescriptorTypeEndpoint DescriptorType = C.LIBUSB_DT_ENDPOINT
|
||||
DescriptorTypeHID DescriptorType = C.LIBUSB_DT_HID
|
||||
DescriptorTypeReport DescriptorType = C.LIBUSB_DT_REPORT
|
||||
DescriptorTypePhysical DescriptorType = C.LIBUSB_DT_PHYSICAL
|
||||
DescriptorTypeHub DescriptorType = C.LIBUSB_DT_HUB
|
||||
)
|
||||
|
||||
var descriptorTypeDescription = map[DescriptorType]string{
|
||||
DescriptorTypeDevice: "device",
|
||||
DescriptorTypeConfig: "configuration",
|
||||
DescriptorTypeString: "string",
|
||||
DescriptorTypeInterface: "interface",
|
||||
DescriptorTypeEndpoint: "endpoint",
|
||||
DescriptorTypeHID: "HID",
|
||||
DescriptorTypeReport: "HID report",
|
||||
DescriptorTypePhysical: "physical",
|
||||
DescriptorTypeHub: "hub",
|
||||
}
|
||||
|
||||
func (dt DescriptorType) String() string {
|
||||
return descriptorTypeDescription[dt]
|
||||
}
|
||||
|
||||
// EndpointDirection defines the direction of data flow - IN (device to host)
|
||||
// or OUT (host to device).
|
||||
type EndpointDirection bool
|
||||
|
||||
const (
|
||||
endpointNumMask = 0x0f
|
||||
endpointDirectionMask = 0x80
|
||||
// EndpointDirectionIn marks data flowing from device to host.
|
||||
EndpointDirectionIn EndpointDirection = true
|
||||
// EndpointDirectionOut marks data flowing from host to device.
|
||||
EndpointDirectionOut EndpointDirection = false
|
||||
)
|
||||
|
||||
var endpointDirectionDescription = map[EndpointDirection]string{
|
||||
EndpointDirectionIn: "IN",
|
||||
EndpointDirectionOut: "OUT",
|
||||
}
|
||||
|
||||
func (ed EndpointDirection) String() string {
|
||||
return endpointDirectionDescription[ed]
|
||||
}
|
||||
|
||||
// TransferType defines the endpoint transfer type.
|
||||
type TransferType uint8
|
||||
|
||||
// Transfer types defined by the USB spec.
|
||||
const (
|
||||
TransferTypeControl TransferType = C.LIBUSB_TRANSFER_TYPE_CONTROL
|
||||
TransferTypeIsochronous TransferType = C.LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
|
||||
TransferTypeBulk TransferType = C.LIBUSB_TRANSFER_TYPE_BULK
|
||||
TransferTypeInterrupt TransferType = C.LIBUSB_TRANSFER_TYPE_INTERRUPT
|
||||
transferTypeMask = 0x03
|
||||
)
|
||||
|
||||
var transferTypeDescription = map[TransferType]string{
|
||||
TransferTypeControl: "control",
|
||||
TransferTypeIsochronous: "isochronous",
|
||||
TransferTypeBulk: "bulk",
|
||||
TransferTypeInterrupt: "interrupt",
|
||||
}
|
||||
|
||||
// String returns a human-readable name of the endpoint transfer type.
|
||||
func (tt TransferType) String() string {
|
||||
return transferTypeDescription[tt]
|
||||
}
|
||||
|
||||
// IsoSyncType defines the isochronous transfer synchronization type.
|
||||
type IsoSyncType uint8
|
||||
|
||||
// Synchronization types defined by the USB spec.
|
||||
const (
|
||||
IsoSyncTypeNone IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_NONE << 2
|
||||
IsoSyncTypeAsync IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ASYNC << 2
|
||||
IsoSyncTypeAdaptive IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_ADAPTIVE << 2
|
||||
IsoSyncTypeSync IsoSyncType = C.LIBUSB_ISO_SYNC_TYPE_SYNC << 2
|
||||
isoSyncTypeMask = 0x0C
|
||||
)
|
||||
|
||||
var isoSyncTypeDescription = map[IsoSyncType]string{
|
||||
IsoSyncTypeNone: "unsynchronized",
|
||||
IsoSyncTypeAsync: "asynchronous",
|
||||
IsoSyncTypeAdaptive: "adaptive",
|
||||
IsoSyncTypeSync: "synchronous",
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the synchronization type.
|
||||
func (ist IsoSyncType) String() string {
|
||||
return isoSyncTypeDescription[ist]
|
||||
}
|
||||
|
||||
// UsageType defines the transfer usage type for isochronous and interrupt
|
||||
// transfers.
|
||||
type UsageType uint8
|
||||
|
||||
// Usage types for iso and interrupt transfers, defined by the USB spec.
|
||||
const (
|
||||
// Note: USB3.0 defines usage type for both isochronous and interrupt
|
||||
// endpoints, with the same constants representing different usage types.
|
||||
// UsageType constants do not correspond to bmAttribute values.
|
||||
UsageTypeUndefined UsageType = iota
|
||||
IsoUsageTypeData
|
||||
IsoUsageTypeFeedback
|
||||
IsoUsageTypeImplicit
|
||||
InterruptUsageTypePeriodic
|
||||
InterruptUsageTypeNotification
|
||||
usageTypeMask = 0x30
|
||||
)
|
||||
|
||||
var usageTypeDescription = map[UsageType]string{
|
||||
UsageTypeUndefined: "undefined usage",
|
||||
IsoUsageTypeData: "data",
|
||||
IsoUsageTypeFeedback: "feedback",
|
||||
IsoUsageTypeImplicit: "implicit data",
|
||||
InterruptUsageTypePeriodic: "periodic",
|
||||
InterruptUsageTypeNotification: "notification",
|
||||
}
|
||||
|
||||
func (ut UsageType) String() string {
|
||||
return usageTypeDescription[ut]
|
||||
}
|
||||
|
||||
// Control request type bit fields as defined in the USB spec. All values are
|
||||
// of uint8 type. These constants can be used with Device.Control() method to
|
||||
// specify the type and destination of the control request, e.g.
|
||||
// `dev.Control(ControlOut|ControlVendor|ControlDevice, ...)`.
|
||||
const (
|
||||
ControlIn = C.LIBUSB_ENDPOINT_IN
|
||||
ControlOut = C.LIBUSB_ENDPOINT_OUT
|
||||
|
||||
// "Standard" is explicitly omitted, as functionality of standard requests
|
||||
// is exposed through higher level operations of gousb.
|
||||
ControlClass = C.LIBUSB_REQUEST_TYPE_CLASS
|
||||
ControlVendor = C.LIBUSB_REQUEST_TYPE_VENDOR
|
||||
// "Reserved" is explicitly omitted, should not be used.
|
||||
|
||||
ControlDevice = C.LIBUSB_RECIPIENT_DEVICE
|
||||
ControlInterface = C.LIBUSB_RECIPIENT_INTERFACE
|
||||
ControlEndpoint = C.LIBUSB_RECIPIENT_ENDPOINT
|
||||
ControlOther = C.LIBUSB_RECIPIENT_OTHER
|
||||
)
|
||||
|
||||
// Speed identifies the speed of the device.
|
||||
type Speed int
|
||||
|
||||
// Device speeds as defined in the USB spec.
|
||||
const (
|
||||
SpeedUnknown Speed = C.LIBUSB_SPEED_UNKNOWN
|
||||
SpeedLow Speed = C.LIBUSB_SPEED_LOW
|
||||
SpeedFull Speed = C.LIBUSB_SPEED_FULL
|
||||
SpeedHigh Speed = C.LIBUSB_SPEED_HIGH
|
||||
SpeedSuper Speed = C.LIBUSB_SPEED_SUPER
|
||||
)
|
||||
|
||||
var deviceSpeedDescription = map[Speed]string{
|
||||
SpeedUnknown: "unknown",
|
||||
SpeedLow: "low",
|
||||
SpeedFull: "full",
|
||||
SpeedHigh: "high",
|
||||
SpeedSuper: "super",
|
||||
}
|
||||
|
||||
// String returns a human-readable name of the device speed.
|
||||
func (s Speed) String() string {
|
||||
return deviceSpeedDescription[s]
|
||||
}
|
||||
|
||||
const (
|
||||
selfPoweredMask = 0x40
|
||||
remoteWakeupMask = 0x20
|
||||
)
|
||||
|
||||
// Milliamperes is a unit of electric current consumption.
|
||||
type Milliamperes uint
|
37
vendor/github.com/google/gousb/debug.go
generated
vendored
Normal file
37
vendor/github.com/google/gousb/debug.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
// To enable internal debugging, set the GOUSB_DEBUG environment variable.
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log" // TODO(kevlar): make a logger
|
||||
"os"
|
||||
)
|
||||
|
||||
var debug *log.Logger
|
||||
|
||||
const debugEnvVarName = "GOUSB_DEBUG"
|
||||
|
||||
func init() {
|
||||
out := io.Writer(ioutil.Discard)
|
||||
if os.Getenv(debugEnvVarName) != "" {
|
||||
out = os.Stderr
|
||||
}
|
||||
debug = log.New(out, "gousb: ", log.LstdFlags|log.Lshortfile)
|
||||
}
|
289
vendor/github.com/google/gousb/device.go
generated
vendored
Normal file
289
vendor/github.com/google/gousb/device.go
generated
vendored
Normal file
|
@ -0,0 +1,289 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DeviceDesc is a representation of a USB device descriptor.
|
||||
type DeviceDesc struct {
|
||||
// Bus information
|
||||
Bus int // The bus on which the device was detected
|
||||
Address int // The address of the device on the bus
|
||||
Speed Speed // The negotiated operating speed for the device
|
||||
Port int // The usb port on which the device was detected
|
||||
|
||||
// Version information
|
||||
Spec BCD // USB Specification Release Number
|
||||
Device BCD // The device version
|
||||
|
||||
// Product information
|
||||
Vendor ID // The Vendor identifer
|
||||
Product ID // The Product identifier
|
||||
|
||||
// Protocol information
|
||||
Class Class // The class of this device
|
||||
SubClass Class // The sub-class (within the class) of this device
|
||||
Protocol Protocol // The protocol (within the sub-class) of this device
|
||||
MaxControlPacketSize int // Maximum size of the control transfer
|
||||
|
||||
// Configuration information
|
||||
Configs map[int]ConfigDesc
|
||||
|
||||
iManufacturer int // The Manufacturer descriptor index
|
||||
iProduct int // The Product descriptor index
|
||||
iSerialNumber int // The SerialNumber descriptor index
|
||||
}
|
||||
|
||||
// String returns a human-readable version of the device descriptor.
|
||||
func (d *DeviceDesc) String() string {
|
||||
return fmt.Sprintf("%d.%d: %s:%s (available configs: %v)", d.Bus, d.Address, d.Vendor, d.Product, d.sortedConfigIds())
|
||||
}
|
||||
|
||||
func (d *DeviceDesc) sortedConfigIds() []int {
|
||||
var cfgs []int
|
||||
for c := range d.Configs {
|
||||
cfgs = append(cfgs, c)
|
||||
}
|
||||
sort.Ints(cfgs)
|
||||
return cfgs
|
||||
}
|
||||
|
||||
func (d *DeviceDesc) cfgDesc(cfgNum int) (*ConfigDesc, error) {
|
||||
desc, ok := d.Configs[cfgNum]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("configuration id %d not found in the descriptor of the device. Available config ids: %v", cfgNum, d.sortedConfigIds())
|
||||
}
|
||||
return &desc, nil
|
||||
}
|
||||
|
||||
// Device represents an opened USB device.
|
||||
// Device allows sending USB control commands through the Command() method.
|
||||
// For data transfers select a device configuration through a call to
|
||||
// Config().
|
||||
// A Device must be Close()d after use.
|
||||
type Device struct {
|
||||
handle *libusbDevHandle
|
||||
ctx *Context
|
||||
|
||||
// Embed the device information for easy access
|
||||
Desc *DeviceDesc
|
||||
// Timeout for control commands
|
||||
ControlTimeout time.Duration
|
||||
|
||||
// Claimed config
|
||||
mu sync.Mutex
|
||||
claimed *Config
|
||||
|
||||
// Handle AutoDetach in this library
|
||||
autodetach bool
|
||||
}
|
||||
|
||||
// String represents a human readable representation of the device.
|
||||
func (d *Device) String() string {
|
||||
return fmt.Sprintf("vid=%s,pid=%s,bus=%d,addr=%d", d.Desc.Vendor, d.Desc.Product, d.Desc.Bus, d.Desc.Address)
|
||||
}
|
||||
|
||||
// Reset performs a USB port reset to reinitialize a device.
|
||||
func (d *Device) Reset() error {
|
||||
if d.handle == nil {
|
||||
return fmt.Errorf("Reset() called on %s after Close", d)
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.claimed != nil {
|
||||
return fmt.Errorf("can't reset device %s while it has an active configuration %s", d, d.claimed)
|
||||
}
|
||||
return d.ctx.libusb.reset(d.handle)
|
||||
}
|
||||
|
||||
// ActiveConfigNum returns the config id of the active configuration.
|
||||
// The value corresponds to the ConfigInfo.Config field of one of the
|
||||
// ConfigInfos of this Device.
|
||||
func (d *Device) ActiveConfigNum() (int, error) {
|
||||
if d.handle == nil {
|
||||
return 0, fmt.Errorf("ActiveConfig() called on %s after Close", d)
|
||||
}
|
||||
ret, err := d.ctx.libusb.getConfig(d.handle)
|
||||
return int(ret), err
|
||||
}
|
||||
|
||||
// Config returns a USB device set to use a particular config.
|
||||
// The cfgNum provided is the config id (not the index) of the configuration to
|
||||
// set, which corresponds to the ConfigInfo.Config field.
|
||||
// USB supports only one active config per device at a time. Config claims the
|
||||
// device before setting the desired config and keeps it locked until Close is
|
||||
// called.
|
||||
// A claimed config needs to be Close()d after use.
|
||||
func (d *Device) Config(cfgNum int) (*Config, error) {
|
||||
if d.handle == nil {
|
||||
return nil, fmt.Errorf("Config(%d) called on %s after Close", cfgNum, d)
|
||||
}
|
||||
desc, err := d.Desc.cfgDesc(cfgNum)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("device %s: %v", d, err)
|
||||
}
|
||||
cfg := &Config{
|
||||
Desc: *desc,
|
||||
dev: d,
|
||||
claimed: make(map[int]bool),
|
||||
}
|
||||
|
||||
if d.autodetach {
|
||||
for _, iface := range cfg.Desc.Interfaces {
|
||||
if err := d.ctx.libusb.detachKernelDriver(d.handle, uint8(iface.Number)); err != nil {
|
||||
return nil, fmt.Errorf("Can't detach kernel driver of the device %s and interface %d: %v", d, iface.Number, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if activeCfgNum, err := d.ActiveConfigNum(); err != nil {
|
||||
return nil, fmt.Errorf("failed to query active config of the device %s: %v", d, err)
|
||||
} else if cfgNum != activeCfgNum {
|
||||
if err := d.ctx.libusb.setConfig(d.handle, uint8(cfgNum)); err != nil {
|
||||
return nil, fmt.Errorf("failed to set active config %d for the device %s: %v", cfgNum, d, err)
|
||||
}
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
d.claimed = cfg
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// DefaultInterface opens interface #0 with alternate setting #0 of the currently active
|
||||
// config. It's intended as a shortcut for devices that have the simplest
|
||||
// interface of a single config, interface and alternate setting.
|
||||
// The done func should be called to release the claimed interface and config.
|
||||
func (d *Device) DefaultInterface() (intf *Interface, done func(), err error) {
|
||||
cfgNum, err := d.ActiveConfigNum()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get active config number of device %s: %v", d, err)
|
||||
}
|
||||
cfg, err := d.Config(cfgNum)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to claim config %d of device %s: %v", cfgNum, d, err)
|
||||
}
|
||||
i, err := cfg.Interface(0, 0)
|
||||
if err != nil {
|
||||
cfg.Close()
|
||||
return nil, nil, fmt.Errorf("failed to select interface #%d alternate setting %d of config %d of device %s: %v", 0, 0, cfgNum, d, err)
|
||||
}
|
||||
return i, func() {
|
||||
intf.Close()
|
||||
cfg.Close()
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Control sends a control request to the device.
|
||||
func (d *Device) Control(rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
||||
if d.handle == nil {
|
||||
return 0, fmt.Errorf("Control() called on %s after Close", d)
|
||||
}
|
||||
return d.ctx.libusb.control(d.handle, d.ControlTimeout, rType, request, val, idx, data)
|
||||
}
|
||||
|
||||
// Close closes the device.
|
||||
func (d *Device) Close() error {
|
||||
if d.handle == nil {
|
||||
return nil
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
if d.claimed != nil {
|
||||
return fmt.Errorf("can't release the device %s, it has an open config %d", d, d.claimed.Desc.Number)
|
||||
}
|
||||
d.ctx.libusb.close(d.handle)
|
||||
d.handle = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStringDescriptor returns a device string descriptor with the given index
|
||||
// number. The first supported language is always used and the returned
|
||||
// descriptor string is converted to ASCII (non-ASCII characters are replaced
|
||||
// with "?").
|
||||
func (d *Device) GetStringDescriptor(descIndex int) (string, error) {
|
||||
if d.handle == nil {
|
||||
return "", fmt.Errorf("GetStringDescriptor(%d) called on %s after Close", descIndex, d)
|
||||
}
|
||||
// string descriptor index value of 0 indicates no string descriptor.
|
||||
if descIndex == 0 {
|
||||
return "", nil
|
||||
}
|
||||
return d.ctx.libusb.getStringDesc(d.handle, descIndex)
|
||||
}
|
||||
|
||||
// Manufacturer returns the device's manufacturer name.
|
||||
// GetStringDescriptor's string conversion rules apply.
|
||||
func (d *Device) Manufacturer() (string, error) {
|
||||
return d.GetStringDescriptor(d.Desc.iManufacturer)
|
||||
}
|
||||
|
||||
// Product returns the device's product name.
|
||||
// GetStringDescriptor's string conversion rules apply.
|
||||
func (d *Device) Product() (string, error) {
|
||||
return d.GetStringDescriptor(d.Desc.iProduct)
|
||||
}
|
||||
|
||||
// SerialNumber returns the device's serial number.
|
||||
// GetStringDescriptor's string conversion rules apply.
|
||||
func (d *Device) SerialNumber() (string, error) {
|
||||
return d.GetStringDescriptor(d.Desc.iSerialNumber)
|
||||
}
|
||||
|
||||
// ConfigDescription returns the description of the selected device
|
||||
// configuration. GetStringDescriptor's string conversion rules apply.
|
||||
func (d *Device) ConfigDescription(cfg int) (string, error) {
|
||||
c, err := d.Desc.cfgDesc(cfg)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: %v", d, err)
|
||||
}
|
||||
return d.GetStringDescriptor(c.iConfiguration)
|
||||
}
|
||||
|
||||
// InterfaceDescription returns the description of the selected interface and
|
||||
// its alternate setting in a selected configuration. GetStringDescriptor's
|
||||
// string conversion rules apply.
|
||||
func (d *Device) InterfaceDescription(cfgNum, intfNum, altNum int) (string, error) {
|
||||
cfg, err := d.Desc.cfgDesc(cfgNum)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: %v", d, err)
|
||||
}
|
||||
alt, err := cfg.intfDesc(intfNum, altNum)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s, configuration %d: %v", d, cfgNum, err)
|
||||
}
|
||||
return d.GetStringDescriptor(alt.iInterface)
|
||||
}
|
||||
|
||||
// SetAutoDetach enables/disables automatic kernel driver detachment.
|
||||
// When autodetach is enabled gousb will automatically detach the kernel driver
|
||||
// on the interface and reattach it when releasing the interface.
|
||||
// Automatic kernel driver detachment is disabled on newly opened device handles by default.
|
||||
func (d *Device) SetAutoDetach(autodetach bool) error {
|
||||
if d.handle == nil {
|
||||
return fmt.Errorf("SetAutoDetach(%v) called on %s after Close", autodetach, d)
|
||||
}
|
||||
d.autodetach = autodetach
|
||||
var autodetachInt int
|
||||
if autodetach {
|
||||
autodetachInt = 1
|
||||
}
|
||||
return d.ctx.libusb.setAutoDetach(d.handle, autodetachInt)
|
||||
}
|
161
vendor/github.com/google/gousb/endpoint.go
generated
vendored
Normal file
161
vendor/github.com/google/gousb/endpoint.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// EndpointAddress is a unique identifier for the endpoint, combining the endpoint number and direction.
|
||||
type EndpointAddress uint8
|
||||
|
||||
// String implements the Stringer interface.
|
||||
func (a EndpointAddress) String() string {
|
||||
return fmt.Sprintf("0x%02x", uint8(a))
|
||||
}
|
||||
|
||||
// EndpointDesc contains the information about an interface endpoint, extracted
|
||||
// from the descriptor.
|
||||
type EndpointDesc struct {
|
||||
// Address is the unique identifier of the endpoint within the interface.
|
||||
Address EndpointAddress
|
||||
// Number represents the endpoint number. Note that the endpoint number is different from the
|
||||
// address field in the descriptor - address 0x82 means endpoint number 2,
|
||||
// with endpoint direction IN.
|
||||
// The device can have up to two endpoints with the same number but with
|
||||
// different directions.
|
||||
Number int
|
||||
// Direction defines whether the data is flowing IN or OUT from the host perspective.
|
||||
Direction EndpointDirection
|
||||
// MaxPacketSize is the maximum USB packet size for a single frame/microframe.
|
||||
MaxPacketSize int
|
||||
// TransferType defines the endpoint type - bulk, interrupt, isochronous.
|
||||
TransferType TransferType
|
||||
// PollInterval is the maximum time between transfers for interrupt and isochronous transfer,
|
||||
// or the NAK interval for a control transfer. See endpoint descriptor bInterval documentation
|
||||
// in the USB spec for details.
|
||||
PollInterval time.Duration
|
||||
// IsoSyncType is the isochronous endpoint synchronization type, as defined by USB spec.
|
||||
IsoSyncType IsoSyncType
|
||||
// UsageType is the isochronous or interrupt endpoint usage type, as defined by USB spec.
|
||||
UsageType UsageType
|
||||
}
|
||||
|
||||
// String returns the human-readable description of the endpoint.
|
||||
func (e EndpointDesc) String() string {
|
||||
ret := make([]string, 0, 3)
|
||||
ret = append(ret, fmt.Sprintf("ep #%d %s (address %s) %s", e.Number, e.Direction, e.Address, e.TransferType))
|
||||
switch e.TransferType {
|
||||
case TransferTypeIsochronous:
|
||||
ret = append(ret, fmt.Sprintf("- %s %s", e.IsoSyncType, e.UsageType))
|
||||
case TransferTypeInterrupt:
|
||||
ret = append(ret, fmt.Sprintf("- %s", e.UsageType))
|
||||
}
|
||||
ret = append(ret, fmt.Sprintf("[%d bytes]", e.MaxPacketSize))
|
||||
return strings.Join(ret, " ")
|
||||
}
|
||||
|
||||
type endpoint struct {
|
||||
h *libusbDevHandle
|
||||
|
||||
InterfaceSetting
|
||||
Desc EndpointDesc
|
||||
|
||||
ctx *Context
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the endpoint.
|
||||
func (e *endpoint) String() string {
|
||||
return e.Desc.String()
|
||||
}
|
||||
|
||||
func (e *endpoint) transfer(ctx context.Context, buf []byte) (int, error) {
|
||||
if len(buf) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
t, err := newUSBTransfer(e.ctx, e.h, &e.Desc, len(buf))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer t.free()
|
||||
if e.Desc.Direction == EndpointDirectionOut {
|
||||
copy(t.data(), buf)
|
||||
}
|
||||
|
||||
if err := t.submit(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n, err := t.wait(ctx)
|
||||
if e.Desc.Direction == EndpointDirectionIn {
|
||||
copy(buf, t.data())
|
||||
}
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// InEndpoint represents an IN endpoint open for transfer.
|
||||
// InEndpoint implements the io.Reader interface.
|
||||
// For high-throughput transfers, consider creating a bufffered read stream
|
||||
// through InEndpoint.ReadStream.
|
||||
type InEndpoint struct {
|
||||
*endpoint
|
||||
}
|
||||
|
||||
// Read reads data from an IN endpoint. Read returns number of bytes obtained
|
||||
// from the endpoint. Read may return non-zero length even if
|
||||
// the returned error is not nil (partial read).
|
||||
func (e *InEndpoint) Read(buf []byte) (int, error) {
|
||||
return e.transfer(context.Background(), buf)
|
||||
}
|
||||
|
||||
// ReadContext reads data from an IN endpoint. ReadContext returns number of
|
||||
// bytes obtained from the endpoint. ReadContext may return non-zero length
|
||||
// even if the returned error is not nil (partial read).
|
||||
// The passed context can be used to control the cancellation of the read. If
|
||||
// the context is cancelled, ReadContext will cancel the underlying transfers,
|
||||
// resulting in TransferCancelled error.
|
||||
func (e *InEndpoint) ReadContext(ctx context.Context, buf []byte) (int, error) {
|
||||
return e.transfer(ctx, buf)
|
||||
}
|
||||
|
||||
// OutEndpoint represents an OUT endpoint open for transfer.
|
||||
type OutEndpoint struct {
|
||||
*endpoint
|
||||
}
|
||||
|
||||
// Write writes data to an OUT endpoint. Write returns number of bytes comitted
|
||||
// to the endpoint. Write may return non-zero length even if the returned error
|
||||
// is not nil (partial write).
|
||||
func (e *OutEndpoint) Write(buf []byte) (int, error) {
|
||||
return e.transfer(context.Background(), buf)
|
||||
}
|
||||
|
||||
// WriteContext writes data to an OUT endpoint. WriteContext returns number of
|
||||
// bytes comitted to the endpoint. WriteContext may return non-zero length even
|
||||
// if the returned error is not nil (partial write).
|
||||
// The passed context can be used to control the cancellation of the write. If
|
||||
// the context is cancelled, WriteContext will cancel the underlying transfers,
|
||||
// resulting in TransferCancelled error.
|
||||
func (e *OutEndpoint) WriteContext(ctx context.Context, buf []byte) (int, error) {
|
||||
return e.transfer(ctx, buf)
|
||||
}
|
58
vendor/github.com/google/gousb/endpoint_stream.go
generated
vendored
Normal file
58
vendor/github.com/google/gousb/endpoint_stream.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2017 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
func (e *endpoint) newStream(size, count int) (*stream, error) {
|
||||
var ts []transferIntf
|
||||
for i := 0; i < count; i++ {
|
||||
t, err := newUSBTransfer(e.ctx, e.h, &e.Desc, size)
|
||||
if err != nil {
|
||||
for _, t := range ts {
|
||||
t.free()
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ts = append(ts, t)
|
||||
}
|
||||
return newStream(ts), nil
|
||||
}
|
||||
|
||||
// NewStream prepares a new read stream that will keep reading data from
|
||||
// the endpoint until closed or until an error or timeout is encountered.
|
||||
// Size defines a buffer size for a single read transaction and count
|
||||
// defines how many transactions should be active at any time.
|
||||
// By keeping multiple transfers active at the same time, a Stream reduces
|
||||
// the latency between subsequent transfers and increases reading throughput.
|
||||
func (e *InEndpoint) NewStream(size, count int) (*ReadStream, error) {
|
||||
s, err := e.newStream(size, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.submitAll()
|
||||
return &ReadStream{s: s}, nil
|
||||
}
|
||||
|
||||
// NewStream prepares a new write stream that will write data in the
|
||||
// background. Size defines a buffer size for a single write transaction and
|
||||
// count defines how many transactions may be active at any time. By buffering
|
||||
// the writes, a Stream reduces the latency between subsequent transfers and
|
||||
// increases writing throughput.
|
||||
func (e *OutEndpoint) NewStream(size, count int) (*WriteStream, error) {
|
||||
s, err := e.newStream(size, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &WriteStream{s: s}, nil
|
||||
}
|
110
vendor/github.com/google/gousb/error.go
generated
vendored
Normal file
110
vendor/github.com/google/gousb/error.go
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// #include <libusb.h>
|
||||
import "C"
|
||||
|
||||
// Error is an error code from a USB operation. See the list of Error constants below.
|
||||
type Error C.int
|
||||
|
||||
// Error implements the error interface.
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("libusb: %s [code %d]", errorString[e], e)
|
||||
}
|
||||
|
||||
func fromErrNo(errno C.int) error {
|
||||
err := Error(errno)
|
||||
if err == Success {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Defined result codes.
|
||||
const (
|
||||
Success Error = C.LIBUSB_SUCCESS
|
||||
ErrorIO Error = C.LIBUSB_ERROR_IO
|
||||
ErrorInvalidParam Error = C.LIBUSB_ERROR_INVALID_PARAM
|
||||
ErrorAccess Error = C.LIBUSB_ERROR_ACCESS
|
||||
ErrorNoDevice Error = C.LIBUSB_ERROR_NO_DEVICE
|
||||
ErrorNotFound Error = C.LIBUSB_ERROR_NOT_FOUND
|
||||
ErrorBusy Error = C.LIBUSB_ERROR_BUSY
|
||||
ErrorTimeout Error = C.LIBUSB_ERROR_TIMEOUT
|
||||
// ErrorOverflow indicates that the device tried to send more data than was
|
||||
// requested and that could fit in the packet buffer.
|
||||
ErrorOverflow Error = C.LIBUSB_ERROR_OVERFLOW
|
||||
ErrorPipe Error = C.LIBUSB_ERROR_PIPE
|
||||
ErrorInterrupted Error = C.LIBUSB_ERROR_INTERRUPTED
|
||||
ErrorNoMem Error = C.LIBUSB_ERROR_NO_MEM
|
||||
ErrorNotSupported Error = C.LIBUSB_ERROR_NOT_SUPPORTED
|
||||
ErrorOther Error = C.LIBUSB_ERROR_OTHER
|
||||
)
|
||||
|
||||
var errorString = map[Error]string{
|
||||
Success: "success",
|
||||
ErrorIO: "i/o error",
|
||||
ErrorInvalidParam: "invalid param",
|
||||
ErrorAccess: "bad access",
|
||||
ErrorNoDevice: "no device",
|
||||
ErrorNotFound: "not found",
|
||||
ErrorBusy: "device or resource busy",
|
||||
ErrorTimeout: "timeout",
|
||||
ErrorOverflow: "overflow",
|
||||
ErrorPipe: "pipe error",
|
||||
ErrorInterrupted: "interrupted",
|
||||
ErrorNoMem: "out of memory",
|
||||
ErrorNotSupported: "not supported",
|
||||
ErrorOther: "unknown error",
|
||||
}
|
||||
|
||||
// TransferStatus contains information about the result of a transfer.
|
||||
type TransferStatus uint8
|
||||
|
||||
// Defined Transfer status values.
|
||||
const (
|
||||
TransferCompleted TransferStatus = C.LIBUSB_TRANSFER_COMPLETED
|
||||
TransferError TransferStatus = C.LIBUSB_TRANSFER_ERROR
|
||||
TransferTimedOut TransferStatus = C.LIBUSB_TRANSFER_TIMED_OUT
|
||||
TransferCancelled TransferStatus = C.LIBUSB_TRANSFER_CANCELLED
|
||||
TransferStall TransferStatus = C.LIBUSB_TRANSFER_STALL
|
||||
TransferNoDevice TransferStatus = C.LIBUSB_TRANSFER_NO_DEVICE
|
||||
TransferOverflow TransferStatus = C.LIBUSB_TRANSFER_OVERFLOW
|
||||
)
|
||||
|
||||
var transferStatusDescription = map[TransferStatus]string{
|
||||
TransferCompleted: "transfer completed without error",
|
||||
TransferError: "transfer failed",
|
||||
TransferTimedOut: "transfer timed out",
|
||||
TransferCancelled: "transfer was cancelled",
|
||||
TransferStall: "halt condition detected (endpoint stalled) or control request not supported",
|
||||
TransferNoDevice: "device was disconnected",
|
||||
TransferOverflow: "device sent more data than requested",
|
||||
}
|
||||
|
||||
// String returns a human-readable transfer status.
|
||||
func (ts TransferStatus) String() string {
|
||||
return transferStatusDescription[ts]
|
||||
}
|
||||
|
||||
// Error implements the error interface.
|
||||
func (ts TransferStatus) Error() string {
|
||||
return ts.String()
|
||||
}
|
220
vendor/github.com/google/gousb/fakelibusb_devices.go
generated
vendored
Normal file
220
vendor/github.com/google/gousb/fakelibusb_devices.go
generated
vendored
Normal file
|
@ -0,0 +1,220 @@
|
|||
// Copyright 2017 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
// fake devices connected through the fakeLibusb stack.
|
||||
type fakeDevice struct {
|
||||
devDesc *DeviceDesc
|
||||
strDesc map[int]string
|
||||
alt uint8
|
||||
}
|
||||
|
||||
var fakeDevices = []fakeDevice{
|
||||
// Bus 001 Device 001: ID 9999:0001
|
||||
// One config, one interface, one setup,
|
||||
// two endpoints: 0x01 OUT, 0x82 IN.
|
||||
{
|
||||
devDesc: &DeviceDesc{
|
||||
Bus: 1,
|
||||
Address: 1,
|
||||
Port: 1,
|
||||
Spec: Version(2, 0),
|
||||
Device: Version(1, 0),
|
||||
Vendor: ID(0x9999),
|
||||
Product: ID(0x0001),
|
||||
Protocol: 255,
|
||||
Configs: map[int]ConfigDesc{1: {
|
||||
Number: 1,
|
||||
MaxPower: Milliamperes(100),
|
||||
Interfaces: []InterfaceDesc{{
|
||||
Number: 0,
|
||||
AltSettings: []InterfaceSetting{{
|
||||
Number: 0,
|
||||
Alternate: 0,
|
||||
Class: ClassVendorSpec,
|
||||
Endpoints: map[EndpointAddress]EndpointDesc{
|
||||
0x01: {
|
||||
Address: 0x01,
|
||||
Number: 1,
|
||||
Direction: EndpointDirectionOut,
|
||||
MaxPacketSize: 512,
|
||||
TransferType: TransferTypeBulk,
|
||||
},
|
||||
0x82: {
|
||||
Address: 0x82,
|
||||
Number: 2,
|
||||
Direction: EndpointDirectionIn,
|
||||
MaxPacketSize: 512,
|
||||
TransferType: TransferTypeBulk,
|
||||
},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
// Bus 001 Device 002: ID 8888:0002
|
||||
// One config, two interfaces. interface #0 with no endpoints,
|
||||
// interface #1 with two alt setups with different packet sizes for
|
||||
// endpoints. Two isochronous endpoints, 0x05 OUT and 0x86 OUT.
|
||||
{
|
||||
devDesc: &DeviceDesc{
|
||||
Bus: 1,
|
||||
Address: 2,
|
||||
Port: 2,
|
||||
Spec: Version(2, 0),
|
||||
Device: Version(1, 3),
|
||||
Vendor: ID(0x8888),
|
||||
Product: ID(0x0002),
|
||||
Protocol: 255,
|
||||
Configs: map[int]ConfigDesc{1: {
|
||||
Number: 1,
|
||||
MaxPower: Milliamperes(100),
|
||||
iConfiguration: 5,
|
||||
Interfaces: []InterfaceDesc{{
|
||||
Number: 0,
|
||||
AltSettings: []InterfaceSetting{{
|
||||
Number: 0,
|
||||
Alternate: 0,
|
||||
Class: ClassVendorSpec,
|
||||
iInterface: 6,
|
||||
}},
|
||||
}, {
|
||||
Number: 1,
|
||||
AltSettings: []InterfaceSetting{{
|
||||
Number: 1,
|
||||
Alternate: 0,
|
||||
Class: ClassVendorSpec,
|
||||
Endpoints: map[EndpointAddress]EndpointDesc{
|
||||
0x05: {
|
||||
Address: 0x05,
|
||||
Number: 5,
|
||||
Direction: EndpointDirectionOut,
|
||||
MaxPacketSize: 3 * 1024,
|
||||
TransferType: TransferTypeIsochronous,
|
||||
UsageType: IsoUsageTypeData,
|
||||
},
|
||||
0x86: {
|
||||
Address: 0x86,
|
||||
Number: 6,
|
||||
Direction: EndpointDirectionIn,
|
||||
MaxPacketSize: 3 * 1024,
|
||||
TransferType: TransferTypeIsochronous,
|
||||
UsageType: IsoUsageTypeData,
|
||||
},
|
||||
},
|
||||
iInterface: 7,
|
||||
}, {
|
||||
Number: 1,
|
||||
Alternate: 1,
|
||||
Class: ClassVendorSpec,
|
||||
Endpoints: map[EndpointAddress]EndpointDesc{
|
||||
0x05: {
|
||||
Address: 0x05,
|
||||
Number: 5,
|
||||
Direction: EndpointDirectionOut,
|
||||
MaxPacketSize: 2 * 1024,
|
||||
TransferType: TransferTypeIsochronous,
|
||||
},
|
||||
0x86: {
|
||||
Address: 0x86,
|
||||
Number: 6,
|
||||
Direction: EndpointDirectionIn,
|
||||
MaxPacketSize: 2 * 1024,
|
||||
TransferType: TransferTypeIsochronous,
|
||||
},
|
||||
},
|
||||
iInterface: 8,
|
||||
}, {
|
||||
Number: 1,
|
||||
Alternate: 2,
|
||||
Class: ClassVendorSpec,
|
||||
Endpoints: map[EndpointAddress]EndpointDesc{
|
||||
0x05: {
|
||||
Address: 0x05,
|
||||
Number: 5,
|
||||
Direction: EndpointDirectionIn,
|
||||
MaxPacketSize: 1024,
|
||||
TransferType: TransferTypeIsochronous,
|
||||
},
|
||||
0x86: {
|
||||
Address: 0x86,
|
||||
Number: 6,
|
||||
Direction: EndpointDirectionIn,
|
||||
MaxPacketSize: 1024,
|
||||
TransferType: TransferTypeIsochronous,
|
||||
},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
iManufacturer: 1,
|
||||
iProduct: 2,
|
||||
iSerialNumber: 3,
|
||||
},
|
||||
strDesc: map[int]string{
|
||||
1: "ACME Industries",
|
||||
2: "Fidgety Gadget",
|
||||
3: "01234567",
|
||||
5: "Weird configuration",
|
||||
6: "Boring setting",
|
||||
7: "Fast streaming",
|
||||
8: "Slower streaming",
|
||||
},
|
||||
},
|
||||
// Bus 001 Device 003: ID 9999:0002
|
||||
// One config, one interface, one setup,
|
||||
// two endpoints: 0x01 OUT, 0x81 IN.
|
||||
{
|
||||
devDesc: &DeviceDesc{
|
||||
Bus: 1,
|
||||
Address: 3,
|
||||
Port: 3,
|
||||
Spec: Version(2, 0),
|
||||
Device: Version(1, 0),
|
||||
Vendor: ID(0x1111),
|
||||
Product: ID(0x1111),
|
||||
Protocol: 255,
|
||||
Configs: map[int]ConfigDesc{1: {
|
||||
Number: 1,
|
||||
MaxPower: Milliamperes(100),
|
||||
Interfaces: []InterfaceDesc{{
|
||||
Number: 0,
|
||||
AltSettings: []InterfaceSetting{{
|
||||
Number: 0,
|
||||
Alternate: 0,
|
||||
Class: ClassVendorSpec,
|
||||
Endpoints: map[EndpointAddress]EndpointDesc{
|
||||
0x01: {
|
||||
Address: 0x01,
|
||||
Number: 1,
|
||||
Direction: EndpointDirectionOut,
|
||||
MaxPacketSize: 512,
|
||||
TransferType: TransferTypeBulk,
|
||||
},
|
||||
0x81: {
|
||||
Address: 0x81,
|
||||
Number: 1,
|
||||
Direction: EndpointDirectionIn,
|
||||
MaxPacketSize: 512,
|
||||
TransferType: TransferTypeBulk,
|
||||
},
|
||||
},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
29
vendor/github.com/google/gousb/fixlibusb_darwin.sh
generated
vendored
Executable file
29
vendor/github.com/google/gousb/fixlibusb_darwin.sh
generated
vendored
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
function die {
|
||||
echo "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
FILE="$1"
|
||||
if [[ -z "$FILE" ]]; then
|
||||
die "Usage: $0 <path to libusb.h>"
|
||||
fi
|
||||
|
||||
if [[ $(gcc --version | grep -i "llvm") == "" ]]; then
|
||||
die "Error: This change is unnecessary unless your gcc uses llvm"
|
||||
fi
|
||||
|
||||
BACKUP="${FILE}.orig"
|
||||
if [[ -f "$BACKUP" ]]; then
|
||||
die "It looks like you've already run this script ($BACKUP exists)"
|
||||
fi
|
||||
|
||||
cp $FILE $BACKUP || die "Could not create backup"
|
||||
|
||||
{
|
||||
echo 'H' # Turn on error printing
|
||||
echo 'g/\[0\].*non-standard/s/\[0\]/[1]/' # Use [1] instead of [0] so the size is unambiguous
|
||||
echo 'g/\[.\].*non-standard/p' # Print the lines changed
|
||||
echo 'w' # Write output
|
||||
} | ed $FILE
|
139
vendor/github.com/google/gousb/interface.go
generated
vendored
Normal file
139
vendor/github.com/google/gousb/interface.go
generated
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// InterfaceDesc contains information about a USB interface, extracted from
|
||||
// the descriptor.
|
||||
type InterfaceDesc struct {
|
||||
// Number is the number of this interface, a zero-based index in the array
|
||||
// of interfaces supported by the device configuration.
|
||||
Number int
|
||||
// AltSettings is a list of alternate settings supported by the interface.
|
||||
AltSettings []InterfaceSetting
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the interface descriptor and
|
||||
// its alternate settings.
|
||||
func (i InterfaceDesc) String() string {
|
||||
return fmt.Sprintf("Interface %d (%d alternate settings)", i.Number, len(i.AltSettings))
|
||||
}
|
||||
|
||||
// InterfaceSetting contains information about a USB interface with a particular
|
||||
// alternate setting, extracted from the descriptor.
|
||||
type InterfaceSetting struct {
|
||||
// Number is the number of this interface, the same as in InterfaceDesc.
|
||||
Number int
|
||||
// Alternate is the number of this alternate setting.
|
||||
Alternate int
|
||||
// Class is the USB-IF (Implementers Forum) class code, as defined by the USB spec.
|
||||
Class Class
|
||||
// SubClass is the USB-IF (Implementers Forum) subclass code, as defined by the USB spec.
|
||||
SubClass Class
|
||||
// Protocol is USB protocol code, as defined by the USB spe.c
|
||||
Protocol Protocol
|
||||
// Endpoints enumerates the endpoints available on this interface with
|
||||
// this alternate setting.
|
||||
Endpoints map[EndpointAddress]EndpointDesc
|
||||
|
||||
iInterface int // index of a string descriptor describing this interface.
|
||||
}
|
||||
|
||||
func (a InterfaceSetting) sortedEndpointIds() []string {
|
||||
var eps []string
|
||||
for _, ei := range a.Endpoints {
|
||||
eps = append(eps, fmt.Sprintf("%s(%d,%s)", ei.Address, ei.Number, ei.Direction))
|
||||
}
|
||||
sort.Strings(eps)
|
||||
return eps
|
||||
}
|
||||
|
||||
// String returns a human-readable description of the particular
|
||||
// alternate setting of an interface.
|
||||
func (a InterfaceSetting) String() string {
|
||||
return fmt.Sprintf("Interface %d alternate setting %d (available endpoints: %v)", a.Number, a.Alternate, a.sortedEndpointIds())
|
||||
}
|
||||
|
||||
// Interface is a representation of a claimed interface with a particular setting.
|
||||
// To access device endpoints use InEndpoint() and OutEndpoint() methods.
|
||||
// The interface should be Close()d after use.
|
||||
type Interface struct {
|
||||
Setting InterfaceSetting
|
||||
|
||||
config *Config
|
||||
}
|
||||
|
||||
func (i *Interface) String() string {
|
||||
return fmt.Sprintf("%s,if=%d,alt=%d", i.config, i.Setting.Number, i.Setting.Alternate)
|
||||
}
|
||||
|
||||
// Close releases the interface.
|
||||
func (i *Interface) Close() {
|
||||
if i.config == nil {
|
||||
return
|
||||
}
|
||||
i.config.dev.ctx.libusb.release(i.config.dev.handle, uint8(i.Setting.Number))
|
||||
i.config.mu.Lock()
|
||||
defer i.config.mu.Unlock()
|
||||
delete(i.config.claimed, i.Setting.Number)
|
||||
i.config = nil
|
||||
}
|
||||
|
||||
func (i *Interface) openEndpoint(epAddr EndpointAddress) (*endpoint, error) {
|
||||
var ep EndpointDesc
|
||||
ep, ok := i.Setting.Endpoints[epAddr]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s does not have endpoint with address %s. Available endpoints: %v", i, epAddr, i.Setting.sortedEndpointIds())
|
||||
}
|
||||
return &endpoint{
|
||||
InterfaceSetting: i.Setting,
|
||||
Desc: ep,
|
||||
h: i.config.dev.handle,
|
||||
ctx: i.config.dev.ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InEndpoint prepares an IN endpoint for transfer.
|
||||
func (i *Interface) InEndpoint(epNum int) (*InEndpoint, error) {
|
||||
if i.config == nil {
|
||||
return nil, fmt.Errorf("InEndpoint(%d) called on %s after Close", epNum, i)
|
||||
}
|
||||
ep, err := i.openEndpoint(EndpointAddress(0x80 | epNum))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &InEndpoint{
|
||||
endpoint: ep,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// OutEndpoint prepares an OUT endpoint for transfer.
|
||||
func (i *Interface) OutEndpoint(epNum int) (*OutEndpoint, error) {
|
||||
if i.config == nil {
|
||||
return nil, fmt.Errorf("OutEndpoint(%d) called on %s after Close", epNum, i)
|
||||
}
|
||||
ep, err := i.openEndpoint(EndpointAddress(epNum))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &OutEndpoint{
|
||||
endpoint: ep,
|
||||
}, nil
|
||||
}
|
511
vendor/github.com/google/gousb/libusb.go
generated
vendored
Normal file
511
vendor/github.com/google/gousb/libusb.go
generated
vendored
Normal file
|
@ -0,0 +1,511 @@
|
|||
// Copyright 2017 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
#cgo pkg-config: libusb-1.0
|
||||
#include <libusb.h>
|
||||
|
||||
int gousb_compact_iso_data(struct libusb_transfer *xfer, unsigned char *status);
|
||||
struct libusb_transfer *gousb_alloc_transfer_and_buffer(int bufLen, int numIsoPackets);
|
||||
void gousb_free_transfer_and_buffer(struct libusb_transfer *xfer);
|
||||
int submit(struct libusb_transfer *xfer);
|
||||
void gousb_set_debug(libusb_context *ctx, int lvl);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type libusbContext C.libusb_context
|
||||
type libusbDevice C.libusb_device
|
||||
type libusbDevHandle C.libusb_device_handle
|
||||
type libusbTransfer C.struct_libusb_transfer
|
||||
type libusbEndpoint C.struct_libusb_endpoint_descriptor
|
||||
|
||||
func (ep libusbEndpoint) endpointDesc(dev *DeviceDesc) EndpointDesc {
|
||||
ei := EndpointDesc{
|
||||
Address: EndpointAddress(ep.bEndpointAddress),
|
||||
Number: int(ep.bEndpointAddress & endpointNumMask),
|
||||
Direction: EndpointDirection((ep.bEndpointAddress & endpointDirectionMask) != 0),
|
||||
TransferType: TransferType(ep.bmAttributes & transferTypeMask),
|
||||
MaxPacketSize: int(ep.wMaxPacketSize),
|
||||
}
|
||||
if ei.TransferType == TransferTypeIsochronous {
|
||||
// bits 0-10 identify the packet size, bits 11-12 are the number of additional transactions per microframe.
|
||||
// Don't use libusb_get_max_iso_packet_size, as it has a bug where it returns the same value
|
||||
// regardless of alternative setting used, where different alternative settings might define different
|
||||
// max packet sizes.
|
||||
// See http://libusb.org/ticket/77 for more background.
|
||||
ei.MaxPacketSize = int(ep.wMaxPacketSize) & 0x07ff * (int(ep.wMaxPacketSize)>>11&3 + 1)
|
||||
ei.IsoSyncType = IsoSyncType(ep.bmAttributes & isoSyncTypeMask)
|
||||
switch ep.bmAttributes & usageTypeMask {
|
||||
case C.LIBUSB_ISO_USAGE_TYPE_DATA:
|
||||
ei.UsageType = IsoUsageTypeData
|
||||
case C.LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
|
||||
ei.UsageType = IsoUsageTypeFeedback
|
||||
case C.LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
|
||||
ei.UsageType = IsoUsageTypeImplicit
|
||||
}
|
||||
}
|
||||
switch {
|
||||
// If the device conforms to USB1.x:
|
||||
// Interval for polling endpoint for data transfers. Expressed in
|
||||
// milliseconds.
|
||||
// This field is ignored for bulk and control endpoints. For
|
||||
// isochronous endpoints this field must be set to 1. For interrupt
|
||||
// endpoints, this field may range from 1 to 255.
|
||||
// Note: in low-speed mode, isochronous transfers are not supported.
|
||||
case dev.Spec < Version(2, 0):
|
||||
ei.PollInterval = time.Duration(ep.bInterval) * time.Millisecond
|
||||
|
||||
// If the device conforms to USB[23].x and the device is in low or full
|
||||
// speed mode:
|
||||
// Interval for polling endpoint for data transfers. Expressed in
|
||||
// frames (1ms)
|
||||
// For full-speed isochronous endpoints, the value of this field should
|
||||
// be 1.
|
||||
// For full-/low-speed interrupt endpoints, the value of this field may
|
||||
// be from 1 to 255.
|
||||
// Note: in low-speed mode, isochronous transfers are not supported.
|
||||
case dev.Speed == SpeedUnknown || dev.Speed == SpeedLow || dev.Speed == SpeedFull:
|
||||
ei.PollInterval = time.Duration(ep.bInterval) * time.Millisecond
|
||||
|
||||
// If the device conforms to USB[23].x and the device is in high speed
|
||||
// mode:
|
||||
// Interval is expressed in microframe units (125 µs).
|
||||
// For high-speed bulk/control OUT endpoints, the bInterval must
|
||||
// specify the maximum NAK rate of the endpoint. A value of 0 indicates
|
||||
// the endpoint never NAKs. Other values indicate at most 1 NAK each
|
||||
// bInterval number of microframes. This value must be in the range
|
||||
// from 0 to 255.
|
||||
case dev.Speed == SpeedHigh && ei.TransferType == TransferTypeBulk:
|
||||
ei.PollInterval = time.Duration(ep.bInterval) * 125 * time.Microsecond
|
||||
|
||||
// If the device conforms to USB[23].x and the device is in high speed
|
||||
// mode:
|
||||
// For high-speed isochronous endpoints, this value must be in
|
||||
// the range from 1 to 16. The bInterval value is used as the exponent
|
||||
// for a 2bInterval-1 value; e.g., a bInterval of 4 means a period
|
||||
// of 8 (2^(4-1)).
|
||||
// For high-speed interrupt endpoints, the bInterval value is used as
|
||||
// the exponent for a 2bInterval-1 value; e.g., a bInterval of 4 means
|
||||
// a period of 8 (2^(4-1)). This value must be from 1 to 16.
|
||||
// If the device conforms to USB3.x and the device is in SuperSpeed mode:
|
||||
// Interval for servicing the endpoint for data transfers. Expressed in
|
||||
// 125-µs units.
|
||||
// For Enhanced SuperSpeed isochronous and interrupt endpoints, this
|
||||
// value shall be in the range from 1 to 16. However, the valid ranges
|
||||
// are 8 to 16 for Notification type Interrupt endpoints. The bInterval
|
||||
// value is used as the exponent for a 2(^bInterval-1) value; e.g., a
|
||||
// bInterval of 4 means a period of 8 (2^(4-1) → 2^3 → 8).
|
||||
// This field is reserved and shall not be used for Enhanced SuperSpeed
|
||||
// bulk or control endpoints.
|
||||
case dev.Speed == SpeedHigh || dev.Speed == SpeedSuper:
|
||||
ei.PollInterval = 125 * time.Microsecond << (ep.bInterval - 1)
|
||||
}
|
||||
return ei
|
||||
}
|
||||
|
||||
// libusbIntf is a set of trivial idiomatic Go wrappers around libusb C functions.
|
||||
// The underlying code is generally not testable or difficult to test,
|
||||
// since libusb interacts directly with the host USB stack.
|
||||
//
|
||||
// All functions here should operate on types defined on C.libusb* data types,
|
||||
// and occasionally on convenience data types (like TransferType or DeviceDesc).
|
||||
type libusbIntf interface {
|
||||
// context
|
||||
init() (*libusbContext, error)
|
||||
handleEvents(*libusbContext, <-chan struct{})
|
||||
getDevices(*libusbContext) ([]*libusbDevice, error)
|
||||
exit(*libusbContext) error
|
||||
setDebug(*libusbContext, int)
|
||||
|
||||
// device
|
||||
dereference(*libusbDevice)
|
||||
getDeviceDesc(*libusbDevice) (*DeviceDesc, error)
|
||||
open(*libusbDevice) (*libusbDevHandle, error)
|
||||
|
||||
close(*libusbDevHandle)
|
||||
reset(*libusbDevHandle) error
|
||||
control(*libusbDevHandle, time.Duration, uint8, uint8, uint16, uint16, []byte) (int, error)
|
||||
getConfig(*libusbDevHandle) (uint8, error)
|
||||
setConfig(*libusbDevHandle, uint8) error
|
||||
getStringDesc(*libusbDevHandle, int) (string, error)
|
||||
setAutoDetach(*libusbDevHandle, int) error
|
||||
detachKernelDriver(*libusbDevHandle, uint8) error
|
||||
|
||||
// interface
|
||||
claim(*libusbDevHandle, uint8) error
|
||||
release(*libusbDevHandle, uint8)
|
||||
setAlt(*libusbDevHandle, uint8, uint8) error
|
||||
|
||||
// transfer
|
||||
alloc(*libusbDevHandle, *EndpointDesc, int, int, chan struct{}) (*libusbTransfer, error)
|
||||
cancel(*libusbTransfer) error
|
||||
submit(*libusbTransfer) error
|
||||
buffer(*libusbTransfer) []byte
|
||||
data(*libusbTransfer) (int, TransferStatus)
|
||||
free(*libusbTransfer)
|
||||
setIsoPacketLengths(*libusbTransfer, uint32)
|
||||
}
|
||||
|
||||
// libusbImpl is an implementation of libusbIntf using real CGo-wrapped libusb.
|
||||
type libusbImpl struct{}
|
||||
|
||||
func (libusbImpl) init() (*libusbContext, error) {
|
||||
var ctx *C.libusb_context
|
||||
if err := fromErrNo(C.libusb_init(&ctx)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*libusbContext)(ctx), nil
|
||||
}
|
||||
|
||||
func (libusbImpl) handleEvents(c *libusbContext, done <-chan struct{}) {
|
||||
tv := C.struct_timeval{tv_usec: 100e3}
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
default:
|
||||
}
|
||||
if errno := C.libusb_handle_events_timeout_completed((*C.libusb_context)(c), &tv, nil); errno < 0 {
|
||||
log.Printf("handle_events: error: %s", Error(errno))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (libusbImpl) getDevices(ctx *libusbContext) ([]*libusbDevice, error) {
|
||||
var list **C.libusb_device
|
||||
cnt := C.libusb_get_device_list((*C.libusb_context)(ctx), &list)
|
||||
if cnt < 0 {
|
||||
return nil, fromErrNo(C.int(cnt))
|
||||
}
|
||||
var devs []*C.libusb_device
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&devs)) = reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(list)),
|
||||
Len: int(cnt),
|
||||
Cap: int(cnt),
|
||||
}
|
||||
var ret []*libusbDevice
|
||||
for _, d := range devs {
|
||||
ret = append(ret, (*libusbDevice)(d))
|
||||
}
|
||||
// devices will be dereferenced later, during close.
|
||||
C.libusb_free_device_list(list, 0)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (libusbImpl) exit(c *libusbContext) error {
|
||||
C.libusb_exit((*C.libusb_context)(c))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (libusbImpl) setDebug(c *libusbContext, lvl int) {
|
||||
C.gousb_set_debug((*C.libusb_context)(c), C.int(lvl))
|
||||
}
|
||||
|
||||
func (libusbImpl) getDeviceDesc(d *libusbDevice) (*DeviceDesc, error) {
|
||||
var desc C.struct_libusb_device_descriptor
|
||||
if err := fromErrNo(C.libusb_get_device_descriptor((*C.libusb_device)(d), &desc)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dev := &DeviceDesc{
|
||||
Bus: int(C.libusb_get_bus_number((*C.libusb_device)(d))),
|
||||
Address: int(C.libusb_get_device_address((*C.libusb_device)(d))),
|
||||
Port: int(C.libusb_get_port_number((*C.libusb_device)(d))),
|
||||
Speed: Speed(C.libusb_get_device_speed((*C.libusb_device)(d))),
|
||||
Spec: BCD(desc.bcdUSB),
|
||||
Device: BCD(desc.bcdDevice),
|
||||
Vendor: ID(desc.idVendor),
|
||||
Product: ID(desc.idProduct),
|
||||
Class: Class(desc.bDeviceClass),
|
||||
SubClass: Class(desc.bDeviceSubClass),
|
||||
Protocol: Protocol(desc.bDeviceProtocol),
|
||||
MaxControlPacketSize: int(desc.bMaxPacketSize0),
|
||||
iManufacturer: int(desc.iManufacturer),
|
||||
iProduct: int(desc.iProduct),
|
||||
iSerialNumber: int(desc.iSerialNumber),
|
||||
}
|
||||
// Enumerate configurations
|
||||
cfgs := make(map[int]ConfigDesc)
|
||||
for i := 0; i < int(desc.bNumConfigurations); i++ {
|
||||
var cfg *C.struct_libusb_config_descriptor
|
||||
if err := fromErrNo(C.libusb_get_config_descriptor((*C.libusb_device)(d), C.uint8_t(i), &cfg)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := ConfigDesc{
|
||||
Number: int(cfg.bConfigurationValue),
|
||||
SelfPowered: (cfg.bmAttributes & selfPoweredMask) != 0,
|
||||
RemoteWakeup: (cfg.bmAttributes & remoteWakeupMask) != 0,
|
||||
MaxPower: 2 * Milliamperes(cfg.MaxPower),
|
||||
iConfiguration: int(cfg.iConfiguration),
|
||||
}
|
||||
// at GenX speeds MaxPower is expressed in units of 8mA, not 2mA.
|
||||
if dev.Speed == SpeedSuper {
|
||||
c.MaxPower *= 4
|
||||
}
|
||||
|
||||
var ifaces []C.struct_libusb_interface
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&ifaces)) = reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(cfg._interface)),
|
||||
Len: int(cfg.bNumInterfaces),
|
||||
Cap: int(cfg.bNumInterfaces),
|
||||
}
|
||||
c.Interfaces = make([]InterfaceDesc, 0, len(ifaces))
|
||||
for ifNum, iface := range ifaces {
|
||||
if iface.num_altsetting == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var alts []C.struct_libusb_interface_descriptor
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&alts)) = reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(iface.altsetting)),
|
||||
Len: int(iface.num_altsetting),
|
||||
Cap: int(iface.num_altsetting),
|
||||
}
|
||||
descs := make([]InterfaceSetting, 0, len(alts))
|
||||
for altNum, alt := range alts {
|
||||
i := InterfaceSetting{
|
||||
Number: int(alt.bInterfaceNumber),
|
||||
Alternate: int(alt.bAlternateSetting),
|
||||
Class: Class(alt.bInterfaceClass),
|
||||
SubClass: Class(alt.bInterfaceSubClass),
|
||||
Protocol: Protocol(alt.bInterfaceProtocol),
|
||||
iInterface: int(alt.iInterface),
|
||||
}
|
||||
if ifNum != i.Number {
|
||||
return nil, fmt.Errorf("config %d interface at index %d has number %d, USB standard states they should be identical", c.Number, ifNum, i.Number)
|
||||
}
|
||||
if altNum != i.Alternate {
|
||||
return nil, fmt.Errorf("config %d interface %d alternate settings at index %d has number %d, USB standard states they should be identical", c.Number, i.Number, altNum, i.Alternate)
|
||||
}
|
||||
var ends []C.struct_libusb_endpoint_descriptor
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&ends)) = reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(alt.endpoint)),
|
||||
Len: int(alt.bNumEndpoints),
|
||||
Cap: int(alt.bNumEndpoints),
|
||||
}
|
||||
i.Endpoints = make(map[EndpointAddress]EndpointDesc, len(ends))
|
||||
for _, end := range ends {
|
||||
epi := libusbEndpoint(end).endpointDesc(dev)
|
||||
i.Endpoints[epi.Address] = epi
|
||||
}
|
||||
descs = append(descs, i)
|
||||
}
|
||||
c.Interfaces = append(c.Interfaces, InterfaceDesc{
|
||||
Number: descs[0].Number,
|
||||
AltSettings: descs,
|
||||
})
|
||||
}
|
||||
C.libusb_free_config_descriptor(cfg)
|
||||
cfgs[c.Number] = c
|
||||
}
|
||||
|
||||
dev.Configs = cfgs
|
||||
return dev, nil
|
||||
}
|
||||
|
||||
func (libusbImpl) dereference(d *libusbDevice) {
|
||||
C.libusb_unref_device((*C.libusb_device)(d))
|
||||
}
|
||||
|
||||
func (libusbImpl) open(d *libusbDevice) (*libusbDevHandle, error) {
|
||||
var handle *C.libusb_device_handle
|
||||
if err := fromErrNo(C.libusb_open((*C.libusb_device)(d), &handle)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (*libusbDevHandle)(handle), nil
|
||||
}
|
||||
|
||||
func (libusbImpl) close(d *libusbDevHandle) {
|
||||
C.libusb_close((*C.libusb_device_handle)(d))
|
||||
}
|
||||
|
||||
func (libusbImpl) reset(d *libusbDevHandle) error {
|
||||
return fromErrNo(C.libusb_reset_device((*C.libusb_device_handle)(d)))
|
||||
}
|
||||
|
||||
func (libusbImpl) control(d *libusbDevHandle, timeout time.Duration, rType, request uint8, val, idx uint16, data []byte) (int, error) {
|
||||
dataSlice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||
n := C.libusb_control_transfer(
|
||||
(*C.libusb_device_handle)(d),
|
||||
C.uint8_t(rType),
|
||||
C.uint8_t(request),
|
||||
C.uint16_t(val),
|
||||
C.uint16_t(idx),
|
||||
(*C.uchar)(unsafe.Pointer(dataSlice.Data)),
|
||||
C.uint16_t(len(data)),
|
||||
C.uint(timeout/time.Millisecond))
|
||||
if n < 0 {
|
||||
return int(n), fromErrNo(n)
|
||||
}
|
||||
return int(n), nil
|
||||
}
|
||||
|
||||
func (libusbImpl) getConfig(d *libusbDevHandle) (uint8, error) {
|
||||
var cfg C.int
|
||||
if errno := C.libusb_get_configuration((*C.libusb_device_handle)(d), &cfg); errno < 0 {
|
||||
return 0, fromErrNo(errno)
|
||||
}
|
||||
return uint8(cfg), nil
|
||||
}
|
||||
|
||||
func (libusbImpl) setConfig(d *libusbDevHandle, cfg uint8) error {
|
||||
return fromErrNo(C.libusb_set_configuration((*C.libusb_device_handle)(d), C.int(cfg)))
|
||||
}
|
||||
|
||||
// TODO(sebek): device string descriptors are natively in UTF16 and support
|
||||
// multiple languages. get_string_descriptor_ascii uses always the first
|
||||
// language and discards non-ascii bytes. We could do better if needed.
|
||||
func (libusbImpl) getStringDesc(d *libusbDevHandle, index int) (string, error) {
|
||||
// allocate 200-byte array limited the length of string descriptor
|
||||
buf := make([]byte, 200)
|
||||
// get string descriptor from libusb. if errno < 0 then there are any errors.
|
||||
// if errno >= 0; it is a length of result string descriptor
|
||||
errno := C.libusb_get_string_descriptor_ascii(
|
||||
(*C.libusb_device_handle)(d),
|
||||
C.uint8_t(index),
|
||||
(*C.uchar)(unsafe.Pointer(&buf[0])),
|
||||
200)
|
||||
if errno < 0 {
|
||||
return "", fmt.Errorf("failed to get string descriptor %d: %s", index, fromErrNo(errno))
|
||||
}
|
||||
return string(buf[:errno]), nil
|
||||
}
|
||||
|
||||
func (libusbImpl) setAutoDetach(d *libusbDevHandle, val int) error {
|
||||
err := fromErrNo(C.libusb_set_auto_detach_kernel_driver((*C.libusb_device_handle)(d), C.int(val)))
|
||||
if err != nil && err != ErrorNotSupported {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (libusbImpl) detachKernelDriver(d *libusbDevHandle, iface uint8) error {
|
||||
err := fromErrNo(C.libusb_detach_kernel_driver((*C.libusb_device_handle)(d), C.int(iface)))
|
||||
if err != nil && err != ErrorNotSupported && err != ErrorNotFound {
|
||||
// ErrorNotSupported is returned in non linux systems
|
||||
// ErrorNotFound is returned if libusb's driver is already attached to the device
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (libusbImpl) claim(d *libusbDevHandle, iface uint8) error {
|
||||
return fromErrNo(C.libusb_claim_interface((*C.libusb_device_handle)(d), C.int(iface)))
|
||||
}
|
||||
|
||||
func (libusbImpl) release(d *libusbDevHandle, iface uint8) {
|
||||
C.libusb_release_interface((*C.libusb_device_handle)(d), C.int(iface))
|
||||
}
|
||||
|
||||
func (libusbImpl) setAlt(d *libusbDevHandle, iface, setup uint8) error {
|
||||
return fromErrNo(C.libusb_set_interface_alt_setting((*C.libusb_device_handle)(d), C.int(iface), C.int(setup)))
|
||||
}
|
||||
|
||||
func (libusbImpl) alloc(d *libusbDevHandle, ep *EndpointDesc, isoPackets int, bufLen int, done chan struct{}) (*libusbTransfer, error) {
|
||||
xfer := C.gousb_alloc_transfer_and_buffer(C.int(bufLen), C.int(isoPackets))
|
||||
if xfer == nil {
|
||||
return nil, fmt.Errorf("gousb_alloc_transfer_and_buffer(%d, %d) failed", bufLen, isoPackets)
|
||||
}
|
||||
if int(xfer.length) != bufLen {
|
||||
return nil, fmt.Errorf("gousb_alloc_transfer_and_buffer(%d, %d): length = %d, want %d", bufLen, isoPackets, xfer.length, bufLen)
|
||||
}
|
||||
xfer.dev_handle = (*C.libusb_device_handle)(d)
|
||||
xfer.endpoint = C.uchar(ep.Address)
|
||||
xfer._type = C.uchar(ep.TransferType)
|
||||
xfer.num_iso_packets = C.int(isoPackets)
|
||||
ret := (*libusbTransfer)(xfer)
|
||||
xferDoneMap.Lock()
|
||||
xferDoneMap.m[ret] = done
|
||||
xferDoneMap.Unlock()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (libusbImpl) cancel(t *libusbTransfer) error {
|
||||
return fromErrNo(C.libusb_cancel_transfer((*C.struct_libusb_transfer)(t)))
|
||||
}
|
||||
|
||||
func (libusbImpl) submit(t *libusbTransfer) error {
|
||||
return fromErrNo(C.submit((*C.struct_libusb_transfer)(t)))
|
||||
}
|
||||
|
||||
func (libusbImpl) buffer(t *libusbTransfer) []byte {
|
||||
// TODO(go1.10?): replace with more user-friendly construct once
|
||||
// one exists. https://github.com/golang/go/issues/13656
|
||||
var ret []byte
|
||||
*(*reflect.SliceHeader)(unsafe.Pointer(&ret)) = reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(t.buffer)),
|
||||
Len: int(t.length),
|
||||
Cap: int(t.length),
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (libusbImpl) data(t *libusbTransfer) (int, TransferStatus) {
|
||||
if TransferType(t._type) == TransferTypeIsochronous {
|
||||
var status TransferStatus
|
||||
n := int(C.gousb_compact_iso_data((*C.struct_libusb_transfer)(t), (*C.uchar)(unsafe.Pointer(&status))))
|
||||
return n, status
|
||||
}
|
||||
return int(t.actual_length), TransferStatus(t.status)
|
||||
}
|
||||
|
||||
func (libusbImpl) free(t *libusbTransfer) {
|
||||
xferDoneMap.Lock()
|
||||
delete(xferDoneMap.m, t)
|
||||
xferDoneMap.Unlock()
|
||||
C.gousb_free_transfer_and_buffer((*C.struct_libusb_transfer)(t))
|
||||
}
|
||||
|
||||
func (libusbImpl) setIsoPacketLengths(t *libusbTransfer, length uint32) {
|
||||
C.libusb_set_iso_packet_lengths((*C.struct_libusb_transfer)(t), C.uint(length))
|
||||
}
|
||||
|
||||
// xferDoneMap keeps a map of done callback channels for all allocated transfers.
|
||||
var xferDoneMap = struct {
|
||||
m map[*libusbTransfer]chan struct{}
|
||||
sync.RWMutex
|
||||
}{
|
||||
m: make(map[*libusbTransfer]chan struct{}),
|
||||
}
|
||||
|
||||
//export xferCallback
|
||||
func xferCallback(xfer *C.struct_libusb_transfer) {
|
||||
xferDoneMap.RLock()
|
||||
ch := xferDoneMap.m[(*libusbTransfer)(xfer)]
|
||||
xferDoneMap.RUnlock()
|
||||
ch <- struct{}{}
|
||||
}
|
||||
|
||||
// for benchmarking of method on implementation vs vanilla function.
|
||||
func libusbSetDebug(c *libusbContext, lvl int) {
|
||||
C.gousb_set_debug((*C.libusb_context)(c), C.int(lvl))
|
||||
}
|
||||
|
||||
func newDevicePointer() *libusbDevice {
|
||||
return (*libusbDevice)(unsafe.Pointer(C.malloc(1)))
|
||||
}
|
||||
|
||||
func newFakeTransferPointer() *libusbTransfer {
|
||||
return (*libusbTransfer)(unsafe.Pointer(C.malloc(1)))
|
||||
}
|
57
vendor/github.com/google/gousb/misc.go
generated
vendored
Normal file
57
vendor/github.com/google/gousb/misc.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// BCD is a binary-coded decimal version number. Its first 8 bits represent
|
||||
// the major version number, its last 8 bits represent the minor version number.
|
||||
// Major and minor are composed of 4+4 bits, where each 4 bits represents
|
||||
// a decimal digit.
|
||||
// Example: BCD(0x1234) means major 12 (decimal) and minor 34 (decimal).
|
||||
type BCD uint16
|
||||
|
||||
// Major is the major number of the BCD.
|
||||
func (s BCD) Major() uint8 {
|
||||
maj := uint8(s >> 8)
|
||||
return 10*(maj>>4) + maj&0x0f
|
||||
}
|
||||
|
||||
// Minor is the minor number of the BCD.
|
||||
func (s BCD) Minor() uint8 {
|
||||
min := uint8(s & 0xff)
|
||||
return 10*(min>>4) + min&0x0f
|
||||
}
|
||||
|
||||
// String returns a dotted representation of the BCD (major.minor).
|
||||
func (s BCD) String() string {
|
||||
return fmt.Sprintf("%d.%02d", s.Major(), s.Minor())
|
||||
}
|
||||
|
||||
// Version returns a BCD version number with given major/minor.
|
||||
func Version(major, minor uint8) BCD {
|
||||
return (BCD(major)/10)<<12 | (BCD(major)%10)<<8 | (BCD(minor)/10)<<4 | BCD(minor)%10
|
||||
}
|
||||
|
||||
// ID represents a vendor or product ID.
|
||||
type ID uint16
|
||||
|
||||
// String returns a hexadecimal ID.
|
||||
func (id ID) String() string {
|
||||
return fmt.Sprintf("%04x", int(id))
|
||||
}
|
100
vendor/github.com/google/gousb/transfer.c
generated
vendored
Normal file
100
vendor/github.com/google/gousb/transfer.c
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <libusb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void print_xfer(struct libusb_transfer *xfer);
|
||||
void xferCallback(struct libusb_transfer*);
|
||||
|
||||
int submit(struct libusb_transfer *xfer) {
|
||||
xfer->callback = (libusb_transfer_cb_fn)(&xferCallback);
|
||||
xfer->status = -1;
|
||||
return libusb_submit_transfer(xfer);
|
||||
}
|
||||
|
||||
void print_xfer(struct libusb_transfer *xfer) {
|
||||
int i;
|
||||
|
||||
printf("Transfer:\n");
|
||||
printf(" dev_handle: %p\n", xfer->dev_handle);
|
||||
printf(" flags: %08x\n", xfer->flags);
|
||||
printf(" endpoint: %x\n", xfer->endpoint);
|
||||
printf(" type: %x\n", xfer->type);
|
||||
printf(" timeout: %dms\n", xfer->timeout);
|
||||
printf(" status: %x\n", xfer->status);
|
||||
printf(" length: %d (act: %d)\n", xfer->length, xfer->actual_length);
|
||||
printf(" callback: %p\n", xfer->callback);
|
||||
printf(" user_data: %p\n", xfer->user_data);
|
||||
printf(" buffer: %p\n", xfer->buffer);
|
||||
printf(" num_iso_pkts: %d\n", xfer->num_iso_packets);
|
||||
printf(" packets:\n");
|
||||
for (i = 0; i < xfer->num_iso_packets; i++) {
|
||||
printf(" [%04d] %d (act: %d) %x\n", i,
|
||||
xfer->iso_packet_desc[i].length,
|
||||
xfer->iso_packet_desc[i].actual_length,
|
||||
xfer->iso_packet_desc[i].status);
|
||||
}
|
||||
}
|
||||
|
||||
// compact the data in an isochronous transfer. The contents of individual
|
||||
// iso packets are shifted left, so that no gaps are left between them.
|
||||
// Status is set to the first non-zero status of an iso packet.
|
||||
int gousb_compact_iso_data(struct libusb_transfer *xfer, unsigned char *status) {
|
||||
int i;
|
||||
int sum = 0;
|
||||
unsigned char *in = xfer->buffer;
|
||||
unsigned char *out = xfer->buffer;
|
||||
for (i = 0; i < xfer->num_iso_packets; i++) {
|
||||
struct libusb_iso_packet_descriptor pkt = xfer->iso_packet_desc[i];
|
||||
if (pkt.status != 0) {
|
||||
*status = pkt.status;
|
||||
break;
|
||||
}
|
||||
// Copy the data
|
||||
int len = pkt.actual_length;
|
||||
memmove(out, in, len);
|
||||
// Increment offsets
|
||||
sum += len;
|
||||
in += pkt.length;
|
||||
out += len;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
// allocates a libusb transfer and a buffer for packet data.
|
||||
struct libusb_transfer *gousb_alloc_transfer_and_buffer(int bufLen, int isoPackets) {
|
||||
struct libusb_transfer *xfer = libusb_alloc_transfer(isoPackets);
|
||||
if (xfer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
xfer->buffer = (unsigned char*)malloc(bufLen);
|
||||
if (xfer->buffer == NULL) {
|
||||
libusb_free_transfer(xfer);
|
||||
return NULL;
|
||||
}
|
||||
xfer->length = bufLen;
|
||||
return xfer;
|
||||
}
|
||||
|
||||
// frees a libusb transfer and its buffer. The buffer of the given
|
||||
// libusb_transfer must have been allocated with alloc_transfer_and_buffer.
|
||||
void gousb_free_transfer_and_buffer(struct libusb_transfer *xfer) {
|
||||
free(xfer->buffer);
|
||||
xfer->length = 0;
|
||||
libusb_free_transfer(xfer);
|
||||
}
|
160
vendor/github.com/google/gousb/transfer.go
generated
vendored
Normal file
160
vendor/github.com/google/gousb/transfer.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type usbTransfer struct {
|
||||
// mu protects the transfer state.
|
||||
mu sync.Mutex
|
||||
// xfer is the allocated libusb_transfer.
|
||||
xfer *libusbTransfer
|
||||
// buf is the buffer allocated for the transfer. The underlying memory
|
||||
// is allocated by the C code, both buf and xfer.buffer point to the same
|
||||
// memory.
|
||||
buf []byte
|
||||
// done is blocking until the transfer is complete and data and transfer
|
||||
// status are available.
|
||||
done chan struct{}
|
||||
// submitted is true if submit() was called on this transfer.
|
||||
submitted bool
|
||||
// ctx is the Context that created this transfer.
|
||||
ctx *Context
|
||||
}
|
||||
|
||||
// submits the transfer. After submit() the transfer is in flight and is owned by libusb.
|
||||
// It's not safe to access the contents of the transfer until wait() returns.
|
||||
// Once wait() returns, it's ok to re-use the same transfer structure by calling submit() again.
|
||||
func (t *usbTransfer) submit() error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.submitted {
|
||||
return errors.New("transfer was already submitted and is not finished yet")
|
||||
}
|
||||
if err := t.ctx.libusb.submit(t.xfer); err != nil {
|
||||
return err
|
||||
}
|
||||
t.submitted = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// waits for libusb to signal the release of transfer data.
|
||||
// After wait returns, the transfer contents are safe to access
|
||||
// via t.buf. The number returned by wait indicates how many bytes
|
||||
// of the buffer were read or written by libusb, and it can be
|
||||
// smaller than the length of t.buf.
|
||||
func (t *usbTransfer) wait(ctx context.Context) (n int, err error) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if !t.submitted {
|
||||
return 0, nil
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.ctx.libusb.cancel(t.xfer)
|
||||
// after the transfer is cancelled, it will run a callback
|
||||
// that triggers the activation of t.done.
|
||||
<-t.done
|
||||
case <-t.done:
|
||||
}
|
||||
t.submitted = false
|
||||
n, status := t.ctx.libusb.data(t.xfer)
|
||||
if status != TransferCompleted {
|
||||
return n, status
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// cancel aborts a submitted transfer. The transfer is cancelled
|
||||
// asynchronously and the user still needs to wait() to return.
|
||||
func (t *usbTransfer) cancel() error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if !t.submitted {
|
||||
return nil
|
||||
}
|
||||
err := t.ctx.libusb.cancel(t.xfer)
|
||||
if err == ErrorNotFound {
|
||||
// transfer already completed
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// free releases the memory allocated for the transfer.
|
||||
// free should be called only if the transfer is not used by libusb,
|
||||
// i.e. it should not be called after submit() and before wait() returns.
|
||||
func (t *usbTransfer) free() error {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.submitted {
|
||||
return errors.New("free() cannot be called on a submitted transfer until wait() returns")
|
||||
}
|
||||
if t.xfer == nil {
|
||||
return nil
|
||||
}
|
||||
t.ctx.libusb.free(t.xfer)
|
||||
t.xfer = nil
|
||||
t.buf = nil
|
||||
t.done = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// data returns the slice containing transfer buffer.
|
||||
func (t *usbTransfer) data() []byte {
|
||||
return t.buf
|
||||
}
|
||||
|
||||
// newUSBTransfer allocates a new transfer structure and a new buffer for
|
||||
// communication with a given device/endpoint.
|
||||
func newUSBTransfer(ctx *Context, dev *libusbDevHandle, ei *EndpointDesc, bufLen int) (*usbTransfer, error) {
|
||||
var isoPackets, isoPktSize int
|
||||
if ei.TransferType == TransferTypeIsochronous {
|
||||
isoPktSize = ei.MaxPacketSize
|
||||
if bufLen < isoPktSize {
|
||||
isoPktSize = bufLen
|
||||
}
|
||||
isoPackets = bufLen / isoPktSize
|
||||
debug.Printf("New isochronous transfer - buffer length %d, using %d packets of %d bytes each", bufLen, isoPackets, isoPktSize)
|
||||
}
|
||||
|
||||
done := make(chan struct{}, 1)
|
||||
xfer, err := ctx.libusb.alloc(dev, ei, isoPackets, bufLen, done)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ei.TransferType == TransferTypeIsochronous {
|
||||
ctx.libusb.setIsoPacketLengths(xfer, uint32(isoPktSize))
|
||||
}
|
||||
|
||||
t := &usbTransfer{
|
||||
xfer: xfer,
|
||||
buf: ctx.libusb.buffer(xfer),
|
||||
done: done,
|
||||
ctx: ctx,
|
||||
}
|
||||
runtime.SetFinalizer(t, func(t *usbTransfer) {
|
||||
t.cancel()
|
||||
t.wait(context.Background())
|
||||
t.free()
|
||||
})
|
||||
return t, nil
|
||||
}
|
314
vendor/github.com/google/gousb/transfer_stream.go
generated
vendored
Normal file
314
vendor/github.com/google/gousb/transfer_stream.go
generated
vendored
Normal file
|
@ -0,0 +1,314 @@
|
|||
// Copyright 2017 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gousb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
type transferIntf interface {
|
||||
submit() error
|
||||
cancel() error
|
||||
wait(context.Context) (int, error)
|
||||
free() error
|
||||
data() []byte
|
||||
}
|
||||
|
||||
type stream struct {
|
||||
// a fifo of USB transfers.
|
||||
transfers chan transferIntf
|
||||
// err is the first encountered error, returned to the user.
|
||||
err error
|
||||
// finished is true if transfers has been already closed.
|
||||
finished bool
|
||||
}
|
||||
|
||||
func (s *stream) gotError(err error) {
|
||||
if s.err == nil {
|
||||
s.err = err
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stream) noMore() {
|
||||
if !s.finished {
|
||||
close(s.transfers)
|
||||
s.finished = true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stream) submitAll() {
|
||||
count := len(s.transfers)
|
||||
var all []transferIntf
|
||||
for i := 0; i < count; i++ {
|
||||
all = append(all, <-s.transfers)
|
||||
}
|
||||
for _, t := range all {
|
||||
if err := t.submit(); err != nil {
|
||||
t.free()
|
||||
s.gotError(err)
|
||||
s.noMore()
|
||||
return
|
||||
}
|
||||
s.transfers <- t
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *stream) flushRemaining() {
|
||||
s.noMore()
|
||||
for t := range s.transfers {
|
||||
t.cancel()
|
||||
t.wait(context.Background())
|
||||
t.free()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stream) done() {
|
||||
if s.err == nil {
|
||||
close(s.transfers)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadStream is a buffer that tries to prefetch data from the IN endpoint,
|
||||
// reducing the latency between subsequent Read()s.
|
||||
// ReadStream keeps prefetching data until Close() is called or until
|
||||
// an error is encountered. After Close(), the buffer might still have
|
||||
// data left from transfers that were initiated before Close. Read()ing
|
||||
// from the ReadStream will keep returning available data. When no more
|
||||
// data is left, io.EOF is returned.
|
||||
type ReadStream struct {
|
||||
s *stream
|
||||
// current holds the last transfer to return.
|
||||
current transferIntf
|
||||
// total/used are the number of all/used bytes in the current transfer.
|
||||
total, used int
|
||||
}
|
||||
|
||||
// Read reads data from the transfer stream.
|
||||
// The data will come from at most a single transfer, so the returned number
|
||||
// might be smaller than the length of p.
|
||||
// After a non-nil error is returned, all subsequent attempts to read will
|
||||
// return io.ErrClosedPipe.
|
||||
// Read cannot be called concurrently with other Read, ReadContext
|
||||
// or Close.
|
||||
func (r *ReadStream) Read(p []byte) (int, error) {
|
||||
return r.ReadContext(context.Background(), p)
|
||||
}
|
||||
|
||||
// ReadContext reads data from the transfer stream.
|
||||
// The data will come from at most a single transfer, so the returned number
|
||||
// might be smaller than the length of p.
|
||||
// After a non-nil error is returned, all subsequent attempts to read will
|
||||
// return io.ErrClosedPipe.
|
||||
// ReadContext cannot be called concurrently with other Read, ReadContext
|
||||
// or Close.
|
||||
// The context passed controls the cancellation of this particular read
|
||||
// operation within the stream. The semantics is identical to
|
||||
// Endpoint.ReadContext.
|
||||
func (r *ReadStream) ReadContext(ctx context.Context, p []byte) (int, error) {
|
||||
if r.s.transfers == nil {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
if r.current == nil {
|
||||
t, ok := <-r.s.transfers
|
||||
if !ok {
|
||||
// no more transfers in flight
|
||||
r.s.transfers = nil
|
||||
return 0, r.s.err
|
||||
}
|
||||
n, err := t.wait(ctx)
|
||||
if err != nil {
|
||||
// wait error aborts immediately, all remaining data is invalid.
|
||||
t.free()
|
||||
r.s.flushRemaining()
|
||||
r.s.transfers = nil
|
||||
return n, err
|
||||
}
|
||||
r.current = t
|
||||
r.total = n
|
||||
r.used = 0
|
||||
}
|
||||
use := r.total - r.used
|
||||
if use > len(p) {
|
||||
use = len(p)
|
||||
}
|
||||
copy(p, r.current.data()[r.used:r.used+use])
|
||||
r.used += use
|
||||
if r.used == r.total {
|
||||
if r.s.err == nil {
|
||||
if err := r.current.submit(); err == nil {
|
||||
// guaranteed to not block, len(transfers) == number of allocated transfers
|
||||
r.s.transfers <- r.current
|
||||
} else {
|
||||
r.s.gotError(err)
|
||||
r.s.noMore()
|
||||
}
|
||||
}
|
||||
if r.s.err != nil {
|
||||
r.current.free()
|
||||
}
|
||||
r.current = nil
|
||||
}
|
||||
return use, nil
|
||||
}
|
||||
|
||||
// Close signals that the transfer should stop. After Close is called,
|
||||
// subsequent Read()s will return data from all transfers that were already
|
||||
// in progress before returning an io.EOF error, unless another error
|
||||
// was encountered earlier.
|
||||
// Close cannot be called concurrently with Read.
|
||||
func (r *ReadStream) Close() error {
|
||||
if r.s.transfers == nil {
|
||||
return nil
|
||||
}
|
||||
r.s.gotError(io.EOF)
|
||||
r.s.noMore()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteStream is a buffer that will send data asynchronously, reducing
|
||||
// the latency between subsequent Write()s.
|
||||
type WriteStream struct {
|
||||
s *stream
|
||||
total int
|
||||
}
|
||||
|
||||
// Write sends the data to the endpoint. Write returning a nil error doesn't
|
||||
// mean that data was written to the device, only that it was written to the
|
||||
// buffer. Only a call to Close() that returns nil error guarantees that
|
||||
// all transfers have succeeded.
|
||||
// If the slice passed to Write does not align exactly with the transfer
|
||||
// buffer size (as declared in a call to NewStream), the last USB transfer
|
||||
// of this Write will be sent with less data than the full buffer.
|
||||
// After a non-nil error is returned, all subsequent attempts to write will
|
||||
// return io.ErrClosedPipe.
|
||||
// If Write encounters an error when preparing the transfer, the stream
|
||||
// will still try to complete any pending transfers. The total number
|
||||
// of bytes successfully written can be retrieved through a Written()
|
||||
// call after Close() has returned.
|
||||
// Write cannot be called concurrently with another Write, Written or Close.
|
||||
func (w *WriteStream) Write(p []byte) (int, error) {
|
||||
return w.WriteContext(context.Background(), p)
|
||||
}
|
||||
|
||||
// WriteContext sends the data to the endpoint. Write returning a nil error doesn't
|
||||
// mean that data was written to the device, only that it was written to the
|
||||
// buffer. Only a call to Close() that returns nil error guarantees that
|
||||
// all transfers have succeeded.
|
||||
// If the slice passed to WriteContext does not align exactly with the transfer
|
||||
// buffer size (as declared in a call to NewStream), the last USB transfer
|
||||
// of this Write will be sent with less data than the full buffer.
|
||||
// After a non-nil error is returned, all subsequent attempts to write will
|
||||
// return io.ErrClosedPipe.
|
||||
// If WriteContext encounters an error when preparing the transfer, the stream
|
||||
// will still try to complete any pending transfers. The total number
|
||||
// of bytes successfully written can be retrieved through a Written()
|
||||
// call after Close() has returned.
|
||||
// WriteContext cannot be called concurrently with another Write, WriteContext,
|
||||
// Written, Close or CloseContext.
|
||||
func (w *WriteStream) WriteContext(ctx context.Context, p []byte) (int, error) {
|
||||
if w.s.transfers == nil || w.s.err != nil {
|
||||
return 0, io.ErrClosedPipe
|
||||
}
|
||||
written := 0
|
||||
all := len(p)
|
||||
for written < all {
|
||||
t := <-w.s.transfers
|
||||
n, err := t.wait(ctx) // unsubmitted transfers will return 0 bytes and no error
|
||||
w.total += n
|
||||
if err != nil {
|
||||
t.free()
|
||||
w.s.gotError(err)
|
||||
// This branch is used only after all the transfers were set in flight.
|
||||
// That means all transfers left in the queue are in flight.
|
||||
// They must be ignored, since this wait() failed.
|
||||
w.s.flushRemaining()
|
||||
return written, err
|
||||
}
|
||||
use := all - written
|
||||
if max := len(t.data()); use > max {
|
||||
use = max
|
||||
}
|
||||
copy(t.data(), p[written:written+use])
|
||||
if err := t.submit(); err != nil {
|
||||
t.free()
|
||||
w.s.gotError(err)
|
||||
// Even though this submit failed, all the transfers in flight are still valid.
|
||||
// Don't flush remaining transfers.
|
||||
// We won't submit any more transfers.
|
||||
w.s.noMore()
|
||||
return written, err
|
||||
}
|
||||
written += use
|
||||
w.s.transfers <- t // guaranteed non blocking
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// Close signals end of data to write. Close blocks until all transfers
|
||||
// that were sent are finished. The error returned by Close is the first
|
||||
// error encountered during writing the entire stream (if any).
|
||||
// Close returning nil indicates all transfers completed successfully.
|
||||
// After Close, the total number of bytes successfully written can be
|
||||
// retrieved using Written().
|
||||
// Close may not be called concurrently with Write, Close or Written.
|
||||
func (w *WriteStream) Close() error {
|
||||
return w.CloseContext(context.Background())
|
||||
}
|
||||
|
||||
// Close signals end of data to write. Close blocks until all transfers
|
||||
// that were sent are finished. The error returned by Close is the first
|
||||
// error encountered during writing the entire stream (if any).
|
||||
// Close returning nil indicates all transfers completed successfully.
|
||||
// After Close, the total number of bytes successfully written can be
|
||||
// retrieved using Written().
|
||||
// Close may not be called concurrently with Write, Close or Written.
|
||||
// CloseContext
|
||||
func (w *WriteStream) CloseContext(ctx context.Context) error {
|
||||
if w.s.transfers == nil {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
w.s.noMore()
|
||||
for t := range w.s.transfers {
|
||||
n, err := t.wait(ctx)
|
||||
w.total += n
|
||||
t.free()
|
||||
if err != nil {
|
||||
w.s.gotError(err)
|
||||
w.s.flushRemaining()
|
||||
}
|
||||
t.free()
|
||||
}
|
||||
w.s.transfers = nil
|
||||
return w.s.err
|
||||
}
|
||||
|
||||
// Written returns the number of bytes successfully written by the stream.
|
||||
// Written may be called only after Close() or CloseContext()
|
||||
// has been called and returned.
|
||||
func (w *WriteStream) Written() int {
|
||||
return w.total
|
||||
}
|
||||
|
||||
func newStream(tt []transferIntf) *stream {
|
||||
s := &stream{
|
||||
transfers: make(chan transferIntf, len(tt)),
|
||||
}
|
||||
for _, t := range tt {
|
||||
s.transfers <- t
|
||||
}
|
||||
return s
|
||||
}
|
26
vendor/github.com/google/gousb/usb.c
generated
vendored
Normal file
26
vendor/github.com/google/gousb/usb.c
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2018 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
void gousb_set_debug(libusb_context *ctx, int lvl) {
|
||||
// TODO(sebek): remove libusb_debug entirely in 2.1 or 3.0,
|
||||
// require libusb >= 1.0.22. libusb 1.0.22 sets API version 0x01000106.
|
||||
#if LIBUSB_API_VERSION >= 0x01000106
|
||||
libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, lvl);
|
||||
#else
|
||||
libusb_set_debug(ctx, lvl);
|
||||
#endif
|
||||
}
|
231
vendor/github.com/google/gousb/usb.go
generated
vendored
Normal file
231
vendor/github.com/google/gousb/usb.go
generated
vendored
Normal file
|
@ -0,0 +1,231 @@
|
|||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
Package gousb provides an low-level interface to attached USB devices.
|
||||
|
||||
A Short Tutorial
|
||||
|
||||
A Context manages all resources necessary for communicating with USB
|
||||
devices.
|
||||
Through the Context users can iterate over available USB devices.
|
||||
|
||||
The USB standard defines a mechanism of discovering USB device functionality
|
||||
through descriptors. After the device is attached and
|
||||
initialized by the host stack, it's possible to retrieve its descriptor
|
||||
(the device descriptor). It contains elements such as product and vendor IDs,
|
||||
bus number and device number (address) on the bus.
|
||||
|
||||
In gousb, the Device struct represents a USB device. The Device struct’s Desc
|
||||
field contains all known information about the device.
|
||||
|
||||
Among other information in the device descriptor is a list of configuration
|
||||
descriptors, accessible through Device.Desc.Configs.
|
||||
|
||||
The USB standard allows one physical USB device to switch between different
|
||||
sets of behaviors, or working modes, by selecting one of the offered configs
|
||||
(each device has at least one).
|
||||
This allows the same device to sometimes present itself as e.g. a 3G modem,
|
||||
and sometimes as a flash drive with the drivers for that 3G modem.
|
||||
Configs are mutually exclusive, each device
|
||||
can have only one active config at a time. Switching the active config performs
|
||||
a light-weight device reset. Each config in the device descriptor has
|
||||
a unique identification number.
|
||||
|
||||
In gousb a device config needs to be selected through Device.Config(num).
|
||||
It returns a Config struct that represents the device in this particular configuration.
|
||||
The configuration descriptor is accessible through Config.Desc.
|
||||
|
||||
A config descriptor determines the list of available USB interfaces on the device.
|
||||
Each interface is a virtual device within the physical USB device and its active
|
||||
config. There can be many interfaces active concurrently. Interfaces are
|
||||
enumerated sequentially starting from zero.
|
||||
|
||||
Additionally, each interface comes with a number of alternate settings for
|
||||
the interface, which are somewhat similar to device configs, but on the
|
||||
interface level. Each interface can have only a single alternate setting
|
||||
active at any time. Alternate settings are enumerated sequentially starting from
|
||||
zero.
|
||||
|
||||
In gousb an interface and its alternate setting can be selected through
|
||||
Config.Interface(num, altNum). The Interface struct is the representation
|
||||
of the claimed interface with a particular alternate setting.
|
||||
The descriptor of the interface is available through Interface.Setting.
|
||||
|
||||
An interface with a particular alternate setting defines up to 30 data
|
||||
endpoints, each identified by a unique address. The endpoint address is a combination
|
||||
of endpoint number (1..15) and endpoint directionality (IN/OUT).
|
||||
IN endpoints have addresses 0x81..0x8f, while OUT endpoints 0x01..0x0f.
|
||||
|
||||
An endpoint can be considered similar to a UDP/IP port,
|
||||
except the data transfers are unidirectional.
|
||||
|
||||
Endpoints are represented by the Endpoint struct, and all defined endpoints
|
||||
can be obtained through the Endpoints field of the Interface.Setting.
|
||||
|
||||
Each endpoint descriptor (EndpointDesc) defined in the interface's endpoint
|
||||
map includes information about the type of the endpoint:
|
||||
|
||||
- endpoint address
|
||||
|
||||
- endpoint number
|
||||
|
||||
- direction: IN (device-to-host) or OUT (host-to-device)
|
||||
|
||||
- transfer type: USB standard defines a few distinct data transfer types:
|
||||
|
||||
--- bulk - high throughput, but no guaranteed bandwidth and no latency guarantees,
|
||||
|
||||
--- isochronous - medium throughput, guaranteed bandwidth, some latency guarantees,
|
||||
|
||||
--- interrupt - low throughput, high latency guarantees.
|
||||
|
||||
The endpoint descriptor determines the type of the transfer that will be used.
|
||||
|
||||
- maximum packet size: maximum number of bytes that can be sent or received by the device in a single USB transaction.
|
||||
and a few other less frequently used pieces of endpoint information.
|
||||
|
||||
An IN Endpoint can be opened for reading through Interface.InEndpoint(epNum),
|
||||
while an OUT Endpoint can be opened for writing through Interface.OutEndpoint(epNum).
|
||||
|
||||
An InEndpoint implements the io.Reader interface, an OutEndpoint implements
|
||||
the io.Writer interface. Both Reads and Writes will accept larger slices
|
||||
of data than the endpoint's maximum packet size, the transfer will be split
|
||||
into smaller USB transactions as needed. But using Read/Write size equal
|
||||
to an integer multiple of maximum packet size helps with improving the transfer
|
||||
performance.
|
||||
|
||||
Apart from 15 possible data endpoints, each USB device also has a control endpoint.
|
||||
The control endpoint is present regardless of the current device config, claimed
|
||||
interfaces and their alternate settings. It makes a lot of sense, as the control endpoint is actually used, among others,
|
||||
to issue commands to switch the active config or select an alternate setting for an interface.
|
||||
|
||||
Control commands are also often used to control the behavior of the device. There is no single
|
||||
standard for control commands though, and many devices implement their custom control command schema.
|
||||
|
||||
Control commands can be issued through Device.Control().
|
||||
|
||||
See Also
|
||||
|
||||
For more information about USB protocol and handling USB devices,
|
||||
see the excellent "USB in a nutshell" guide: http://www.beyondlogic.org/usbnutshell/
|
||||
|
||||
*/
|
||||
package gousb
|
||||
|
||||
// Context manages all resources related to USB device handling.
|
||||
type Context struct {
|
||||
ctx *libusbContext
|
||||
done chan struct{}
|
||||
libusb libusbIntf
|
||||
}
|
||||
|
||||
// Debug changes the debug level. Level 0 means no debug, higher levels
|
||||
// will print out more debugging information.
|
||||
// TODO(sebek): in the next major release, replace int levels with
|
||||
// Go-typed constants.
|
||||
func (c *Context) Debug(level int) {
|
||||
c.libusb.setDebug(c.ctx, level)
|
||||
}
|
||||
|
||||
func newContextWithImpl(impl libusbIntf) *Context {
|
||||
c, err := impl.init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx := &Context{
|
||||
ctx: c,
|
||||
done: make(chan struct{}),
|
||||
libusb: impl,
|
||||
}
|
||||
go impl.handleEvents(ctx.ctx, ctx.done)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// NewContext returns a new Context instance.
|
||||
func NewContext() *Context {
|
||||
return newContextWithImpl(libusbImpl{})
|
||||
}
|
||||
|
||||
// OpenDevices calls opener with each enumerated device.
|
||||
// If the opener returns true, the device is opened and a Device is returned if the operation succeeds.
|
||||
// Every Device returned (whether an error is also returned or not) must be closed.
|
||||
// If there are any errors enumerating the devices,
|
||||
// the final one is returned along with any successfully opened devices.
|
||||
func (c *Context) OpenDevices(opener func(desc *DeviceDesc) bool) ([]*Device, error) {
|
||||
list, err := c.libusb.getDevices(c.ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var reterr error
|
||||
var ret []*Device
|
||||
for _, dev := range list {
|
||||
desc, err := c.libusb.getDeviceDesc(dev)
|
||||
if err != nil {
|
||||
c.libusb.dereference(dev)
|
||||
reterr = err
|
||||
continue
|
||||
}
|
||||
|
||||
if opener(desc) {
|
||||
handle, err := c.libusb.open(dev)
|
||||
if err != nil {
|
||||
c.libusb.dereference(dev)
|
||||
reterr = err
|
||||
continue
|
||||
}
|
||||
ret = append(ret, &Device{handle: handle, ctx: c, Desc: desc})
|
||||
} else {
|
||||
c.libusb.dereference(dev)
|
||||
}
|
||||
}
|
||||
return ret, reterr
|
||||
}
|
||||
|
||||
// OpenDeviceWithVIDPID opens Device from specific VendorId and ProductId.
|
||||
// If none is found, it returns nil and nil error. If there are multiple devices
|
||||
// with the same VID/PID, it will return one of them, picked arbitrarily.
|
||||
// If there were any errors during device list traversal, it is possible
|
||||
// it will return a non-nil device and non-nil error. A Device.Close() must
|
||||
// be called to release the device if the returned device wasn't nil.
|
||||
func (c *Context) OpenDeviceWithVIDPID(vid, pid ID) (*Device, error) {
|
||||
var found bool
|
||||
devs, err := c.OpenDevices(func(desc *DeviceDesc) bool {
|
||||
if found {
|
||||
return false
|
||||
}
|
||||
if desc.Vendor == ID(vid) && desc.Product == ID(pid) {
|
||||
found = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if len(devs) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return devs[0], nil
|
||||
}
|
||||
|
||||
// Close releases the Context and all associated resources.
|
||||
func (c *Context) Close() error {
|
||||
var ret error
|
||||
c.done <- struct{}{}
|
||||
if c.ctx != nil {
|
||||
ret = c.libusb.exit(c.ctx)
|
||||
}
|
||||
c.ctx = nil
|
||||
return ret
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue