pyusb-1.0.0/ 0000775 0001750 0001750 00000000000 12711232524 013435 5 ustar wander wander 0000000 0000000 pyusb-1.0.0/ChangeLog 0000664 0001750 0001750 00000001316 12711232011 015177 0 ustar wander wander 0000000 0000000 Author: Wander Lairson Costa
Release notes not necessary anymore.
Author: Wander Lairson Costa
Bump version to stable.
Author: Wander Lairson Costa
Merge pull request #140 from MattHeard/patch-3
Correct minor documentation typo
Author: Matt
Correct minor documentation typo
Author: Wander Lairson Costa
Merge pull request #134 from SimplicityGuy/master
Fixing Issue #133
Author: Robert Wlodarczyk
Issue #133: Fixing `detach_kernel_driver`.
Author: Robert Wlodarczyk
Fixing minor alignment issue.
Author: Wander Lairson Costa
Fixed typo in README.
Thanks to Ioan Lupu.
Author: Wander Lairson Costa
Fix braino in libusb0.
Thanks to Ioan Lupu.
pyusb-1.0.0/LICENSE 0000664 0001750 0001750 00000002577 12661452153 014463 0 ustar wander wander 0000000 0000000 Copyright (C) 2009-2014 Wander Lairson Costa. All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
pyusb-1.0.0/README.rst 0000664 0001750 0001750 00000006334 12662340511 015133 0 ustar wander wander 0000000 0000000 =======================================
PyUSB 1.0 - Easy USB access from Python
=======================================
Introduction
============
The PyUSB module provides for Python easy access to the host
machine's Universal Serial Bus (USB) system.
Until 0.4 version, PyUSB used to be a thin wrapper over libusb.
With 1.0 version, things changed considerably. Now PyUSB is an
API rich, backend neutral Python USB module easy to use.
As with most Python modules, PyUSB's documentation is based on Python
doc strings and can therefore be manipulated by tools such as pydoc.
You can also find a tutorial at:
https://github.com/walac/pyusb/blob/master/docs/tutorial.rst.
PyUSB is being developed and tested on Linux and Windows, but it should work
fine on any platform running Python >= 2.4, ctypes and at least one of the
builtin backends.
PyUSB supports libusb 0.1, libusb 1.0 and OpenUSB, but the user does not need
to worry about that, unless in some corner cases.
If you have any question about PyUSB, you can use the PyUSB mailing list
hosted in the SourceForge. In the PyUSB website (http://walac.github.io/pyusb)
you can find instructions on how to subscribe to the mailing list.
Installing PyUSB on GNU/Linux Systems
=====================================
These instructions are for Debian-based systems. Instructions for
other flavors of GNU/Linux should be similar.
You will first need to install the following packages:
1) python (PyUSB is useless without it), version >= 2.4
2) At least one of the supported libraries (libusb 1.0, libusb 0.1 or OpenUSB)
3) If your Python version is < 2.5, you have to install ctypes as a separate
package, because these versions of Python does not ship it.
For example, the command::
$ sudo apt-get install python libusb-1.0-0
should install all these packages on most Debian-based systems with
access to the proper package repositories.
Once the above packages are installed, you can install PyUSB
with the command::
$ sudo python setup.py install
Run it as root from within the same directory as this README file.
You can also use `pip `_ to
install PyUSB::
$ sudo pip install pyusb --pre
Just bear in mind that you still follow to procedure to install the
libusb library.
Installing PyUSB on Windows
===========================
Now that PyUSB is 100% written in Python, you install it on Windows
in the same way you do on Linux::
python setup.py install
If you get some kind of "command not found" error, make sure to add
the Python install directory to your PATH environment variable or
give the complete path to the Python interpreter.
Remember that you need libusb (1.0 or 0.1) or OpenUSB running on your
system. For Windows users, libusb 0.1 is provided through
`libusb-win32 `_
package. Check the libusb website for updates
(http://www.libusb.org).
Reporting bugs/Submitting patches
=================================
Some people have been sending patches and reporting bugs directly
at my email. Please, do it through
`github `_, I had a hardtime tracking
their names to put them in the acknowledgments file. ;-)
PS: this README file was based on the great Josh Lifton's one... ^_^
pyusb-1.0.0/docs/ 0000775 0001750 0001750 00000000000 12711232524 014365 5 ustar wander wander 0000000 0000000 pyusb-1.0.0/docs/faq.rst 0000664 0001750 0001750 00000002210 12661452153 015667 0 ustar wander wander 0000000 0000000 FAQ
===
How do I fix "No backend available" errors?
-------------------------------------------
Generally, there are four possible causes for this problem:
1. You didn't install libusb library.
2. Your libusb library isn't in the standard shared library paths.
3. Your libusb version is too old.
4. Your PyUSB version is too old.
To debug what's wrong, run the following script in your environment::
import os
os.environ['PYUSB_DEBUG'] = 'debug'
import usb.core
usb.core.find()
This will print debug messages to the console. If you still have problems
to figure out what's going on, please ask for help in the mailing list,
providing the debug output.
How do I enforce a backend?
---------------------------
Here is an example for the *libusb1* backend::
>>> import usb.core
>>> from usb.backend import libusb1
>>> be = libusb1.get_backend()
>>> dev = usb.core.find(backend=be)
How can I pass the libusb library path to the backend?
------------------------------------------------------
Check the *Specify libraries by hand* section in the tutorial_.
.. _tutorial: https://github.com/walac/pyusb/docs/tutorial.rst
pyusb-1.0.0/docs/tutorial.rst 0000664 0001750 0001750 00000063457 12661452153 017007 0 ustar wander wander 0000000 0000000 ==========================
Programming with PyUSB 1.0
==========================
Let me introduce myself
=======================
PyUSB 1.0 is a Python_ library allowing easy USB_ access. PyUSB provides
several features:
100% written in Python:
Unlike the 0.x version, which is written in C, 1.0 version is written in
Python. This allows Python programmers with no background in C to
understand better how PyUSB works.
Platform neutrality:
1.0 version implements a frontend-backend scheme. This isolates the API
from system specific implementation details. The glue between the two
layers is the ``IBackend`` interface. PyUSB comes with builtin backends for
libusb 0.1, libusb 1.0 and OpenUSB. You can write your own backend if you
desire to.
Portability:
PyUSB should run on any platform with Python >= 2.4, ctypes_ and at least
one of the supported builtin backends.
Easiness:
Communicating with an USB_ device has never been so easy! USB is a complex
protocol, but PyUSB has good defaults for most common configurations.
Support for isochronous transfers:
PyUSB supports isochronous transfers if the underlying backend supports it.
Although PyUSB makes USB programming less painful, it is assumed in this
tutorial that you have a minimal USB protocol background. If you don't know
anything about USB, I recommend you the excellent Jan Axelson's book **USB
Complete**.
Enough talk, let's code!
========================
Who's who
---------
First of all, let's give an overview on the PyUSB modules. PyUSB modules are
under the ``usb`` package, with the following modules:
======= ===========
Content Description
------- -----------
core The main USB module.
util Utility functions.
control Standard control requests.
legacy The 0.x compatibility layer.
backend A subpackage containing the builtin backends.
======= ===========
For example, to import the ``core`` module, type the following::
>>> import usb.core
>>> dev = usb.core.find()
Let's get it started
--------------------
Following is a simplistic program that sends the 'test' string to the first OUT
endpoint found::
import usb.core
import usb.util
# find our device
dev = usb.core.find(idVendor=0xfffe, idProduct=0x0001)
# was it found?
if dev is None:
raise ValueError('Device not found')
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
ep = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
assert ep is not None
# write the data
ep.write('test')
The first two lines import PyUSB package modules. ``usb.core`` is the main
module, and ``usb.util`` contains utility functions. The next command searches
for our device and returns an instance object if it is found. If not, ``None``
is returned. After, we set the configuration to use. Note that no argument
indicating what configuration we want was supplied. As you will see, many PyUSB
functions have defaults for most common devices. In this case, the
configuration set is the first one found.
Then, we look for the endpoint we are interested. We search for it inside the
first interface we have. After finding the endpoint, we send the data to it.
If we know the endpoint address in advance, we could just call the ``write``
function from the device object::
dev.write(1, 'test')
Here we write the string 'test' at the endpoint address *1*.
All these functions will be detailed in the following sections.
What's wrong?
-------------
Every function in PyUSB raises an exception in case of an error. Besides the
`Python standard exceptions
`__, PyUSB defines the
``usb.core.USBError`` for USB related errors.
You can also use the PyUSB log functionality. It uses the `logging
`__ module. To enable it, define
the environment variable ``PYUSB_DEBUG`` with one of the following level
names: ``critical``, ``error``, ``warning``, ``info`` or ``debug``.
By default the messages are sent to `sys.stderr
`__. If you want to, you can redirect
log messages to a file by defining the ``PYUSB_LOG_FILENAME`` environment
variable. If its value is a valid file path, messages will be written to it,
otherwise it will be sent to ``sys.stderr``.
Where are you?
--------------
The ``find()`` function in the ``core`` module is used to find and enumerate
devices connected to the system. For example, let's say that our device has a
vendor ID equal to `0xfffe` and product ID equals to `0x0001`. If we would like
to find it, we proceed in this way::
import usb.core
dev = usb.core.find(idVendor=0xfffe, idProduct=0x0001)
if dev is None:
raise ValueError('Our device is not connected')
That's it, the function will return an ``usb.core.Device`` object representing
our device. If the device is not found, it returns ``None``. Actually, you can
use any field of the Device Descriptor_ you desire. For example, what if we
would like to discover if there is a USB printer connected to the system? This
is very easy::
# actually this is not the whole history, keep reading
if usb.core.find(bDeviceClass=7) is None:
raise ValueError('No printer found')
The 7 is the code for the printer class according to the USB spec.
Hey, wait, what if I want to enumerate all printers present? No problem::
# this is not the whole history yet...
printers = usb.core.find(find_all=True, bDeviceClass=7)
# Python 2, Python 3, to be or not to be
import sys
sys.stdout.write('There are ' + len(printers) + ' in the system\n.')
What happened? Well, it is time for a little explanation... ``find`` has a
parameter called ``find_all`` that defaults to False. When it is false [#]_,
``find`` will return the first device found that matches the specified criteria
(more on that soon). If you give it a *true* value, ``find`` will instead
return a list with all devices matching the criteria. That's it! Simple, isn't
it?
Finished? No! I have not told you the whole history: many devices actually put
their class information in the Interface Descriptor_ instead of the Device
Descriptor_. So, to really find all printers connected to the system, we would
need to transverse all configurations, and then all interfaces and check if one
of the interfaces has its `bInterfaceClass` field equal to 7. If you are a
`programmer `__ like me, you might be
wondering if there is an easier way to do that. The answer is yes, there is.
First, let's give a look on the final code to find all printers connected::
import usb.core
import usb.util
import sys
class find_class(object):
def __init__(self, class_):
self._class = class_
def __call__(self, device):
# first, let's check the device
if device.bDeviceClass == self._class:
return True
# ok, transverse all devices to find an
# interface that matches our class
for cfg in device:
# find_descriptor: what's it?
intf = usb.util.find_descriptor(
cfg,
bInterfaceClass=self._class
)
if intf is not None:
return True
return False
printers = usb.core.find(find_all=1, custom_match=find_class(7))
The ``custom_match`` parameter accepts any callable object that receives the
device object. It must return true for a matching device, and false for a
non-matching device. You can also combine ``custom_match`` with device fields
if you want::
# find all printers that belongs to our vendor:
printers = usb.core.find(find_all=1, custom_match=find_class(7), idVendor=0xfffe)
Here we are only interested in the printers of the `0xfffe` vendor.
Describe yourself
-----------------
Ok, we've found our device, but before talking to it, we would like to know
more about it, you know, configurations, interfaces, endpoints, transfer
types...
If you have a device, you can access any device descriptor fields as object
properties::
>>> dev.bLength
>>> dev.bNumConfigurations
>>> dev.bDeviceClass
>>> # ...
To access the configurations available in the device, you can iterate over the
device::
for cfg in dev:
sys.stdout.write(str(cfg.bConfigurationValue) + '\n')
In the same way, you can iterate over a configuration to access the interfaces,
and iterate over the interfaces to access their endpoints. Each kind of object
has as attributes the fields of the respective descriptor. Let's see an
example::
for cfg in dev:
sys.stdout.write(str(cfg.bConfigurationValue) + '\n')
for intf in cfg:
sys.stdout.write('\t' + \
str(intf.bInterfaceNumber) + \
',' + \
str(intf.bAlternateSetting) + \
'\n')
for ep in intf:
sys.stdout.write('\t\t' + \
str(ep.bEndpointAddress) + \
'\n')
You can also use the subscript operator to access the descriptors randomly,
like this::
>>> # access the second configuration
>>> cfg = dev[1]
>>> # access the first interface
>>> intf = cfg[(0,0)]
>>> # third endpoint
>>> ep = intf[2]
As you can see, the index is zero-based. But wait! There is something weird in
the way I access an interface... Yes, you are right, the subscript operator in
the Configuration accepts a sequence of two items, with the first one being the
index of the Interface and the second one, the alternate setting. So, to access
the first interface, but its second alternate setting, we write ``cfg[(0,1)]``.
Now it's time to we learn a powerful way to find descriptors, the
``find_descriptor`` utility function. We have already seen it in the printer
finding example. ``find_descriptor`` works in almost the same way as ``find``,
with two exceptions:
* ``find_descriptor`` receives as its first parameter the parent descriptor
that you will search on.
* There is no ``backend`` [#]_ parameter.
For example, if we have a configuration descriptor ``cfg`` and want to find all
alternate settings of the interface 1, we do so::
import usb.util
alt = usb.util.find_descriptor(cfg, find_all=True, bInterfaceNumber=1)
Notice that ``find_descriptor`` is in the ``usb.util`` module. It also accepts
the early described ``custom_match`` parameter.
Dealing with multiple identical devices
***************************************
Sometimes you may have two identical devices connected to the computer. How can
you differentiate them? ``Device`` objects come with two additional attributes
which are not part of the USB Spec, but are very useful: ``bus`` and
``address`` attributes. First of all, it is worth it to say that these
attributes come from the backend and a backend is free to not support them, in
which case they are set to ``None``. That said, these attributes represent the
bus number and bus address of the device and, as you might already have
imagined, can be used to differentiate two devices with the same ``idVendor``
and ``idProduct`` attributes.
How am I supposed to work?
--------------------------
USB devices after connection must be configured through a few standard
requests. When I started to study USB_ spec, I found myself confused with
descriptors, configurations, interfaces, alternate settings, transfer types and
all this stuff... And worst, you cannot simply ignore them, a device does not
work without setting a configuration, even if it has just one! PyUSB tries to
make your life as easy as possible. For example, after getting your device
object, one of the first things you need to do before communicating with it is
issuing a ``set_configuration`` request. The parameter for this request is the
``bConfigurationValue`` of the configuration you are interested on. Most
devices have no more than one configuration, and tracking the configuration
value to use is annoying (although most code I have seen simply hardcodes it).
Therefore, in PyUSB, you can just issue a ``set_configuration`` call with no
arguments. In this case, it will set the first configuration found (if your
device has just one, you don't need to worry about the configuration value at
all). For example, let's imagine you have a device with one configuration
descriptor with its `bConfigurationValue` field equals to 5 [#]_, the following
calls below will work equally::
>>> dev.set_configuration(5)
# or
>>> dev.set_configuration() # we assume the configuration 5 is the first one
# or
>>> cfg = util.find_descriptor(dev, bConfigurationValue=5)
>>> cfg.set()
# or
>>> cfg = util.find_descriptor(dev, bConfigurationValue=5)
>>> dev.set_configuration(cfg)
Wow! You can use a ``Configuration`` object as a parameter to
``set_configuration``! Yes, and also it has a ``set`` method to configure
itself as the current configuration.
The other setting you might or might not have to configure is the interface
alternate setting. Each device can have only one activated configuration at a
time, and each configuration may have more than one interface, and you can use
all interfaces at the same time. You better understand this concept if you
think of an interface as a logical device. For example, let's imagine a
multifunction printer, which is at the same time a printer and a scanner. To
keep things simple (or at least as simple as we can), let's consider that it
has just one configuration. As we have a printer and a scanner, the
configuration has two interfaces, one for the printer and one for the scanner.
A device with more than one interface is called a composite device. When you
connect your multifunction printer to your computer, the Operating System would
load two different drivers: one for each "logical" peripheral you have [#]_.
What about the alternate setting? Good you asked. An interface has one or more
alternate settings. An interface with just one alternate setting is considered
to not having an alternate setting [#]_. Alternate settings are for interfaces
what configurations are for devices, i.e, for each interface, you can have only
one alternate setting active. For example, USB spec says that a device cannot
have an isochronous endpoint in its primary alternate setting [#]_, so a
streaming device must have at least two alternate settings, with the second one
having the isochronous endpoint(s). But as opposed to configurations,
interfaces with just one alternate setting don't need to be set [#]_. You
select an interface alternate setting through the ``set_interface_altsetting``
function::
>>> dev.set_interface_altsetting(interface = 0, alternate_setting = 0)
.. warning::
The USB spec says that a device is allowed to return an error in case it
receives a SET_INTERFACE request for an interface that has no additional
alternate settings. So, if you are not sure if either the interface has more
than one alternate setting or it accepts a SET_INTERFACE request,
the safest way is to call ``set_interface_altsetting`` inside an
try-except block, like this::
try:
dev.set_interface_altsetting(...)
except USBError:
pass
You can also use an ``Interface`` object as parameter to the function, the
``interface`` and ``alternate_setting`` parameters are automatically inferred
from ``bInterfaceNumber`` and ``bAlternateSetting`` fields. Example::
>>> intf = find_descriptor(...)
>>> dev.set_interface_altsetting(intf)
>>> intf.set_altsetting() # wow! Interface also has a method for it
.. warning::
The ``Interface`` object must belong to the active configuration descriptor.
Talk to me, honey
-----------------
Now it's time for us to learn how to communicate with USB devices. USB has four
flavors of transfers: bulk, interrupt, isochronous and control. I don't intend
to explain the purpose of each transfer and the differences among them.
Therefore, I assume you know at least the basics of the USB transfers.
Control transfer is the only transfer that has structured data described in the
spec, the others just send and receive raw data from USB point of view. Because
of it, you have a different function to deal with control transfers, all the
other transfers are managed by the same functions.
You issue a control transfer through the ``ctrl_transfer`` method. It is used
both for OUT and IN transfers. The transfer direction is determined from the
``bmRequestType`` parameter.
The ``ctrl_transfer`` parameters are almost equal to the control request
structure. Following is a example of how to do a control transfer [#]_::
>>> msg = 'test'
>>> assert dev.ctrl_transfer(0x40, CTRL_LOOPBACK_WRITE, 0, 0, msg) == len(msg)
>>> ret = dev.ctrl_transfer(0xC0, CTRL_LOOPBACK_READ, 0, 0, len(msg))
>>> sret = ''.join([chr(x) for x in ret])
>>> assert sret == msg
In this example, it is assumed that our device implements two custom control
requests that act as a loopback pipe. What you write with the
``CTRL_LOOPBACK_WRITE`` message, you can read with the ``CTRL_LOOPBACK_READ``
message.
The first four parameters are the ``bmRequestType``, ``bmRequest``, ``wValue``
and ``wIndex`` fields of the standard control transfer structure. The fifth
parameter is either the data payload for an OUT transfer or the number of bytes
to read in an IN transfer. The data payload can be any sequence type that can
be used as a parameter for the array_ ``__init__`` method. If there is no data
payload, the parameter should be ``None`` (or 0 in case of an IN transfer).
There is one last optional parameter specifying the timeout of the operation.
If you don't supply it, a default timeout will be used (more on that later). In
an OUT transfer, the return value is the number of bytes really sent to the
device. In an IN transfer, the return value is an array_ object with the data
read.
For the other transfers, you use the methods ``write`` and ``read``,
respectively, to write and read data. You don't need to worry about the
transfer type, it is automatically determined from the endpoint address. Here
is our loopback example assuming the we have a loopback pipe in the endpoint
1::
>>> msg = 'test'
>>> assert len(dev.write(1, msg, 100)) == len(msg)
>>> ret = dev.read(0x81, len(msg), 100)
>>> sret = ''.join([chr(x) for x in ret])
>>> assert sret == msg
The first and third parameters are equal for both methods, they are the
endpoint address and timeout, respectively. The second parameter is the data
payload (write) or the number of bytes to read (read). The returned data if
either an instance of the array_ object for the ``read`` method or the number
of bytes written for the ``write`` method.
Since beta 2 version, instead of the number of bytes, you can also pass to
``read`` and ``ctrl_transfer`` an array_ object in which the data will be
read into. In this case, the number of bytes to read will be the length of
the array times the ``array.itemsize`` value.
As in ``ctrl_transfer``, the ``timeout`` parameter is optional. When the
``timeout`` is omitted, it is used the ``Device.default_timeout`` property
as the operation timeout.
Control yourself
----------------
Besides the transfers functions, the module ``usb.control`` offers functions
which implement the standard USB control requests and the ``usb.util`` module
has the convenience function ``get_string`` specifically to return string
descriptors.
Additional Topics
=================
Behind every great abstraction, there's a great implementation
--------------------------------------------------------------
In the early days, there was only libusb_. Then came libusb 1.0, and we had
libusb 0.1 and 1.0. After, they created OpenUSB_, and now we live at the
`Tower of Babel `__ of the USB
libraries [#]_. How does PyUSB deal with it? Well, PyUSB is a democratic
library, you may choose whichever library you want. Actually, you can write
your own USB library from scratch and tell PyUSB to use it.
The ``find`` function has one more parameter that I haven't told you. It is the
``backend`` parameter. If you don't supply it, it will be used one of the
builtin backends. A backend is an object inherited from
``usb.backend.IBackend``, responsible to implement the operating system
specific USB stuff. As you might guess, the builtins are libusb 0.1, libusb 1.0
and OpenUSB backends.
You can create your own backend and use it. Just inherit from ``IBackend`` and
implement the methods necessary. You might want to take a look at the
``usb.backend`` package documentation to learn how to do that.
Don't be selfish
----------------
Python has what we call *automatic memory management*. This means that the
virtual machine will decide when to release objects from the memory. Under the
hood, PyUSB manages all low level resources it needs to work (interface
claiming, device handles, etc.) and most of the users don't need to worry about
that. But, because of the nondeterministic nature of automatic object
destruction of Python, users cannot predict when the resources allocated will
be released. Some applications need to allocate and free the resources
deterministically. For these kind of applications, the ``usb.util`` module has
a set of functions to deal with resource management.
If you want to claim and release interfaces manually, you may use the
``claim_interface`` and ``release_interface`` functions. ``claim_interface``
will claim the specified interface if the device has not done it yet. If the
device already claimed the interface, it does nothing. In a similar way,
``release_interface`` will release the specified interface if it is claimed.
If the interface is not claimed, it does nothing. You can use manual interface
claim to solve the `configuration selection problem
`__ described in the
libusb_ documentation.
If you want to free all resources allocated by the device object (including
interfaces claimed), you can use the ``dispose_resources`` function. It
releases all resources allocated and puts the device object (but not the device
hardware itself) in the state it was at the time when the ``find`` function
returned.
Specifying libraries by hand
----------------------------
In general, a backend is an wrapper on a shared library which implements the
USB access API. By default, the backend uses the `find_library()
`_
ctypes_ function. On Linux and other Unix like Operating Systems,
``find_library`` tries to run external programs (like */sbin/ldconfig*, *gcc*
and *objdump*) to find the library file.
On systems where these programs are missing and/or the library cache is
disabled, this function cannot be used. To overcome this limitation, PyUSB
allows you to supply a custom `find_library()` function to the backend.
An example for such scenario would be::
>>> import usb.core
>>> import usb.backend.libusb1
>>>
>>> backend = usb.backend.libusb1.get_backend(find_library=lambda x: "/usr/lib/libusb-1.0.so")
>>> dev = usb.core.find(..., backend=backend)
Notice the `find_library` argument for the `get_backend()` function, in which
you supply a function that is responsible to find the correct library for the
backend.
Old school rules
----------------
If you wrote an application using the old PyUSB API (0.whatever), you may be
asking yourself if you need to update your code to use the new API. Well, you
should, but you don't need to. PyUSB 1.0 comes with the ``usb.legacy``
compatibility module. It implements the older API above the new API. "So, do I
have just to replace my ``import usb`` statement with ``import usb.legacy as
usb`` to get my application working?", you ask. The answer is yes, it will
work, but you don't have to. If you run your application untouched it will just
work, because the ``import usb`` statement will import all public symbols from
``usb.legacy``. If you face a problem, probably you found a bug.
Help me, please
---------------
If you need help, **do not email me**, the mailing list is there for this.
Subscribe instructions can be found at the PyUSB_ website.
.. [#] When I say True or False (capitalized), I mean the respective values of
the Python language. And when I say true and false, I mean any
expression in Python which evals to true or false.
.. [#] See backend specific documentation.
.. [#] USB spec does not impose any sequential value to the configuration
value. The same is true for interface and alternate setting numbers.
.. [#] Actually things are a little more complex, but this simple explanation
is enough for us.
.. [#] I know it sounds weird.
.. [#] This is because if there is no bandwidth for isochronous transfer at the
device configuration time, the device can be successfully enumerated.
.. [#] This does not happen for configurations because a device is allowed to
be in an unconfigured state.
.. [#] In PyUSB, control transfers are only issued in the endpoint 0. It's very
very very rare a device having an alternate control endpoint (I've never
seem such device).
.. [#] It's just a joke, don't take it seriously. Many choices is better than
no choice.
.. _libusb: http://www.libusb.org
.. _OpenUSB: http://sourceforge.net/p/openusb/wiki/Home/
.. _USB: http://www.usb.org
.. _PyUSB: http://pyusb.wiki.sourceforge.net
.. _Python: http://www.python.org
.. _ctypes: http://docs.python.org/library/ctypes.html
.. _Descriptor: http://www.beyondlogic.org/usbnutshell/usb5.htm
.. _array: http://docs.python.org/library/array.html
pyusb-1.0.0/setup.cfg 0000664 0001750 0001750 00000000051 12661452153 015260 0 ustar wander wander 0000000 0000000 [metadata]
description-file = README.rst
pyusb-1.0.0/setup.py 0000775 0001750 0001750 00000010042 12711231603 015144 0 ustar wander wander 0000000 0000000 #!/usr/bin/env python
#
# Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
from distutils.core import setup
import usb
setup(
name='pyusb',
version=usb.__version__,
description='Python USB access module',
author='Wander Lairson Costa',
author_email='wander.lairson@gmail.com',
license = 'BSD',
url='http://pyusb.sourceforge.net',
packages=['usb', 'usb.backend'],
long_description =
"""
PyUSB offers easy USB devices communication in Python.
It should work without additional code in any environment with
Python >= 2.4, ctypes and an pre-built usb backend library
(currently, libusb 0.1.x, libusb 1.x, and OpenUSB).
""",
classifiers=[
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: Manufacturing', # USB automation, or mfg USB devs
'Intended Audience :: Science/Research', # interface with instruments
'Intended Audience :: System Administrators', # integrate strange devs
'Intended Audience :: Telecommunications Industry', # telecomm devs
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
# try to union the OSes that can build any of the backend libraries...
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows :: Windows Vista',
'Operating System :: Microsoft :: Windows :: Windows 7',
'Operating System :: POSIX :: BSD :: FreeBSD',
'Operating System :: POSIX :: BSD :: NetBSD',
'Operating System :: POSIX :: BSD :: OpenBSD',
'Operating System :: POSIX :: Linux',
'Operating System :: POSIX :: SunOS/Solaris',
'Programming Language :: Python :: 2.4',
'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
# source(CPython,Jython,IronPython,PyPy): "The Long Term" section of
# http://ojs.pythonpapers.org/index.php/tpp/article/viewFile/23/23
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: IronPython',
'Programming Language :: Python :: Implementation :: Jython',
'Programming Language :: Python :: Implementation :: PyPy',
'Topic :: Scientific/Engineering :' \
': Interface Engine/Protocol Translator',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: System :: Hardware :: Hardware Drivers'
]
)
pyusb-1.0.0/ACKNOWLEDGEMENTS 0000664 0001750 0001750 00000000664 12661452153 015726 0 ustar wander wander 0000000 0000000 Alan Aguiar
jaseg
Johannes Stezenbach
Marijn van Vliet
Stefano Di Martino
Simon Norberg
iThompson
Harry Bock
ponty
Chris Clark
themperek
David Halter
Robert von Burg
James Rowe
Braiden Kindt
Tormod Volden
Chris Clark
Emmanuel Blot
Peter Bigot
Travis Robinson
Xiaofan Chen
Poul-Henning Kamp
Thomas Reitmayr
Carl Ritson
Romain Aviolat
Walker Inman
Prathmesh Prabhu
André Erdmann
Jeffrey Nichols
Deliang Fan
Matthew Chan
Maximilian Köhl
pyusb-1.0.0/usb/ 0000775 0001750 0001750 00000000000 12711232524 014226 5 ustar wander wander 0000000 0000000 pyusb-1.0.0/usb/_debug.py 0000664 0001750 0001750 00000006217 12661452153 016041 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
__author__ = 'Wander Lairson Costa'
__all__ = ['methodtrace', 'functiontrace']
import logging
import usb._interop as _interop
_enable_tracing = False
def enable_tracing(enable):
global _enable_tracing
_enable_tracing = enable
def _trace_function_call(logger, fname, *args, **named_args):
logger.debug(
# TODO: check if 'f' is a method or a free function
fname + '(' + \
', '.join((str(val) for val in args)) + \
', '.join((name + '=' + str(val) for name, val in named_args.items())) + ')'
)
# decorator for methods calls tracing
def methodtrace(logger):
def decorator_logging(f):
if not _enable_tracing:
return f
def do_trace(*args, **named_args):
# this if is just a optimization to avoid unecessary string formatting
if logging.DEBUG >= logger.getEffectiveLevel():
fn = type(args[0]).__name__ + '.' + f.__name__
_trace_function_call(logger, fn, *args[1:], **named_args)
return f(*args, **named_args)
_interop._update_wrapper(do_trace, f)
return do_trace
return decorator_logging
# decorator for methods calls tracing
def functiontrace(logger):
def decorator_logging(f):
if not _enable_tracing:
return f
def do_trace(*args, **named_args):
# this if is just a optimization to avoid unecessary string formatting
if logging.DEBUG >= logger.getEffectiveLevel():
_trace_function_call(logger, f.__name__, *args, **named_args)
return f(*args, **named_args)
_interop._update_wrapper(do_trace, f)
return do_trace
return decorator_logging
pyusb-1.0.0/usb/core.py 0000664 0001750 0001750 00000133160 12661452153 015542 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
r"""usb.core - Core USB features.
This module exports:
Device - a class representing a USB device.
Configuration - a class representing a configuration descriptor.
Interface - a class representing an interface descriptor.
Endpoint - a class representing an endpoint descriptor.
find() - a function to find USB devices.
show_devices() - a function to show the devices present.
"""
__author__ = 'Wander Lairson Costa'
__all__ = [ 'Device', 'Configuration', 'Interface', 'Endpoint', 'find',
'show_devices' ]
import usb.util as util
import copy
import operator
import usb._interop as _interop
import usb._objfinalizer as _objfinalizer
import usb._lookup as _lu
import logging
import array
import threading
import functools
_logger = logging.getLogger('usb.core')
_DEFAULT_TIMEOUT = 1000
def _set_attr(input, output, fields):
for f in fields:
setattr(output, f, getattr(input, f))
def _try_get_string(dev, index, langid = None, default_str_i0 = "",
default_access_error = "Error Accessing String"):
""" try to get a string, but return a string no matter what
"""
if index == 0 :
string = default_str_i0
else:
try:
if langid is None:
string = util.get_string(dev, index)
else:
string = util.get_string(dev, index, langid)
except :
string = default_access_error
return string
def _try_lookup(table, value, default = ""):
""" try to get a string from the lookup table, return "" instead of key
error
"""
try:
string = table[ value ]
except KeyError:
string = default
return string
class _DescriptorInfo(str):
""" this class is used so that when a descriptor is shown on the
terminal it is propely formatted """
def __repr__(self):
return self
def synchronized(f):
@functools.wraps(f)
def wrapper(self, *args, **kwargs):
try:
self.lock.acquire()
return f(self, *args, **kwargs)
finally:
self.lock.release()
return wrapper
class _ResourceManager(object):
def __init__(self, dev, backend):
self.backend = backend
self._active_cfg_index = None
self.dev = dev
self.handle = None
self._claimed_intf = _interop._set()
self._ep_info = {}
self.lock = threading.RLock()
@synchronized
def managed_open(self):
if self.handle is None:
self.handle = self.backend.open_device(self.dev)
return self.handle
@synchronized
def managed_close(self):
if self.handle is not None:
self.backend.close_device(self.handle)
self.handle = None
@synchronized
def managed_set_configuration(self, device, config):
if config is None:
cfg = device[0]
elif isinstance(config, Configuration):
cfg = config
elif config == 0: # unconfigured state
class MockConfiguration(object):
def __init__(self):
self.index = None
self.bConfigurationValue = 0
cfg = MockConfiguration()
else:
cfg = util.find_descriptor(device, bConfigurationValue=config)
if cfg is None:
raise ValueError("Invalid configuration " + str(config))
self.managed_open()
self.backend.set_configuration(self.handle, cfg.bConfigurationValue)
# cache the index instead of the object to avoid cyclic references
# of the device and Configuration (Device tracks the _ResourceManager,
# which tracks the Configuration, which tracks the Device)
self._active_cfg_index = cfg.index
self._ep_info.clear()
@synchronized
def managed_claim_interface(self, device, intf):
self.managed_open()
if isinstance(intf, Interface):
i = intf.bInterfaceNumber
else:
i = intf
if i not in self._claimed_intf:
self.backend.claim_interface(self.handle, i)
self._claimed_intf.add(i)
@synchronized
def managed_release_interface(self, device, intf):
if intf is None:
cfg = self.get_active_configuration(device)
i = cfg[(0,0)].bInterfaceNumber
elif isinstance(intf, Interface):
i = intf.bInterfaceNumber
else:
i = intf
if i in self._claimed_intf:
try:
self.backend.release_interface(self.handle, i)
finally:
self._claimed_intf.remove(i)
@synchronized
def managed_set_interface(self, device, intf, alt):
if isinstance(intf, Interface):
i = intf
else:
cfg = self.get_active_configuration(device)
if intf is None:
intf = cfg[(0,0)].bInterfaceNumber
if alt is not None:
i = util.find_descriptor(cfg, bInterfaceNumber=intf, bAlternateSetting=alt)
else:
i = util.find_descriptor(cfg, bInterfaceNumber=intf)
self.managed_claim_interface(device, i)
if alt is None:
alt = i.bAlternateSetting
self.backend.set_interface_altsetting(self.handle, i.bInterfaceNumber, alt)
@synchronized
def setup_request(self, device, endpoint):
# we need the endpoint address, but the "endpoint" parameter
# can be either the a Endpoint object or the endpoint address itself
if isinstance(endpoint, Endpoint):
endpoint_address = endpoint.bEndpointAddress
else:
endpoint_address = endpoint
intf, ep = self.get_interface_and_endpoint(device, endpoint_address)
self.managed_claim_interface(device, intf)
return (intf, ep)
# Find the interface and endpoint objects which endpoint address belongs to
@synchronized
def get_interface_and_endpoint(self, device, endpoint_address):
try:
return self._ep_info[endpoint_address]
except KeyError:
for intf in self.get_active_configuration(device):
ep = util.find_descriptor(intf, bEndpointAddress=endpoint_address)
if ep is not None:
self._ep_info[endpoint_address] = (intf, ep)
return intf, ep
raise ValueError('Invalid endpoint address ' + hex(endpoint_address))
@synchronized
def get_active_configuration(self, device):
if self._active_cfg_index is None:
self.managed_open()
cfg = util.find_descriptor(
device,
bConfigurationValue=self.backend.get_configuration(self.handle)
)
if cfg is None:
raise USBError('Configuration not set')
self._active_cfg_index = cfg.index
return cfg
return device[self._active_cfg_index]
@synchronized
def release_all_interfaces(self, device):
claimed = copy.copy(self._claimed_intf)
for i in claimed:
try:
self.managed_release_interface(device, i)
except USBError:
# Ignore errors when releasing the interfaces
# When the device is disconnected, the call may fail
pass
@synchronized
def dispose(self, device, close_handle = True):
self.release_all_interfaces(device)
if close_handle:
self.managed_close()
self._ep_info.clear()
self._active_cfg_index = None
class USBError(IOError):
r"""Exception class for USB errors.
Backends must raise this exception when USB related errors occur. The
backend specific error code is available through the 'backend_error_code'
member variable.
"""
def __init__(self, strerror, error_code = None, errno = None):
r"""Initialize the object.
This initializes the USBError object. The strerror and errno are passed
to the parent object. The error_code parameter is attributed to the
backend_error_code member variable.
"""
IOError.__init__(self, errno, strerror)
self.backend_error_code = error_code
class NoBackendError(ValueError):
r"Exception class when a valid backend is not found."
pass
class Endpoint(object):
r"""Represent an endpoint object.
This class contains all fields of the Endpoint Descriptor according to the
USB Specification. You can access them as class properties. For example, to
access the field bEndpointAddress of the endpoint descriptor, you can do so:
>>> import usb.core
>>> dev = usb.core.find()
>>> for cfg in dev:
>>> for i in cfg:
>>> for e in i:
>>> print e.bEndpointAddress
"""
def __init__(self, device, endpoint, interface = 0,
alternate_setting = 0, configuration = 0):
r"""Initialize the Endpoint object.
The device parameter is the device object returned by the find()
function. endpoint is the endpoint logical index (not the endpoint
address). The configuration parameter is the logical index of the
configuration (not the bConfigurationValue field). The interface
parameter is the interface logical index (not the bInterfaceNumber
field) and alternate_setting is the alternate setting logical index
(not the bAlternateSetting value). An interface may have only one
alternate setting. In this case, the alternate_setting parameter
should be zero. By "logical index" we mean the relative order of the
configurations returned by the peripheral as a result of GET_DESCRIPTOR
request.
"""
self.device = device
self.index = endpoint
backend = device._ctx.backend
desc = backend.get_endpoint_descriptor(
device._ctx.dev,
endpoint,
interface,
alternate_setting,
configuration
)
_set_attr(
desc,
self,
(
'bLength',
'bDescriptorType',
'bEndpointAddress',
'bmAttributes',
'wMaxPacketSize',
'bInterval',
'bRefresh',
'bSynchAddress',
'extra_descriptors'
)
)
def __repr__(self):
return "<" + self._str() + ">"
def __str__(self):
headstr = " " + self._str() + " "
if util.endpoint_direction(self.bEndpointAddress) == util.ENDPOINT_IN:
direction = "IN"
else:
direction = "OUT"
return "%s%s\n" % (headstr, "=" * (60 - len(headstr))) + \
" %-17s:%#7x (7 bytes)\n" % (
"bLength", self.bLength) + \
" %-17s:%#7x %s\n" % (
"bDescriptorType", self.bDescriptorType,
_try_lookup(_lu.descriptors, self.bDescriptorType)) + \
" %-17s:%#7x %s\n" % (
"bEndpointAddress", self.bEndpointAddress, direction) + \
" %-17s:%#7x %s\n" % (
"bmAttributes", self.bmAttributes,
_lu.ep_attributes[(self.bmAttributes & 0x3)]) + \
" %-17s:%#7x (%d bytes)\n" % (
"wMaxPacketSize", self.wMaxPacketSize, self.wMaxPacketSize) + \
" %-17s:%#7x" % ("bInterval", self.bInterval)
def write(self, data, timeout = None):
r"""Write data to the endpoint.
The parameter data contains the data to be sent to the endpoint and
timeout is the time limit of the operation. The transfer type and
endpoint address are automatically inferred.
The method returns the number of bytes written.
For details, see the Device.write() method.
"""
return self.device.write(self, data, timeout)
def read(self, size_or_buffer, timeout = None):
r"""Read data from the endpoint.
The parameter size_or_buffer is either the number of bytes to
read or an array object where the data will be put in and timeout is the
time limit of the operation. The transfer type and endpoint address
are automatically inferred.
The method returns either an array object or the number of bytes
actually read.
For details, see the Device.read() method.
"""
return self.device.read(self, size_or_buffer, timeout)
def clear_halt(self):
r"""Clear the halt/status condition of the endpoint."""
self.device.clear_halt(self.bEndpointAddress)
def _str(self):
if util.endpoint_direction(self.bEndpointAddress) == util.ENDPOINT_IN:
direction = "IN"
else:
direction = "OUT"
return (
"ENDPOINT 0x%X: %s %s" % (self.bEndpointAddress,
_lu.ep_attributes[(self.bmAttributes & 0x3)],
direction))
class Interface(object):
r"""Represent an interface object.
This class contains all fields of the Interface Descriptor
according to the USB Specification. You may access them as class
properties. For example, to access the field bInterfaceNumber
of the interface descriptor, you can do so:
>>> import usb.core
>>> dev = usb.core.find()
>>> for cfg in dev:
>>> for i in cfg:
>>> print i.bInterfaceNumber
"""
def __init__(self, device, interface = 0,
alternate_setting = 0, configuration = 0):
r"""Initialize the interface object.
The device parameter is the device object returned by the find()
function. The configuration parameter is the logical index of the
configuration (not the bConfigurationValue field). The interface
parameter is the interface logical index (not the bInterfaceNumber
field) and alternate_setting is the alternate setting logical index
(not the bAlternateSetting value). An interface may have only one
alternate setting. In this case, the alternate_setting parameter
should be zero. By "logical index" we mean the relative order of
the configurations returned by the peripheral as a result of
GET_DESCRIPTOR request.
"""
self.device = device
self.alternate_index = alternate_setting
self.index = interface
self.configuration = configuration
backend = device._ctx.backend
desc = backend.get_interface_descriptor(
self.device._ctx.dev,
interface,
alternate_setting,
configuration
)
_set_attr(
desc,
self,
(
'bLength',
'bDescriptorType',
'bInterfaceNumber',
'bAlternateSetting',
'bNumEndpoints',
'bInterfaceClass',
'bInterfaceSubClass',
'bInterfaceProtocol',
'iInterface',
'extra_descriptors'
)
)
def __repr__(self):
return "<" + self._str() + ">"
def __str__(self):
"""Show all information for the interface."""
string = self._get_full_descriptor_str()
for endpoint in self:
string += "\n" + str(endpoint)
return string
def endpoints(self):
r"""Return a tuple of the interface endpoints."""
return tuple(self)
def set_altsetting(self):
r"""Set the interface alternate setting."""
self.device.set_interface_altsetting(
self.bInterfaceNumber,
self.bAlternateSetting)
def __iter__(self):
r"""Iterate over all endpoints of the interface."""
for i in range(self.bNumEndpoints):
yield Endpoint(
self.device,
i,
self.index,
self.alternate_index,
self.configuration)
def __getitem__(self, index):
r"""Return the Endpoint object in the given position."""
return Endpoint(
self.device,
index,
self.index,
self.alternate_index,
self.configuration)
def _str(self):
if self.bAlternateSetting:
alt_setting = ", %d" % self.bAlternateSetting
else:
alt_setting = ""
return "INTERFACE %d%s: %s" % (self.bInterfaceNumber, alt_setting,
_try_lookup(_lu.interface_classes, self.bInterfaceClass,
default = "Unknown Class"))
def _get_full_descriptor_str(self):
headstr = " " + self._str() + " "
return "%s%s\n" % (headstr, "=" * (60 - len(headstr))) + \
" %-19s:%#7x (9 bytes)\n" % (
"bLength", self.bLength) + \
" %-19s:%#7x %s\n" % (
"bDescriptorType", self.bDescriptorType,
_try_lookup(_lu.descriptors, self.bDescriptorType)) + \
" %-19s:%#7x\n" % (
"bInterfaceNumber", self.bInterfaceNumber) + \
" %-19s:%#7x\n" % (
"bAlternateSetting", self.bAlternateSetting) + \
" %-19s:%#7x\n" % (
"bNumEndpoints", self.bNumEndpoints) + \
" %-19s:%#7x %s\n" % (
"bInterfaceClass", self.bInterfaceClass,
_try_lookup(_lu.interface_classes, self.bInterfaceClass)) + \
" %-19s:%#7x\n" % (
"bInterfaceSubClass", self.bInterfaceSubClass) + \
" %-19s:%#7x\n" % (
"bInterfaceProtocol", self.bInterfaceProtocol) + \
" %-19s:%#7x %s" % (
"iInterface", self.iInterface,
_try_get_string(self.device, self.iInterface))
class Configuration(object):
r"""Represent a configuration object.
This class contains all fields of the Configuration Descriptor according to
the USB Specification. You may access them as class properties. For
example, to access the field bConfigurationValue of the configuration
descriptor, you can do so:
>>> import usb.core
>>> dev = usb.core.find()
>>> for cfg in dev:
>>> print cfg.bConfigurationValue
"""
def __init__(self, device, configuration = 0):
r"""Initialize the configuration object.
The device parameter is the device object returned by the find()
function. The configuration parameter is the logical index of the
configuration (not the bConfigurationValue field). By "logical index"
we mean the relative order of the configurations returned by the
peripheral as a result of GET_DESCRIPTOR request.
"""
self.device = device
self.index = configuration
backend = device._ctx.backend
desc = backend.get_configuration_descriptor(
self.device._ctx.dev,
configuration
)
_set_attr(
desc,
self,
(
'bLength',
'bDescriptorType',
'wTotalLength',
'bNumInterfaces',
'bConfigurationValue',
'iConfiguration',
'bmAttributes',
'bMaxPower',
'extra_descriptors'
)
)
def __repr__(self):
return "<" + self._str() + ">"
def __str__(self):
string = self._get_full_descriptor_str()
for interface in self:
string += "\n%s" % str(interface)
return string
def interfaces(self):
r"""Return a tuple of the configuration interfaces."""
return tuple(self)
def set(self):
r"""Set this configuration as the active one."""
self.device.set_configuration(self.bConfigurationValue)
def __iter__(self):
r"""Iterate over all interfaces of the configuration."""
for i in range(self.bNumInterfaces):
alt = 0
try:
while True:
yield Interface(self.device, i, alt, self.index)
alt += 1
except (USBError, IndexError):
pass
def __getitem__(self, index):
r"""Return the Interface object in the given position.
index is a tuple of two values with interface index and
alternate setting index, respectivally. Example:
>>> interface = config[(0, 0)]
"""
return Interface(self.device, index[0], index[1], self.index)
def _str(self):
return "CONFIGURATION %d: %d mA" % (
self.bConfigurationValue,
_lu.MAX_POWER_UNITS_USB2p0 * self.bMaxPower)
def _get_full_descriptor_str(self):
headstr = " " + self._str() + " "
if self.bmAttributes & (1<<6):
powered = "Self"
else:
powered = "Bus"
if self.bmAttributes & (1<<5):
remote_wakeup = ", Remote Wakeup"
else:
remote_wakeup = ""
return "%s%s\n" % (headstr, "=" * (60 - len(headstr))) + \
" %-21s:%#7x (9 bytes)\n" % (
"bLength", self.bLength) + \
" %-21s:%#7x %s\n" % (
"bDescriptorType", self.bDescriptorType,
_try_lookup(_lu.descriptors, self.bDescriptorType)) + \
" %-21s:%#7x (%d bytes)\n" % (
"wTotalLength", self.wTotalLength, self.wTotalLength) + \
" %-21s:%#7x\n" % (
"bNumInterfaces", self.bNumInterfaces) + \
" %-21s:%#7x\n" % (
"bConfigurationValue", self.bConfigurationValue) + \
" %-21s:%#7x %s\n" % (
"iConfiguration", self.iConfiguration,
_try_get_string(self.device, self.iConfiguration)) + \
" %-21s:%#7x %s Powered%s\n" % (
"bmAttributes", self.bmAttributes, powered, remote_wakeup
# bit 7 is high, bit 4..0 are 0
) + \
" %-21s:%#7x (%d mA)" % (
"bMaxPower", self.bMaxPower,
_lu.MAX_POWER_UNITS_USB2p0 * self.bMaxPower)
# FIXME : add a check for superspeed vs usb 2.0
class Device(_objfinalizer.AutoFinalizedObject):
r"""Device object.
This class contains all fields of the Device Descriptor according to the
USB Specification. You may access them as class properties. For example,
to access the field bDescriptorType of the device descriptor, you can
do so:
>>> import usb.core
>>> dev = usb.core.find()
>>> dev.bDescriptorType
Additionally, the class provides methods to communicate with the hardware.
Typically, an application will first call the set_configuration() method to
put the device in a known configured state, optionally call the
set_interface_altsetting() to select the alternate setting (if there is
more than one) of the interface used, and call the write() and read()
methods to send and receive data, respectively.
When working in a new hardware, the first try could be like this:
>>> import usb.core
>>> dev = usb.core.find(idVendor=myVendorId, idProduct=myProductId)
>>> dev.set_configuration()
>>> dev.write(1, 'test')
This sample finds the device of interest (myVendorId and myProductId should
be replaced by the corresponding values of your device), then configures
the device (by default, the configuration value is 1, which is a typical
value for most devices) and then writes some data to the endpoint 0x01.
Timeout values for the write, read and ctrl_transfer methods are specified
in miliseconds. If the parameter is omitted, Device.default_timeout value
will be used instead. This property can be set by the user at anytime.
"""
def __repr__(self):
return "<" + self._str() + ">"
def __str__(self):
string = self._get_full_descriptor_str()
try:
for configuration in self:
string += "\n%s" % str(configuration)
except USBError:
try:
configuration = self.get_active_configuration()
string += "\n%s" % (configuration.info)
except USBError:
string += " USBError Accessing Configurations"
return string
def configurations(self):
r"""Return a tuple of the device configurations."""
return tuple(self)
def __init__(self, dev, backend):
r"""Initialize the Device object.
Library users should normally get a Device instance through
the find function. The dev parameter is the identification
of a device to the backend and its meaning is opaque outside
of it. The backend parameter is a instance of a backend
object.
"""
self._ctx = _ResourceManager(dev, backend)
self.__default_timeout = _DEFAULT_TIMEOUT
self._serial_number, self._product, self._manufacturer = None, None, None
self._langids = None
desc = backend.get_device_descriptor(dev)
_set_attr(
desc,
self,
(
'bLength',
'bDescriptorType',
'bcdUSB',
'bDeviceClass',
'bDeviceSubClass',
'bDeviceProtocol',
'bMaxPacketSize0',
'idVendor',
'idProduct',
'bcdDevice',
'iManufacturer',
'iProduct',
'iSerialNumber',
'bNumConfigurations',
'address',
'bus',
'port_number',
'port_numbers',
'speed',
)
)
if desc.bus is not None:
self.bus = int(desc.bus)
else:
self.bus = None
if desc.address is not None:
self.address = int(desc.address)
else:
self.address = None
if desc.port_number is not None:
self.port_number = int(desc.port_number)
else:
self.port_number = None
if desc.speed is not None:
self.speed = int(desc.speed)
else:
self.speed = None
@property
def langids(self):
""" Return the USB device's supported language ID codes.
These are 16-bit codes familiar to Windows developers, where for
example instead of en-US you say 0x0409. USB_LANGIDS.pdf on the usb.org
developer site for more info. String requests using a LANGID not
in this array should not be sent to the device.
This property will cause some USB traffic the first time it is accessed
and cache the resulting value for future use.
"""
if self._langids is None:
try:
self._langids = util.get_langids(self)
except USBError:
self._langids = ()
return self._langids
@property
def serial_number(self):
""" Return the USB device's serial number string descriptor.
This property will cause some USB traffic the first time it is accessed
and cache the resulting value for future use.
"""
if self._serial_number is None:
self._serial_number = util.get_string(self, self.iSerialNumber)
return self._serial_number
@property
def product(self):
""" Return the USB device's product string descriptor.
This property will cause some USB traffic the first time it is accessed
and cache the resulting value for future use.
"""
if self._product is None:
self._product = util.get_string(self, self.iProduct)
return self._product
@property
def manufacturer(self):
""" Return the USB device's manufacturer string descriptor.
This property will cause some USB traffic the first time it is accessed
and cache the resulting value for future use.
"""
if self._manufacturer is None:
self._manufacturer = util.get_string(self, self.iManufacturer)
return self._manufacturer
@property
def backend(self):
"""Return the backend being used by the device."""
return self._ctx.backend
def set_configuration(self, configuration = None):
r"""Set the active configuration.
The configuration parameter is the bConfigurationValue field of the
configuration you want to set as active. If you call this method
without parameter, it will use the first configuration found. As a
device hardly ever has more than one configuration, calling the method
without arguments is enough to get the device ready.
"""
self._ctx.managed_set_configuration(self, configuration)
def get_active_configuration(self):
r"""Return a Configuration object representing the current
configuration set.
"""
return self._ctx.get_active_configuration(self)
def set_interface_altsetting(self, interface = None, alternate_setting = None):
r"""Set the alternate setting for an interface.
When you want to use an interface and it has more than one alternate
setting, you should call this method to select the appropriate
alternate setting. If you call the method without one or the two
parameters, it will be selected the first one found in the Device in
the same way of the set_configuration method.
Commonly, an interface has only one alternate setting and this call is
not necessary. For most devices, either it has more than one
alternate setting or not, it is not harmful to make a call to this
method with no arguments, as devices will silently ignore the request
when there is only one alternate setting, though the USB Spec allows
devices with no additional alternate setting return an error to the
Host in response to a SET_INTERFACE request.
If you are in doubt, you may want to call it with no arguments wrapped
by a try/except clause:
>>> try:
>>> dev.set_interface_altsetting()
>>> except usb.core.USBError:
>>> pass
"""
self._ctx.managed_set_interface(self, interface, alternate_setting)
def clear_halt(self, ep):
r""" Clear the halt/stall condition for the endpoint ep."""
if isinstance(ep, Endpoint):
ep = ep.bEndpointAddress
self._ctx.managed_open()
self._ctx.backend.clear_halt(self._ctx.handle, ep)
def reset(self):
r"""Reset the device."""
self._ctx.managed_open()
self._ctx.dispose(self, False)
self._ctx.backend.reset_device(self._ctx.handle)
self._ctx.dispose(self, True)
def write(self, endpoint, data, timeout = None):
r"""Write data to the endpoint.
This method is used to send data to the device. The endpoint parameter
corresponds to the bEndpointAddress member whose endpoint you want to
communicate with.
The data parameter should be a sequence like type convertible to
the array type (see array module).
The timeout is specified in miliseconds.
The method returns the number of bytes written.
"""
backend = self._ctx.backend
fn_map = {
util.ENDPOINT_TYPE_BULK:backend.bulk_write,
util.ENDPOINT_TYPE_INTR:backend.intr_write,
util.ENDPOINT_TYPE_ISO:backend.iso_write
}
intf, ep = self._ctx.setup_request(self, endpoint)
fn = fn_map[util.endpoint_type(ep.bmAttributes)]
return fn(
self._ctx.handle,
ep.bEndpointAddress,
intf.bInterfaceNumber,
_interop.as_array(data),
self.__get_timeout(timeout)
)
def read(self, endpoint, size_or_buffer, timeout = None):
r"""Read data from the endpoint.
This method is used to receive data from the device. The endpoint
parameter corresponds to the bEndpointAddress member whose endpoint
you want to communicate with. The size_or_buffer parameter either
tells how many bytes you want to read or supplies the buffer to
receive the data (it *must* be an object of the type array).
The timeout is specified in miliseconds.
If the size_or_buffer parameter is the number of bytes to read, the
method returns an array object with the data read. If the
size_or_buffer parameter is an array object, it returns the number
of bytes actually read.
"""
backend = self._ctx.backend
fn_map = {
util.ENDPOINT_TYPE_BULK:backend.bulk_read,
util.ENDPOINT_TYPE_INTR:backend.intr_read,
util.ENDPOINT_TYPE_ISO:backend.iso_read
}
intf, ep = self._ctx.setup_request(self, endpoint)
fn = fn_map[util.endpoint_type(ep.bmAttributes)]
if isinstance(size_or_buffer, array.array):
buff = size_or_buffer
else: # here we consider it is a integer
buff = util.create_buffer(size_or_buffer)
ret = fn(
self._ctx.handle,
ep.bEndpointAddress,
intf.bInterfaceNumber,
buff,
self.__get_timeout(timeout))
if isinstance(size_or_buffer, array.array):
return ret
elif ret != len(buff) * buff.itemsize:
return buff[:ret]
else:
return buff
def ctrl_transfer(self, bmRequestType, bRequest, wValue=0, wIndex=0,
data_or_wLength = None, timeout = None):
r"""Do a control transfer on the endpoint 0.
This method is used to issue a control transfer over the endpoint 0
(endpoint 0 is required to always be a control endpoint).
The parameters bmRequestType, bRequest, wValue and wIndex are the same
of the USB Standard Control Request format.
Control requests may or may not have a data payload to write/read.
In cases which it has, the direction bit of the bmRequestType
field is used to infer the desired request direction. For
host to device requests (OUT), data_or_wLength parameter is
the data payload to send, and it must be a sequence type convertible
to an array object. In this case, the return value is the number
of bytes written in the data payload. For device to host requests
(IN), data_or_wLength is either the wLength parameter of the control
request specifying the number of bytes to read in data payload, and
the return value is an array object with data read, or an array
object which the data will be read to, and the return value is the
number of bytes read.
"""
try:
buff = util.create_buffer(data_or_wLength)
except TypeError:
buff = _interop.as_array(data_or_wLength)
self._ctx.managed_open()
# Thanks to Johannes Stezenbach to point me out that we need to
# claim the recipient interface
recipient = bmRequestType & 3
rqtype = bmRequestType & (3 << 5)
if recipient == util.CTRL_RECIPIENT_INTERFACE \
and rqtype != util.CTRL_TYPE_VENDOR:
interface_number = wIndex & 0xff
self._ctx.managed_claim_interface(self, interface_number)
ret = self._ctx.backend.ctrl_transfer(
self._ctx.handle,
bmRequestType,
bRequest,
wValue,
wIndex,
buff,
self.__get_timeout(timeout))
if isinstance(data_or_wLength, array.array) \
or util.ctrl_direction(bmRequestType) == util.CTRL_OUT:
return ret
elif ret != len(buff) * buff.itemsize:
return buff[:ret]
else:
return buff
def is_kernel_driver_active(self, interface):
r"""Determine if there is kernel driver associated with the interface.
If a kernel driver is active, the object will be unable to perform
I/O.
The interface parameter is the device interface number to check.
"""
self._ctx.managed_open()
return self._ctx.backend.is_kernel_driver_active(
self._ctx.handle,
interface)
def detach_kernel_driver(self, interface):
r"""Detach a kernel driver.
If successful, you will then be able to perform I/O.
The interface parameter is the device interface number to detach the
driver from.
"""
self._ctx.managed_open()
self._ctx.backend.detach_kernel_driver(
self._ctx.handle,
interface)
def attach_kernel_driver(self, interface):
r"""Re-attach an interface's kernel driver, which was previously
detached using detach_kernel_driver().
The interface parameter is the device interface number to attach the
driver to.
"""
self._ctx.managed_open()
self._ctx.backend.attach_kernel_driver(
self._ctx.handle,
interface)
def __iter__(self):
r"""Iterate over all configurations of the device."""
for i in range(self.bNumConfigurations):
yield Configuration(self, i)
def __getitem__(self, index):
r"""Return the Configuration object in the given position."""
return Configuration(self, index)
def _finalize_object(self):
self._ctx.dispose(self)
def __get_timeout(self, timeout):
if timeout is not None:
return timeout
return self.__default_timeout
def __set_def_tmo(self, tmo):
if tmo < 0:
raise ValueError('Timeout cannot be a negative value')
self.__default_timeout = tmo
def __get_def_tmo(self):
return self.__default_timeout
def _str(self):
return "DEVICE ID %04x:%04x on Bus %03d Address %03d" % (
self.idVendor, self.idProduct, self.bus, self.address)
def _get_full_descriptor_str(self):
headstr = self._str() + " "
if self.bcdUSB & 0xf:
low_bcd_usb = str(self.bcdUSB & 0xf)
else:
low_bcd_usb = ""
if self.bcdDevice & 0xf:
low_bcd_device = str(self.bcdDevice & 0xf)
else:
low_bcd_device = ""
return "%s%s\n" % (headstr, "=" * (60 - len(headstr))) + \
" %-23s:%#7x (18 bytes)\n" % (
"bLength", self.bLength) + \
" %-23s:%#7x %s\n" % (
"bDescriptorType", self.bDescriptorType,
_try_lookup(_lu.descriptors, self.bDescriptorType)) + \
" %-23s:%#7x USB %d.%d%s\n" % (
"bcdUSB", self.bcdUSB, (self.bcdUSB & 0xff00)>>8,
(self.bcdUSB & 0xf0) >> 4, low_bcd_usb) + \
" %-23s:%#7x %s\n" % (
"bDeviceClass", self.bDeviceClass,
_try_lookup(_lu.device_classes, self.bDeviceClass)) + \
" %-23s:%#7x\n" % (
"bDeviceSubClass", self.bDeviceSubClass) + \
" %-23s:%#7x\n" % (
"bDeviceProtocol", self.bDeviceProtocol) + \
" %-23s:%#7x (%d bytes)\n" % (
"bMaxPacketSize0", self.bMaxPacketSize0, self.bMaxPacketSize0) + \
" %-23s: %#06x\n" % (
"idVendor", self.idVendor) + \
" %-23s: %#06x\n" % (
"idProduct", self.idProduct) + \
" %-23s:%#7x Device %d.%d%s\n" % (
"bcdDevice", self.bcdDevice, (self.bcdDevice & 0xff00)>>8,
(self.bcdDevice & 0xf0) >> 4, low_bcd_device) + \
" %-23s:%#7x %s\n" % (
"iManufacturer", self.iManufacturer,
_try_get_string(self, self.iManufacturer)) + \
" %-23s:%#7x %s\n" % (
"iProduct", self.iProduct,
_try_get_string(self, self.iProduct)) + \
" %-23s:%#7x %s\n" % (
"iSerialNumber", self.iSerialNumber,
_try_get_string(self, self.iSerialNumber)) + \
" %-23s:%#7x" % (
"bNumConfigurations", self.bNumConfigurations)
default_timeout = property(
__get_def_tmo,
__set_def_tmo,
doc = 'Default timeout for transfer I/O functions'
)
def find(find_all=False, backend = None, custom_match = None, **args):
r"""Find an USB device and return it.
find() is the function used to discover USB devices. You can pass as
arguments any combination of the USB Device Descriptor fields to match a
device. For example:
find(idVendor=0x3f4, idProduct=0x2009)
will return the Device object for the device with idVendor field equals
to 0x3f4 and idProduct equals to 0x2009.
If there is more than one device which matchs the criteria, the first one
found will be returned. If a matching device cannot be found the function
returns None. If you want to get all devices, you can set the parameter
find_all to True, then find will return an iterator with all matched devices.
If no matching device is found, it will return an empty iterator. Example:
for printer in find(find_all=True, bDeviceClass=7):
print (printer)
This call will get all the USB printers connected to the system. (actually
may be not, because some devices put their class information in the
Interface Descriptor).
You can also use a customized match criteria:
dev = find(custom_match = lambda d: d.idProduct=0x3f4 and d.idvendor=0x2009)
A more accurate printer finder using a customized match would be like
so:
def is_printer(dev):
import usb.util
if dev.bDeviceClass == 7:
return True
for cfg in dev:
if usb.util.find_descriptor(cfg, bInterfaceClass=7) is not None:
return True
for printer in find(find_all=True, custom_match = is_printer):
print (printer)
Now even if the device class code is in the interface descriptor the
printer will be found.
You can combine a customized match with device descriptor fields. In this
case, the fields must match and the custom_match must return True. In the
our previous example, if we would like to get all printers belonging to the
manufacturer 0x3f4, the code would be like so:
printers = list(find(find_all=True, idVendor=0x3f4, custom_match=is_printer))
If you want to use find as a 'list all devices' function, just call
it with find_all = True:
devices = list(find(find_all=True))
Finally, you can pass a custom backend to the find function:
find(backend = MyBackend())
PyUSB has builtin backends for libusb 0.1, libusb 1.0 and OpenUSB. If you
do not supply a backend explicitly, find() function will select one of the
predefineds backends according to system availability.
Backends are explained in the usb.backend module.
"""
def device_iter(**kwargs):
for dev in backend.enumerate_devices():
d = Device(dev, backend)
tests = (val == getattr(d, key) for key, val in kwargs.items())
if _interop._all(tests) and (custom_match is None or custom_match(d)):
yield d
if backend is None:
import usb.backend.libusb1 as libusb1
import usb.backend.libusb0 as libusb0
import usb.backend.openusb as openusb
for m in (libusb1, openusb, libusb0):
backend = m.get_backend()
if backend is not None:
_logger.info('find(): using backend "%s"', m.__name__)
break
else:
raise NoBackendError('No backend available')
if find_all:
return device_iter(**args)
else:
try:
return _interop._next(device_iter(**args))
except StopIteration:
return None
def show_devices(verbose=False, **kwargs):
"""Show information about connected devices.
The verbose flag sets to verbose or not.
**kwargs are passed directly to the find() function.
"""
kwargs["find_all"] = True
devices = find(**kwargs)
strings = ""
for device in devices:
if not verbose:
strings += "%s, %s\n" % (device._str(), _try_lookup(
_lu.device_classes, device.bDeviceClass))
else:
strings += "%s\n\n" % str(device)
return _DescriptorInfo(strings)
pyusb-1.0.0/usb/legacy.py 0000664 0001750 0001750 00000030440 12661452153 016053 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
import usb.core as core
import usb.util as util
import usb._objfinalizer as _objfinalizer
import usb.control as control
from itertools import groupby
__author__ = 'Wander Lairson Costa'
USBError = core.USBError
CLASS_AUDIO = 1
CLASS_COMM = 2
CLASS_DATA = 10
CLASS_HID = 3
CLASS_HUB = 9
CLASS_MASS_STORAGE = 8
CLASS_PER_INTERFACE = 0
CLASS_PRINTER = 7
CLASS_VENDOR_SPEC = 255
DT_CONFIG = 2
DT_CONFIG_SIZE = 9
DT_DEVICE = 1
DT_DEVICE_SIZE = 18
DT_ENDPOINT = 5
DT_ENDPOINT_AUDIO_SIZE = 9
DT_ENDPOINT_SIZE = 7
DT_HID = 33
DT_HUB = 41
DT_HUB_NONVAR_SIZE = 7
DT_INTERFACE = 4
DT_INTERFACE_SIZE = 9
DT_PHYSICAL = 35
DT_REPORT = 34
DT_STRING = 3
ENDPOINT_ADDRESS_MASK = 15
ENDPOINT_DIR_MASK = 128
ENDPOINT_IN = 128
ENDPOINT_OUT = 0
ENDPOINT_TYPE_BULK = 2
ENDPOINT_TYPE_CONTROL = 0
ENDPOINT_TYPE_INTERRUPT = 3
ENDPOINT_TYPE_ISOCHRONOUS = 1
ENDPOINT_TYPE_MASK = 3
ERROR_BEGIN = 500000
MAXALTSETTING = 128
MAXCONFIG = 8
MAXENDPOINTS = 32
MAXINTERFACES = 32
RECIP_DEVICE = 0
RECIP_ENDPOINT = 2
RECIP_INTERFACE = 1
RECIP_OTHER = 3
REQ_CLEAR_FEATURE = 1
REQ_GET_CONFIGURATION = 8
REQ_GET_DESCRIPTOR = 6
REQ_GET_INTERFACE = 10
REQ_GET_STATUS = 0
REQ_SET_ADDRESS = 5
REQ_SET_CONFIGURATION = 9
REQ_SET_DESCRIPTOR = 7
REQ_SET_FEATURE = 3
REQ_SET_INTERFACE = 11
REQ_SYNCH_FRAME = 12
TYPE_CLASS = 32
TYPE_RESERVED = 96
TYPE_STANDARD = 0
TYPE_VENDOR = 64
class Endpoint(object):
r"""Endpoint descriptor object."""
def __init__(self, ep):
self.address = ep.bEndpointAddress
self.interval = ep.bInterval
self.maxPacketSize = ep.wMaxPacketSize
self.type = util.endpoint_type(ep.bmAttributes)
class Interface(object):
r"""Interface descriptor object."""
def __init__(self, intf):
self.alternateSetting = intf.bAlternateSetting
self.interfaceNumber = intf.bInterfaceNumber
self.iInterface = intf.iInterface
self.interfaceClass = intf.bInterfaceClass
self.interfaceSubClass = intf.bInterfaceSubClass
self.interfaceProtocol = intf.bInterfaceProtocol
self.endpoints = [Endpoint(e) for e in intf]
class Configuration(object):
r"""Configuration descriptor object."""
def __init__(self, cfg):
self.iConfiguration = cfg.iConfiguration
self.maxPower = cfg.bMaxPower << 1
self.remoteWakeup = (cfg.bmAttributes >> 5) & 1
self.selfPowered = (cfg.bmAttributes >> 6) & 1
self.totalLength = cfg.wTotalLength
self.value = cfg.bConfigurationValue
self.interfaces = [
list(g) for k, g in groupby(
sorted(
[Interface(i) for i in cfg],
key=lambda i: i.interfaceNumber
),
lambda i: i.alternateSetting)
]
class DeviceHandle(_objfinalizer.AutoFinalizedObject):
def __init__(self, dev):
self.dev = dev
self.__claimed_interface = None
def _finalize_object(self):
util.dispose_resources(self.dev)
self.dev = None
def bulkWrite(self, endpoint, buffer, timeout = 100):
r"""Perform a bulk write request to the endpoint specified.
Arguments:
endpoint: endpoint number.
buffer: sequence data buffer to write.
This parameter can be any sequence type.
timeout: operation timeout in miliseconds. (default: 100)
Returns the number of bytes written.
"""
return self.dev.write(endpoint, buffer, timeout)
def bulkRead(self, endpoint, size, timeout = 100):
r"""Performs a bulk read request to the endpoint specified.
Arguments:
endpoint: endpoint number.
size: number of bytes to read.
timeout: operation timeout in miliseconds. (default: 100)
Return a tuple with the data read.
"""
return self.dev.read(endpoint, size, timeout)
def interruptWrite(self, endpoint, buffer, timeout = 100):
r"""Perform a interrupt write request to the endpoint specified.
Arguments:
endpoint: endpoint number.
buffer: sequence data buffer to write.
This parameter can be any sequence type.
timeout: operation timeout in miliseconds. (default: 100)
Returns the number of bytes written.
"""
return self.dev.write(endpoint, buffer, timeout)
def interruptRead(self, endpoint, size, timeout = 100):
r"""Performs a interrupt read request to the endpoint specified.
Arguments:
endpoint: endpoint number.
size: number of bytes to read.
timeout: operation timeout in miliseconds. (default: 100)
Return a tuple with the data read.
"""
return self.dev.read(endpoint, size, timeout)
def controlMsg(self, requestType, request, buffer, value = 0, index = 0, timeout = 100):
r"""Perform a control request to the default control pipe on a device.
Arguments:
requestType: specifies the direction of data flow, the type
of request, and the recipient.
request: specifies the request.
buffer: if the transfer is a write transfer, buffer is a sequence
with the transfer data, otherwise, buffer is the number of
bytes to read.
value: specific information to pass to the device. (default: 0)
index: specific information to pass to the device. (default: 0)
timeout: operation timeout in miliseconds. (default: 100)
Return the number of bytes written.
"""
return self.dev.ctrl_transfer(
requestType,
request,
wValue = value,
wIndex = index,
data_or_wLength = buffer,
timeout = timeout)
def clearHalt(self, endpoint):
r"""Clears any halt status on the specified endpoint.
Arguments:
endpoint: endpoint number.
"""
self.dev.clear_halt(endpoint)
def claimInterface(self, interface):
r"""Claims the interface with the Operating System.
Arguments:
interface: interface number or an Interface object.
"""
if isinstance(interface, Interface):
interface = interface.interfaceNumber
util.claim_interface(self.dev, interface)
self.__claimed_interface = interface
def releaseInterface(self):
r"""Release an interface previously claimed with claimInterface."""
util.release_interface(self.dev, self.__claimed_interface)
self.__claimed_interface = -1
def reset(self):
r"""Reset the specified device by sending a RESET
down the port it is connected to."""
self.dev.reset()
def resetEndpoint(self, endpoint):
r"""Reset all states for the specified endpoint.
Arguments:
endpoint: endpoint number.
"""
self.clearHalt(endpoint)
def setConfiguration(self, configuration):
r"""Set the active configuration of a device.
Arguments:
configuration: a configuration value or a Configuration object.
"""
if isinstance(configuration, Configuration):
configuration = configuration.value
self.dev.set_configuration(configuration)
def setAltInterface(self, alternate):
r"""Sets the active alternate setting of the current interface.
Arguments:
alternate: an alternate setting number or an Interface object.
"""
if isinstance(alternate, Interface):
alternate = alternate.alternateSetting
self.dev.set_interface_altsetting(self.__claimed_interface, alternate)
def getString(self, index, length, langid = None):
r"""Retrieve the string descriptor specified by index
and langid from a device.
Arguments:
index: index of descriptor in the device.
length: number of bytes of the string (ignored)
langid: Language ID. If it is omittedi, will be
used the first language.
"""
return util.get_string(self.dev, index, langid).encode('ascii')
def getDescriptor(self, desc_type, desc_index, length, endpoint = -1):
r"""Retrieves a descriptor from the device identified by the type
and index of the descriptor.
Arguments:
desc_type: descriptor type.
desc_index: index of the descriptor.
len: descriptor length.
endpoint: ignored.
"""
return control.get_descriptor(self.dev, length, desc_type, desc_index)
def detachKernelDriver(self, interface):
r"""Detach a kernel driver from the interface (if one is attached,
we have permission and the operation is supported by the OS)
Arguments:
interface: interface number or an Interface object.
"""
if isinstance(interface, Interface):
interface = interface.interfaceNumber
self.dev.detach_kernel_driver(interface)
class Device(object):
r"""Device descriptor object"""
def __init__(self, dev):
self.deviceClass = dev.bDeviceClass
self.deviceSubClass = dev.bDeviceSubClass
self.deviceProtocol = dev.bDeviceProtocol
self.deviceVersion = str((dev.bcdDevice >> 12) & 0xf) + \
str((dev.bcdDevice >> 8) & 0xf) + \
'.' + \
str((dev.bcdDevice >> 4) & 0xf) + \
str(dev.bcdDevice & 0xf)
self.devnum = None
self.filename = ''
self.iManufacturer = dev.iManufacturer
self.iProduct = dev.iProduct
self.iSerialNumber = dev.iSerialNumber
self.idProduct = dev.idProduct
self.idVendor = dev.idVendor
self.maxPacketSize = dev.bMaxPacketSize0
self.usbVersion = str((dev.bcdUSB >> 12) & 0xf) + \
str((dev.bcdUSB >> 8) & 0xf) + \
'.' + \
str((dev.bcdUSB >> 4) & 0xf) + \
str(dev.bcdUSB & 0xf)
self.configurations = [Configuration(c) for c in dev]
self.dev = dev
def open(self):
r"""Open the device for use.
Return a DeviceHandle object
"""
return DeviceHandle(self.dev)
class Bus(object):
r"""Bus object."""
def __init__(self, devices):
self.dirname = ''
self.location = 0
self.devices = [Device(d) for d in devices]
def busses():
r"""Return a tuple with the usb busses."""
return (Bus(g) for k, g in groupby(
sorted(core.find(find_all=True), key=lambda d: d.bus),
lambda d: d.bus))
pyusb-1.0.0/usb/_interop.py 0000664 0001750 0001750 00000006702 12661452153 016432 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
# All the hacks necessary to assure compatibility across all
# supported versions come here.
# Please, note that there is one version check for each
# hack we need to do, this makes maintenance easier... ^^
import sys
import array
__all__ = ['_reduce', '_set', '_next', '_update_wrapper']
# we support Python >= 2.4
assert sys.hexversion >= 0x020400f0
# On Python 3, reduce became a functools module function
try:
import functools
_reduce = functools.reduce
except (ImportError, AttributeError):
_reduce = reduce
# all, introduced in Python 2.5
try:
_all = all
except NameError:
_all = lambda iter_ : _reduce( lambda x, y: x and y, iter_, True )
# we only have the builtin set type since 2.5 version
try:
_set = set
except NameError:
import sets
_set = sets.Set
# On Python >= 2.6, we have the builtin next() function
# On Python 2.5 and before, we have to call the iterator method next()
def _next(iter):
try:
return next(iter)
except NameError:
return iter.next()
# functools appeared in 2.5
try:
import functools
_update_wrapper = functools.update_wrapper
except (ImportError, AttributeError):
def _update_wrapper(wrapper, wrapped):
wrapper.__name__ = wrapped.__name__
wrapper.__module__ = wrapped.__module__
wrapper.__doc__ = wrapped.__doc__
wrapper.__dict__ = wrapped.__dict__
# this is used (as of May 2015) twice in core, once in backend/openusb, and in
# some unit test code. It would probably be clearer if written in terms of some
# definite 3.2+ API (bytearrays?) with a fallback provided for 2.4+.
def as_array(data=None):
if data is None:
return array.array('B')
if isinstance(data, array.array):
return data
try:
return array.array('B', data)
except TypeError:
# When you pass a unicode string or a character sequence,
# you get a TypeError if the first parameter does not match
a = array.array('B')
a.fromstring(data) # deprecated since 3.2
return a
pyusb-1.0.0/usb/_objfinalizer.py 0000664 0001750 0001750 00000012247 12661452153 017431 0 ustar wander wander 0000000 0000000 # -*- coding: utf-8 -*-
#
# Copyright (C) 2014 André Erdmann
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
import sys
__all__ = ['AutoFinalizedObject']
class _AutoFinalizedObjectBase(object):
"""
Base class for objects that get automatically
finalized on delete or at exit.
"""
def _finalize_object(self):
"""Actually finalizes the object (frees allocated resources etc.).
Returns: None
Derived classes should implement this.
"""
pass
def __new__(cls, *args, **kwargs):
"""Creates a new object instance and adds the private finalizer
attributes to it.
Returns: new object instance
Arguments:
* *args, **kwargs -- ignored
"""
instance = super(_AutoFinalizedObjectBase, cls).__new__(cls)
instance._finalize_called = False
return instance
def _do_finalize_object(self):
"""Helper method that finalizes the object if not already done.
Returns: None
"""
if not self._finalize_called: # race-free?
self._finalize_called = True
self._finalize_object()
def finalize(self):
"""Finalizes the object if not already done.
Returns: None
"""
# this is the "public" finalize method
raise NotImplementedError(
"finalize() must be implemented by AutoFinalizedObject."
)
def __del__(self):
self.finalize()
if sys.hexversion >= 0x3040000:
# python >= 3.4: use weakref.finalize
import weakref
def _do_finalize_object_ref(obj_ref):
"""Helper function for weakref.finalize() that dereferences a weakref
to an object and calls its _do_finalize_object() method if the object
is still alive. Does nothing otherwise.
Returns: None (implicit)
Arguments:
* obj_ref -- weakref to an object
"""
obj = obj_ref()
if obj is not None:
# else object disappeared
obj._do_finalize_object()
class AutoFinalizedObject(_AutoFinalizedObjectBase):
def __new__(cls, *args, **kwargs):
"""Creates a new object instance and adds the private finalizer
attributes to it.
Returns: new object instance
Arguments:
* *args, **kwargs -- passed to the parent instance creator
(which ignores them)
"""
# Note: Do not pass a (hard) reference to instance to the
# finalizer as func/args/kwargs, it'd keep the object
# alive until the program terminates.
# A weak reference is fine.
#
# Note 2: When using weakrefs and not calling finalize() in
# __del__, the object may already have disappeared
# when weakref.finalize() kicks in.
# Make sure that _finalizer() gets called,
# i.e. keep __del__() from the base class.
#
# Note 3: the _finalize_called attribute is (probably) useless
# for this class
instance = super(AutoFinalizedObject, cls).__new__(
cls, *args, **kwargs
)
instance._finalizer = weakref.finalize(
instance, _do_finalize_object_ref, weakref.ref(instance)
)
return instance
def finalize(self):
"""Finalizes the object if not already done."""
self._finalizer()
else:
# python < 3.4: keep the old behavior (rely on __del__),
# but don't call _finalize_object() more than once
class AutoFinalizedObject(_AutoFinalizedObjectBase):
def finalize(self):
"""Finalizes the object if not already done."""
self._do_finalize_object()
pyusb-1.0.0/usb/util.py 0000664 0001750 0001750 00000030003 12661452153 015557 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
r"""usb.util - Utility functions.
This module exports:
endpoint_address - return the endpoint absolute address.
endpoint_direction - return the endpoint transfer direction.
endpoint_type - return the endpoint type
ctrl_direction - return the direction of a control transfer
build_request_type - build a bmRequestType field of a control transfer.
find_descriptor - find an inner descriptor.
claim_interface - explicitly claim an interface.
release_interface - explicitly release an interface.
dispose_resources - release internal resources allocated by the object.
get_langids - retrieve the list of supported string languages from the device.
get_string - retrieve a string descriptor from the device.
"""
__author__ = 'Wander Lairson Costa'
import operator
import array
from sys import hexversion
import usb._interop as _interop
# descriptor type
DESC_TYPE_DEVICE = 0x01
DESC_TYPE_CONFIG = 0x02
DESC_TYPE_STRING = 0x03
DESC_TYPE_INTERFACE = 0x04
DESC_TYPE_ENDPOINT = 0x05
# endpoint direction
ENDPOINT_IN = 0x80
ENDPOINT_OUT = 0x00
# endpoint type
ENDPOINT_TYPE_CTRL = 0x00
ENDPOINT_TYPE_ISO = 0x01
ENDPOINT_TYPE_BULK = 0x02
ENDPOINT_TYPE_INTR = 0x03
# control request type
CTRL_TYPE_STANDARD = (0 << 5)
CTRL_TYPE_CLASS = (1 << 5)
CTRL_TYPE_VENDOR = (2 << 5)
CTRL_TYPE_RESERVED = (3 << 5)
# control request recipient
CTRL_RECIPIENT_DEVICE = 0
CTRL_RECIPIENT_INTERFACE = 1
CTRL_RECIPIENT_ENDPOINT = 2
CTRL_RECIPIENT_OTHER = 3
# control request direction
CTRL_OUT = 0x00
CTRL_IN = 0x80
_ENDPOINT_ADDR_MASK = 0x0f
_ENDPOINT_DIR_MASK = 0x80
_ENDPOINT_TRANSFER_TYPE_MASK = 0x03
_CTRL_DIR_MASK = 0x80
# For compatibility between Python 2 and 3
_dummy_s = '\x00'.encode('utf-8')
# speed type
SPEED_LOW = 1
SPEED_FULL = 2
SPEED_HIGH = 3
SPEED_SUPER = 4
SPEED_UNKNOWN = 0
def endpoint_address(address):
r"""Return the endpoint absolute address.
The address parameter is the bEndpointAddress field
of the endpoint descriptor.
"""
return address & _ENDPOINT_ADDR_MASK
def endpoint_direction(address):
r"""Return the endpoint direction.
The address parameter is the bEndpointAddress field
of the endpoint descriptor.
The possible return values are ENDPOINT_OUT or ENDPOINT_IN.
"""
return address & _ENDPOINT_DIR_MASK
def endpoint_type(bmAttributes):
r"""Return the transfer type of the endpoint.
The bmAttributes parameter is the bmAttributes field
of the endpoint descriptor.
The possible return values are: ENDPOINT_TYPE_CTRL,
ENDPOINT_TYPE_ISO, ENDPOINT_TYPE_BULK or ENDPOINT_TYPE_INTR.
"""
return bmAttributes & _ENDPOINT_TRANSFER_TYPE_MASK
def ctrl_direction(bmRequestType):
r"""Return the direction of a control request.
The bmRequestType parameter is the value of the
bmRequestType field of a control transfer.
The possible return values are CTRL_OUT or CTRL_IN.
"""
return bmRequestType & _CTRL_DIR_MASK
def build_request_type(direction, type, recipient):
r"""Build a bmRequestType field for control requests.
These is a conventional function to build a bmRequestType
for a control request.
The direction parameter can be CTRL_OUT or CTRL_IN.
The type parameter can be CTRL_TYPE_STANDARD, CTRL_TYPE_CLASS,
CTRL_TYPE_VENDOR or CTRL_TYPE_RESERVED values.
The recipient can be CTRL_RECIPIENT_DEVICE, CTRL_RECIPIENT_INTERFACE,
CTRL_RECIPIENT_ENDPOINT or CTRL_RECIPIENT_OTHER.
Return the bmRequestType value.
"""
return recipient | type | direction
def create_buffer(length):
r"""Create a buffer to be passed to a read function.
A read function may receive an out buffer so the data
is read inplace and the object can be reused, avoiding
the overhead of creating a new object at each new read
call. This function creates a compatible sequence buffer
of the given length.
"""
return array.array('B', _dummy_s * length)
def find_descriptor(desc, find_all=False, custom_match=None, **args):
r"""Find an inner descriptor.
find_descriptor works in the same way as the core.find() function does,
but it acts on general descriptor objects. For example, suppose you
have a Device object called dev and want a Configuration of this
object with its bConfigurationValue equals to 1, the code would
be like so:
>>> cfg = util.find_descriptor(dev, bConfigurationValue=1)
You can use any field of the Descriptor as a match criteria, and you
can supply a customized match just like core.find() does. The
find_descriptor function also accepts the find_all parameter to get
an iterator instead of just one descriptor.
"""
def desc_iter(**kwargs):
for d in desc:
tests = (val == getattr(d, key) for key, val in kwargs.items())
if _interop._all(tests) and (custom_match is None or custom_match(d)):
yield d
if find_all:
return desc_iter(**args)
else:
try:
return _interop._next(desc_iter(**args))
except StopIteration:
return None
def claim_interface(device, interface):
r"""Explicitly claim an interface.
PyUSB users normally do not have to worry about interface claiming,
as the library takes care of it automatically. But there are situations
where you need deterministic interface claiming. For these uncommon
cases, you can use claim_interface.
If the interface is already claimed, either through a previously call
to claim_interface or internally by the device object, nothing happens.
"""
device._ctx.managed_claim_interface(device, interface)
def release_interface(device, interface):
r"""Explicitly release an interface.
This function is used to release an interface previously claimed,
either through a call to claim_interface or internally by the
device object.
Normally, you do not need to worry about claiming policies, as
the device object takes care of it automatically.
"""
device._ctx.managed_release_interface(device, interface)
def dispose_resources(device):
r"""Release internal resources allocated by the object.
Sometimes you need to provide deterministic resources
freeing, for example to allow another application to
talk to the device. As Python does not provide deterministic
destruction, this function releases all internal resources
allocated by the device, like device handle and interface
policy.
After calling this function, you can continue using the device
object normally. If the resources will be necessary again, it
will be allocated automatically.
"""
device._ctx.dispose(device)
def get_langids(dev):
r"""Retrieve the list of supported Language IDs from the device.
Most client code should not call this function directly, but instead use
the langids property on the Device object, which will call this function as
needed and cache the result.
USB LANGIDs are 16-bit integers familiar to Windows developers, where
for example instead of en-US you say 0x0409. See the file USB_LANGIDS.pdf
somewhere on the usb.org site for a list, which does not claim to be
complete. It requires "system software must allow the enumeration and
selection of LANGIDs that are not currently on this list." It also requires
"system software should never request a LANGID not defined in the LANGID
code array (string index = 0) presented by a device." Client code can
check this tuple before issuing string requests for a specific language ID.
dev is the Device object whose supported language IDs will be retrieved.
The return value is a tuple of integer LANGIDs, possibly empty if the
device does not support strings at all (which USB 3.1 r1.0 section
9.6.9 allows). In that case client code should not request strings at all.
A USBError may be raised from this function for some devices that have no
string support, instead of returning an empty tuple. The accessor for the
langids property on Device catches that case and supplies an empty tuple,
so client code can ignore this detail by using the langids property instead
of directly calling this function.
"""
from usb.control import get_descriptor
buf = get_descriptor(
dev,
254,
DESC_TYPE_STRING,
0
)
# The array is retrieved by asking for string descriptor zero, which is
# never the index of a real string. The returned descriptor has bLength
# and bDescriptorType bytes followed by pairs of bytes representing
# little-endian LANGIDs. That is, buf[0] contains the length of the
# returned array, buf[2] is the least-significant byte of the first LANGID
# (if any), buf[3] is the most-significant byte, and in general the LSBs of
# all the LANGIDs are given by buf[2:buf[0]:2] and MSBs by buf[3:buf[0]:2].
# If the length of buf came back odd, something is wrong.
if len(buf) < 4 or buf[0] < 4 or buf[0]&1 != 0:
return ()
return tuple(map(lambda x,y: x+(y<<8), buf[2:buf[0]:2], buf[3:buf[0]:2]))
def get_string(dev, index, langid = None):
r"""Retrieve a string descriptor from the device.
dev is the Device object which the string will be read from.
index is the string descriptor index and langid is the Language
ID of the descriptor. If langid is omitted, the string descriptor
of the first Language ID will be returned.
Zero is never the index of a real string. The USB spec allows a device to
use zero in a string index field to indicate that no string is provided.
So the caller does not have to treat that case specially, this function
returns None if passed an index of zero, and generates no traffic
to the device.
The return value is the unicode string present in the descriptor, or None
if the requested index was zero.
It is a ValueError to request a real string (index not zero), if: the
device's langid tuple is empty, or with an explicit langid the device does
not support.
"""
if 0 == index:
return None
from usb.control import get_descriptor
langids = dev.langids
if 0 == len(langids):
raise ValueError("The device has no langid")
if langid is None:
langid = langids[0]
elif langid not in langids:
raise ValueError("The device does not support the specified langid")
buf = get_descriptor(
dev,
255, # Maximum descriptor size
DESC_TYPE_STRING,
index,
langid
)
if hexversion >= 0x03020000:
return buf[2:buf[0]].tobytes().decode('utf-16-le')
else:
return buf[2:buf[0]].tostring().decode('utf-16-le')
pyusb-1.0.0/usb/libloader.py 0000664 0001750 0001750 00000015177 12661452153 016556 0 ustar wander wander 0000000 0000000 # -*- coding: utf-8 -*-
#
# Copyright (C) 2013-2014 André Erdmann
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
import ctypes
import ctypes.util
import logging
import sys
__all__ = [
'LibaryException',
'LibraryNotFoundException',
'NoLibraryCandidatesException',
'LibraryNotLoadedException',
'LibraryMissingSymbolsException',
'locate_library',
'load_library',
'load_locate_library'
]
_LOGGER = logging.getLogger('usb.libloader')
class LibaryException(OSError):
pass
class LibraryNotFoundException(LibaryException):
pass
class NoLibraryCandidatesException(LibraryNotFoundException):
pass
class LibraryNotLoadedException(LibaryException):
pass
class LibraryMissingSymbolsException(LibaryException):
pass
def locate_library (candidates, find_library=ctypes.util.find_library):
"""Tries to locate a library listed in candidates using the given
find_library() function (or ctypes.util.find_library).
Returns the first library found, which can be the library's name
or the path to the library file, depending on find_library().
Returns None if no library is found.
arguments:
* candidates -- iterable with library names
* find_library -- function that takes one positional arg (candidate)
and returns a non-empty str if a library has been found.
Any "false" value (None,False,empty str) is interpreted
as "library not found".
Defaults to ctypes.util.find_library if not given or
None.
"""
if find_library is None:
find_library = ctypes.util.find_library
use_dll_workaround = (
sys.platform == 'win32' and find_library is ctypes.util.find_library
)
for candidate in candidates:
# Workaround for CPython 3.3 issue#16283 / pyusb #14
if use_dll_workaround:
candidate += '.dll'
libname = find_library(candidate)
if libname:
return libname
# -- end for
return None
def load_library(lib, name=None, lib_cls=None):
"""Loads a library. Catches and logs exceptions.
Returns: the loaded library or None
arguments:
* lib -- path to/name of the library to be loaded
* name -- the library's identifier (for logging)
Defaults to None.
* lib_cls -- library class. Defaults to None (-> ctypes.CDLL).
"""
try:
if lib_cls:
return lib_cls(lib)
else:
return ctypes.CDLL(lib)
except Exception:
if name:
lib_msg = '%s (%s)' % (name, lib)
else:
lib_msg = lib
lib_msg += ' could not be loaded'
if sys.platform == 'cygwin':
lib_msg += ' in cygwin'
_LOGGER.error(lib_msg, exc_info=True)
return None
def load_locate_library(candidates, cygwin_lib, name,
win_cls=None, cygwin_cls=None, others_cls=None,
find_library=None, check_symbols=None):
"""Locates and loads a library.
Returns: the loaded library
arguments:
* candidates -- candidates list for locate_library()
* cygwin_lib -- name of the cygwin library
* name -- lib identifier (for logging). Defaults to None.
* win_cls -- class that is used to instantiate the library on
win32 platforms. Defaults to None (-> ctypes.CDLL).
* other_cls -- library class for cygwin platforms.
Defaults to None (-> ctypes.CDLL).
* cygwin_cls -- library class for all other platforms.
Defaults to None (-> ctypes.CDLL).
* find_library -- see locate_library(). Defaults to None.
* check_symbols -- either None or a list of symbols that the loaded lib
must provide (hasattr(<>)) in order to be considered
valid. LibraryMissingSymbolsException is raised if
any symbol is missing.
raises:
* NoLibraryCandidatesException
* LibraryNotFoundException
* LibraryNotLoadedException
* LibraryMissingSymbolsException
"""
if sys.platform == 'cygwin':
if cygwin_lib:
loaded_lib = load_library(cygwin_lib, name, cygwin_cls)
else:
raise NoLibraryCandidatesException(name)
elif candidates:
lib = locate_library(candidates, find_library)
if lib:
if sys.platform == 'win32':
loaded_lib = load_library(lib, name, win_cls)
else:
loaded_lib = load_library(lib, name, others_cls)
else:
_LOGGER.error('%r could not be found', (name or candidates))
raise LibraryNotFoundException(name)
else:
raise NoLibraryCandidatesException(name)
if loaded_lib is None:
raise LibraryNotLoadedException(name)
elif check_symbols:
symbols_missing = [
s for s in check_symbols if not hasattr(loaded_lib, s)
]
if symbols_missing:
msg = ('%r, missing symbols: %r', lib, symbols_missing )
_LOGGER.error(msg)
raise LibraryMissingSymbolsException(lib)
else:
return loaded_lib
else:
return loaded_lib
pyusb-1.0.0/usb/backend/ 0000775 0001750 0001750 00000000000 12711232524 015615 5 ustar wander wander 0000000 0000000 pyusb-1.0.0/usb/backend/__init__.py 0000664 0001750 0001750 00000037260 12711231457 017742 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
r"""usb.backend - Backend interface.
This module exports:
IBackend - backend interface.
Backends are Python objects which implement the IBackend interface.
The easiest way to do so is inherinting from IBackend.
PyUSB already provides backends for libusb versions 0.1 and 1.0,
and OpenUSB library. Backends modules included with PyUSB are required to
export the get_backend() function, which returns an instance of a backend
object. You can provide your own customized backend if you
want to. Below you find a skeleton of a backend implementation module:
import usb.backend
class MyBackend(usb.backend.IBackend):
pass
def get_backend():
return MyBackend()
You can use your customized backend by passing it as the backend parameter of the
usb.core.find() function. For example:
import custom_backend
import usb.core
myidVendor = 0xfffe
myidProduct = 0x0001
mybackend = custom_backend.get_backend()
dev = usb.core.find(backend = mybackend, idProduct=myidProduct,
idVendor=myidVendor)
For custom backends, you are not required to supply the get_backend() function,
since the application code will instantiate the backend.
If you do not provide a backend to the find() function, it will use one of the
defaults backend according to its internal rules. For details, consult the
find() function documentation.
"""
import usb._objfinalizer as _objfinalizer
__author__ = 'Wander Lairson Costa'
__all__ = ['IBackend', 'libusb01', 'libusb10', 'openusb']
def _not_implemented(func):
raise NotImplementedError(func.__name__)
class IBackend(_objfinalizer.AutoFinalizedObject):
r"""Backend interface.
IBackend is the basic interface for backend implementations. By default,
the methods of the interface raise a NotImplementedError exception. A
backend implementation should replace the methods to provide the funcionality
necessary.
As Python is a dynamic typed language, you are not obligated to inherit from
IBackend: everything that behaves like an IBackend is an IBackend. But you
are strongly recommended to do so, inheriting from IBackend provides consistent
default behavior.
"""
def enumerate_devices(self):
r"""This function is required to return an iterable object which
yields an implementation defined device identification for each
USB device found in the system.
The device identification object is used as argument to other methods
of the interface.
"""
_not_implemented(self.enumerate_devices)
def get_device_descriptor(self, dev):
r"""Return the device descriptor of the given device.
The object returned is required to have all the Device Descriptor
fields accessible as member variables. They must be convertible (but
not required to be equal) to the int type.
dev is an object yielded by the iterator returned by the enumerate_devices()
method.
"""
_not_implemented(self.get_device_descriptor)
def get_configuration_descriptor(self, dev, config):
r"""Return a configuration descriptor of the given device.
The object returned is required to have all the Configuration Descriptor
fields acessible as member variables. They must be convertible (but
not required to be equal) to the int type.
The dev parameter is the device identification object.
config is the logical index of the configuration (not the bConfigurationValue
field). By "logical index" we mean the relative order of the configurations
returned by the peripheral as a result of GET_DESCRIPTOR request.
"""
_not_implemented(self.get_configuration_descriptor)
def get_interface_descriptor(self, dev, intf, alt, config):
r"""Return an interface descriptor of the given device.
The object returned is required to have all the Interface Descriptor
fields accessible as member variables. They must be convertible (but
not required to be equal) to the int type.
The dev parameter is the device identification object.
The intf parameter is the interface logical index (not the bInterfaceNumber field)
and alt is the alternate setting logical index (not the bAlternateSetting value).
Not every interface has more than one alternate setting. In this case, the alt
parameter should be zero. config is the configuration logical index (not the
bConfigurationValue field).
"""
_not_implemented(self.get_interface_descriptor)
def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
r"""Return an endpoint descriptor of the given device.
The object returned is required to have all the Endpoint Descriptor
fields acessible as member variables. They must be convertible (but
not required to be equal) to the int type.
The ep parameter is the endpoint logical index (not the bEndpointAddress
field) of the endpoint descriptor desired. dev, intf, alt and config are the same
values already described in the get_interface_descriptor() method.
"""
_not_implemented(self.get_endpoint_descriptor)
def open_device(self, dev):
r"""Open the device for data exchange.
This method opens the device identified by the dev parameter for communication.
This method must be called before calling any communication related method, such
as transfer methods.
It returns a handle identifying the communication instance. This handle must be
passed to the communication methods.
"""
_not_implemented(self.open_device)
def close_device(self, dev_handle):
r"""Close the device handle.
This method closes the device communication channel and releases any
system resources related to it.
"""
_not_implemented(self.close_device)
def set_configuration(self, dev_handle, config_value):
r"""Set the active device configuration.
This method should be called to set the active configuration
of the device. The dev_handle parameter is the value returned
by the open_device() method and the config_value parameter is the
bConfigurationValue field of the related configuration descriptor.
"""
_not_implemented(self.set_configuration)
def get_configuration(self, dev_handle):
r"""Get the current active device configuration.
This method returns the bConfigurationValue of the currently
active configuration. Depending on the backend and the OS,
either a cached value may be returned or a control request may
be issued. The dev_handle parameter is the value returned by
the open_device method.
"""
_not_implemented(self.get_configuration)
def set_interface_altsetting(self, dev_handle, intf, altsetting):
r"""Set the interface alternate setting.
This method should only be called when the interface has more than
one alternate setting. The dev_handle is the value returned by the
open_device() method. intf and altsetting are respectivelly the
bInterfaceNumber and bAlternateSetting fields of the related interface.
"""
_not_implemented(self.set_interface_altsetting)
def claim_interface(self, dev_handle, intf):
r"""Claim the given interface.
Interface claiming is not related to USB spec itself, but it is
generally an necessary call of the USB libraries. It requests exclusive
access to the interface on the system. This method must be called
before using one of the transfer methods.
dev_handle is the value returned by the open_device() method and
intf is the bInterfaceNumber field of the desired interface.
"""
_not_implemented(self.claim_interface)
def release_interface(self, dev_handle, intf):
r"""Release the claimed interface.
dev_handle and intf are the same parameters of the claim_interface
method.
"""
_not_implemented(self.release_interface)
def bulk_write(self, dev_handle, ep, intf, data, timeout):
r"""Perform a bulk write.
dev_handle is the value returned by the open_device() method.
The ep parameter is the bEndpointAddress field whose endpoint
the data will be sent to. intf is the bInterfaceNumber field
of the interface containing the endpoint. The data parameter
is the data to be sent. It must be an instance of the array.array
class. The timeout parameter specifies a time limit to the operation
in miliseconds.
The method returns the number of bytes written.
"""
_not_implemented(self.bulk_write)
def bulk_read(self, dev_handle, ep, intf, buff, timeout):
r"""Perform a bulk read.
dev_handle is the value returned by the open_device() method.
The ep parameter is the bEndpointAddress field whose endpoint
the data will be received from. intf is the bInterfaceNumber field
of the interface containing the endpoint. The buff parameter
is the buffer to receive the data read, the length of the buffer
tells how many bytes should be read. The timeout parameter
specifies a time limit to the operation in miliseconds.
The method returns the number of bytes actually read.
"""
_not_implemented(self.bulk_read)
def intr_write(self, dev_handle, ep, intf, data, timeout):
r"""Perform an interrupt write.
dev_handle is the value returned by the open_device() method.
The ep parameter is the bEndpointAddress field whose endpoint
the data will be sent to. intf is the bInterfaceNumber field
of the interface containing the endpoint. The data parameter
is the data to be sent. It must be an instance of the array.array
class. The timeout parameter specifies a time limit to the operation
in miliseconds.
The method returns the number of bytes written.
"""
_not_implemented(self.intr_write)
def intr_read(self, dev_handle, ep, intf, size, timeout):
r"""Perform an interrut read.
dev_handle is the value returned by the open_device() method.
The ep parameter is the bEndpointAddress field whose endpoint
the data will be received from. intf is the bInterfaceNumber field
of the interface containing the endpoint. The buff parameter
is the buffer to receive the data read, the length of the buffer
tells how many bytes should be read. The timeout parameter
specifies a time limit to the operation in miliseconds.
The method returns the number of bytes actually read.
"""
_not_implemented(self.intr_read)
def iso_write(self, dev_handle, ep, intf, data, timeout):
r"""Perform an isochronous write.
dev_handle is the value returned by the open_device() method.
The ep parameter is the bEndpointAddress field whose endpoint
the data will be sent to. intf is the bInterfaceNumber field
of the interface containing the endpoint. The data parameter
is the data to be sent. It must be an instance of the array.array
class. The timeout parameter specifies a time limit to the operation
in miliseconds.
The method returns the number of bytes written.
"""
_not_implemented(self.iso_write)
def iso_read(self, dev_handle, ep, intf, size, timeout):
r"""Perform an isochronous read.
dev_handle is the value returned by the open_device() method.
The ep parameter is the bEndpointAddress field whose endpoint
the data will be received from. intf is the bInterfaceNumber field
of the interface containing the endpoint. The buff parameter
is buffer to receive the data read, the length of the buffer tells
how many bytes should be read. The timeout parameter specifies
a time limit to the operation in miliseconds.
The method returns the number of bytes actually read.
"""
_not_implemented(self.iso_read)
def ctrl_transfer(self,
dev_handle,
bmRequestType,
bRequest,
wValue,
wIndex,
data,
timeout):
r"""Perform a control transfer on the endpoint 0.
The direction of the transfer is inferred from the bmRequestType
field of the setup packet.
dev_handle is the value returned by the open_device() method.
bmRequestType, bRequest, wValue and wIndex are the same fields
of the setup packet. data is an array object, for OUT requests
it contains the bytes to transmit in the data stage and for
IN requests it is the buffer to hold the data read. The number
of bytes requested to transmit or receive is equal to the length
of the array times the data.itemsize field. The timeout parameter
specifies a time limit to the operation in miliseconds.
Return the number of bytes written (for OUT transfers) or the data
read (for IN transfers), as an array.array object.
"""
_not_implemented(self.ctrl_transfer)
def clear_halt(self, dev_handle, ep):
r"""Clear the halt/stall condition for the endpoint."""
_not_implemented(self.clear_halt)
def reset_device(self, dev_handle):
r"""Reset the device."""
_not_implemented(self.reset_device)
def is_kernel_driver_active(self, dev_handle, intf):
r"""Determine if a kernel driver is active on an interface.
If a kernel driver is active, you cannot claim the interface,
and the backend will be unable to perform I/O.
"""
_not_implemented(self.is_kernel_driver_active)
def detach_kernel_driver(self, dev_handle, intf):
r"""Detach a kernel driver from an interface.
If successful, you will then be able to claim the interface
and perform I/O.
"""
_not_implemented(self.detach_kernel_driver)
def attach_kernel_driver(self, dev_handle, intf):
r"""Re-attach an interface's kernel driver, which was previously
detached using detach_kernel_driver()."""
_not_implemented(self.attach_kernel_driver)
pyusb-1.0.0/usb/backend/openusb.py 0000664 0001750 0001750 00000066562 12661452153 017667 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
from ctypes import *
import ctypes.util
import usb.util
from usb._debug import methodtrace
import logging
import errno
import sys
import usb._interop as _interop
import usb._objfinalizer as _objfinalizer
import usb.util as util
import usb.libloader
from usb.core import USBError
__author__ = 'Wander Lairson Costa'
__all__ = [
'get_backend'
'OPENUSB_SUCCESS'
'OPENUSB_PLATFORM_FAILURE'
'OPENUSB_NO_RESOURCES'
'OPENUSB_NO_BANDWIDTH'
'OPENUSB_NOT_SUPPORTED'
'OPENUSB_HC_HARDWARE_ERROR'
'OPENUSB_INVALID_PERM'
'OPENUSB_BUSY'
'OPENUSB_BADARG'
'OPENUSB_NOACCESS'
'OPENUSB_PARSE_ERROR'
'OPENUSB_UNKNOWN_DEVICE'
'OPENUSB_INVALID_HANDLE'
'OPENUSB_SYS_FUNC_FAILURE'
'OPENUSB_NULL_LIST'
'OPENUSB_CB_CONTINUE'
'OPENUSB_CB_TERMINATE'
'OPENUSB_IO_STALL'
'OPENUSB_IO_CRC_ERROR'
'OPENUSB_IO_DEVICE_HUNG'
'OPENUSB_IO_REQ_TOO_BIG'
'OPENUSB_IO_BIT_STUFFING'
'OPENUSB_IO_UNEXPECTED_PID'
'OPENUSB_IO_DATA_OVERRUN'
'OPENUSB_IO_DATA_UNDERRUN'
'OPENUSB_IO_BUFFER_OVERRUN'
'OPENUSB_IO_BUFFER_UNDERRUN'
'OPENUSB_IO_PID_CHECK_FAILURE'
'OPENUSB_IO_DATA_TOGGLE_MISMATCH'
'OPENUSB_IO_TIMEOUT'
'OPENUSB_IO_CANCELED'
]
_logger = logging.getLogger('usb.backend.openusb')
OPENUSB_SUCCESS = 0
OPENUSB_PLATFORM_FAILURE = -1
OPENUSB_NO_RESOURCES = -2
OPENUSB_NO_BANDWIDTH = -3
OPENUSB_NOT_SUPPORTED = -4
OPENUSB_HC_HARDWARE_ERROR = -5
OPENUSB_INVALID_PERM = -6
OPENUSB_BUSY = -7
OPENUSB_BADARG = -8
OPENUSB_NOACCESS = -9
OPENUSB_PARSE_ERROR = -10
OPENUSB_UNKNOWN_DEVICE = -11
OPENUSB_INVALID_HANDLE = -12
OPENUSB_SYS_FUNC_FAILURE = -13
OPENUSB_NULL_LIST = -14
OPENUSB_CB_CONTINUE = -20
OPENUSB_CB_TERMINATE = -21
OPENUSB_IO_STALL = -50
OPENUSB_IO_CRC_ERROR = -51
OPENUSB_IO_DEVICE_HUNG = -52
OPENUSB_IO_REQ_TOO_BIG = -53
OPENUSB_IO_BIT_STUFFING = -54
OPENUSB_IO_UNEXPECTED_PID = -55
OPENUSB_IO_DATA_OVERRUN = -56
OPENUSB_IO_DATA_UNDERRUN = -57
OPENUSB_IO_BUFFER_OVERRUN = -58
OPENUSB_IO_BUFFER_UNDERRUN = -59
OPENUSB_IO_PID_CHECK_FAILURE = -60
OPENUSB_IO_DATA_TOGGLE_MISMATCH = -61
OPENUSB_IO_TIMEOUT = -62
OPENUSB_IO_CANCELED = -63
_openusb_errno = {
OPENUSB_SUCCESS:None,
OPENUSB_PLATFORM_FAILURE:None,
OPENUSB_NO_RESOURCES:errno.__dict__.get('ENOMEM', None),
OPENUSB_NO_BANDWIDTH:None,
OPENUSB_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),
OPENUSB_HC_HARDWARE_ERROR:errno.__dict__.get('EIO', None),
OPENUSB_INVALID_PERM:errno.__dict__.get('EBADF', None),
OPENUSB_BUSY:errno.__dict__.get('EBUSY', None),
OPENUSB_BADARG:errno.__dict__.get('EINVAL', None),
OPENUSB_NOACCESS:errno.__dict__.get('EACCES', None),
OPENUSB_PARSE_ERROR:None,
OPENUSB_UNKNOWN_DEVICE:errno.__dict__.get('ENODEV', None),
OPENUSB_INVALID_HANDLE:errno.__dict__.get('EINVAL', None),
OPENUSB_SYS_FUNC_FAILURE:None,
OPENUSB_NULL_LIST:None,
OPENUSB_CB_CONTINUE:None,
OPENUSB_CB_TERMINATE:None,
OPENUSB_IO_STALL:errno.__dict__.get('EIO', None),
OPENUSB_IO_CRC_ERROR:errno.__dict__.get('EIO', None),
OPENUSB_IO_DEVICE_HUNG:errno.__dict__.get('EIO', None),
OPENUSB_IO_REQ_TOO_BIG:errno.__dict__.get('E2BIG', None),
OPENUSB_IO_BIT_STUFFING:None,
OPENUSB_IO_UNEXPECTED_PID:errno.__dict__.get('ESRCH', None),
OPENUSB_IO_DATA_OVERRUN:errno.__dict__.get('EOVERFLOW', None),
OPENUSB_IO_DATA_UNDERRUN:None,
OPENUSB_IO_BUFFER_OVERRUN:errno.__dict__.get('EOVERFLOW', None),
OPENUSB_IO_BUFFER_UNDERRUN:None,
OPENUSB_IO_PID_CHECK_FAILURE:None,
OPENUSB_IO_DATA_TOGGLE_MISMATCH:None,
OPENUSB_IO_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),
OPENUSB_IO_CANCELED:errno.__dict__.get('EINTR', None)
}
class _usb_endpoint_desc(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bEndpointAddress', c_uint8),
('bmAttributes', c_uint8),
('wMaxPacketSize', c_uint16),
('bInterval', c_uint8),
('bRefresh', c_uint8),
('bSynchAddress', c_uint8)]
class _usb_interface_desc(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bInterfaceNumber', c_uint8),
('bAlternateSetting', c_uint8),
('bNumEndpoints', c_uint8),
('bInterfaceClass', c_uint8),
('bInterfaceSubClass', c_uint8),
('bInterfaceProtocol', c_uint8),
('iInterface', c_uint8)]
class _usb_config_desc(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('wTotalLength', c_uint16),
('bNumInterfaces', c_uint8),
('bConfigurationValue', c_uint8),
('iConfiguration', c_uint8),
('bmAttributes', c_uint8),
('bMaxPower', c_uint8)]
class _usb_device_desc(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bcdUSB', c_uint16),
('bDeviceClass', c_uint8),
('bDeviceSubClass', c_uint8),
('bDeviceProtocol', c_uint8),
('bMaxPacketSize0', c_uint8),
('idVendor', c_uint16),
('idProduct', c_uint16),
('bcdDevice', c_uint16),
('iManufacturer', c_uint8),
('iProduct', c_uint8),
('iSerialNumber', c_uint8),
('bNumConfigurations', c_uint8)]
class _openusb_request_result(Structure):
_fields_ = [('status', c_int32),
('transferred_bytes', c_uint32)]
class _openusb_ctrl_request(Structure):
def __init__(self):
super(_openusb_ctrl_request, self).__init__()
self.setup.bmRequestType = 0
self.setup.bRequest = 0
self.setup.wValue = 0
self.setup.wIndex = 0
self.payload = None
self.length = 0
self.timeout = 0
self.flags = 0
self.result.status = 0
self.result.transferred_bytes = 0
self.next = None
class _openusb_ctrl_setup(Structure):
_fields_ = [('bmRequestType', c_uint8),
('bRequest', c_uint8),
('wValue', c_uint16),
('wIndex', c_uint16)]
_fields_ = [('setup', _openusb_ctrl_setup),
('payload', POINTER(c_uint8)),
('length', c_uint32),
('timeout', c_uint32),
('flags', c_uint32),
('result', _openusb_request_result),
('next', c_void_p)]
class _openusb_intr_request(Structure):
_fields_ = [('interval', c_uint16),
('payload', POINTER(c_uint8)),
('length', c_uint32),
('timeout', c_uint32),
('flags', c_uint32),
('result', _openusb_request_result),
('next', c_void_p)]
class _openusb_bulk_request(Structure):
_fields_ = [('payload', POINTER(c_uint8)),
('length', c_uint32),
('timeout', c_uint32),
('flags', c_uint32),
('result', _openusb_request_result),
('next', c_void_p)]
class _openusb_isoc_pkts(Structure):
class _openusb_isoc_packet(Structure):
_fields_ = [('payload', POINTER(c_uint8)),
('length', c_uint32)]
_fields_ = [('num_packets', c_uint32),
('packets', POINTER(_openusb_isoc_packet))]
class _openusb_isoc_request(Structure):
_fields_ = [('start_frame', c_uint32),
('flags', c_uint32),
('pkts', _openusb_isoc_pkts),
('isoc_results', POINTER(_openusb_request_result)),
('isoc_status', c_int32),
('next', c_void_p)]
_openusb_devid = c_uint64
_openusb_busid = c_uint64
_openusb_handle = c_uint64
_openusb_dev_handle = c_uint64
_lib = None
_ctx = None
def _load_library(find_library=None):
# FIXME: cygwin name is "openusb"?
# (that's what the original _load_library() function
# would have searched for)
return usb.libloader.load_locate_library(
('openusb',), 'openusb', "OpenUSB library", find_library=find_library
)
def _setup_prototypes(lib):
# int32_t openusb_init(uint32_t flags , openusb_handle_t *handle);
lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)]
lib.openusb_init.restype = c_int32
# void openusb_fini(openusb_handle_t handle );
lib.openusb_fini.argtypes = [_openusb_handle]
# uint32_t openusb_get_busid_list(openusb_handle_t handle,
# openusb_busid_t **busids,
# uint32_t *num_busids);
lib.openusb_get_busid_list.argtypes = [
_openusb_handle,
POINTER(POINTER(_openusb_busid)),
POINTER(c_uint32)
]
# void openusb_free_busid_list(openusb_busid_t * busids);
lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)]
# uint32_t openusb_get_devids_by_bus(openusb_handle_t handle,
# openusb_busid_t busid,
# openusb_devid_t **devids,
# uint32_t *num_devids);
lib.openusb_get_devids_by_bus.argtypes = [
_openusb_handle,
_openusb_busid,
POINTER(POINTER(_openusb_devid)),
POINTER(c_uint32)
]
lib.openusb_get_devids_by_bus.restype = c_int32
# void openusb_free_devid_list(openusb_devid_t * devids);
lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)]
# int32_t openusb_open_device(openusb_handle_t handle,
# openusb_devid_t devid ,
# uint32_t flags,
# openusb_dev_handle_t *dev);
lib.openusb_open_device.argtypes = [
_openusb_handle,
_openusb_devid,
c_uint32,
POINTER(_openusb_dev_handle)
]
lib.openusb_open_device.restype = c_int32
# int32_t openusb_close_device(openusb_dev_handle_t dev);
lib.openusb_close_device.argtypes = [_openusb_dev_handle]
lib.openusb_close_device.restype = c_int32
# int32_t openusb_set_configuration(openusb_dev_handle_t dev,
# uint8_t cfg);
lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8]
lib.openusb_set_configuration.restype = c_int32
# int32_t openusb_get_configuration(openusb_dev_handle_t dev,
# uint8_t *cfg);
lib.openusb_get_configuration.argtypes = [_openusb_dev_handle, POINTER(c_uint8)]
lib.openusb_get_configuration.restype = c_int32
# int32_t openusb_claim_interface(openusb_dev_handle_t dev,
# uint8_t ifc,
# openusb_init_flag_t flags);
lib.openusb_claim_interface.argtypes = [
_openusb_dev_handle,
c_uint8,
c_int
]
lib.openusb_claim_interface.restype = c_int32
# int32_t openusb_release_interface(openusb_dev_handle_t dev,
# uint8_t ifc);
lib.openusb_release_interface.argtypes = [
_openusb_dev_handle,
c_uint8
]
lib.openusb_release_interface.restype = c_int32
# int32_topenusb_set_altsetting(openusb_dev_handle_t dev,
# uint8_t ifc,
# uint8_t alt);
lib.openusb_set_altsetting.argtypes = [
_openusb_dev_handle,
c_uint8,
c_uint8
]
lib.openusb_set_altsetting.restype = c_int32
# int32_t openusb_reset(openusb_dev_handle_t dev);
lib.openusb_reset.argtypes = [_openusb_dev_handle]
lib.openusb_reset.restype = c_int32
# int32_t openusb_parse_device_desc(openusb_handle_t handle,
# openusb_devid_t devid,
# uint8_t *buffer,
# uint16_t buflen,
# usb_device_desc_t *devdesc);
lib.openusb_parse_device_desc.argtypes = [
_openusb_handle,
_openusb_devid,
POINTER(c_uint8),
c_uint16,
POINTER(_usb_device_desc)
]
lib.openusb_parse_device_desc.restype = c_int32
# int32_t openusb_parse_config_desc(openusb_handle_t handle,
# openusb_devid_t devid,
# uint8_t *buffer,
# uint16_t buflen,
# uint8_t cfgidx,
# usb_config_desc_t *cfgdesc);
lib.openusb_parse_config_desc.argtypes = [
_openusb_handle,
_openusb_devid,
POINTER(c_uint8),
c_uint16,
c_uint8,
POINTER(_usb_config_desc)
]
lib.openusb_parse_config_desc.restype = c_int32
# int32_t openusb_parse_interface_desc(openusb_handle_t handle,
# openusb_devid_t devid,
# uint8_t *buffer,
# uint16_t buflen,
# uint8_t cfgidx,
# uint8_t ifcidx,
# uint8_t alt,
# usb_interface_desc_t *ifcdesc);
lib.openusb_parse_interface_desc.argtypes = [
_openusb_handle,
_openusb_devid,
POINTER(c_uint8),
c_uint16,
c_uint8,
c_uint8,
c_uint8,
POINTER(_usb_interface_desc)
]
lib.openusb_parse_interface_desc.restype = c_int32
# int32_t openusb_parse_endpoint_desc(openusb_handle_t handle,
# openusb_devid_t devid,
# uint8_t *buffer,
# uint16_t buflen,
# uint8_t cfgidx,
# uint8_t ifcidx,
# uint8_t alt,
# uint8_t eptidx,
# usb_endpoint_desc_t *eptdesc);
lib.openusb_parse_endpoint_desc.argtypes = [
_openusb_handle,
_openusb_devid,
POINTER(c_uint8),
c_uint16,
c_uint8,
c_uint8,
c_uint8,
c_uint8,
POINTER(_usb_endpoint_desc)
]
lib.openusb_parse_interface_desc.restype = c_int32
# const char *openusb_strerror(int32_t error );
lib.openusb_strerror.argtypes = [c_int32]
lib.openusb_strerror.restype = c_char_p
# int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev,
# uint8_t ifc,
# uint8_t ept,
# openusb_ctrl_request_t *ctrl);
lib.openusb_ctrl_xfer.argtypes = [
_openusb_dev_handle,
c_uint8,
c_uint8,
POINTER(_openusb_ctrl_request)
]
lib.openusb_ctrl_xfer.restype = c_int32
# int32_t openusb_intr_xfer(openusb_dev_handle_t dev,
# uint8_t ifc,
# uint8_t ept,
# openusb_intr_request_t *intr);
lib.openusb_intr_xfer.argtypes = [
_openusb_dev_handle,
c_uint8,
c_uint8,
POINTER(_openusb_intr_request)
]
lib.openusb_bulk_xfer.restype = c_int32
# int32_t openusb_bulk_xfer(openusb_dev_handle_t dev,
# uint8_t ifc,
# uint8_t ept,
# openusb_bulk_request_t *bulk);
lib.openusb_bulk_xfer.argtypes = [
_openusb_dev_handle,
c_uint8,
c_uint8,
POINTER(_openusb_bulk_request)
]
lib.openusb_bulk_xfer.restype = c_int32
# int32_t openusb_isoc_xfer(openusb_dev_handle_t dev,
# uint8_t ifc,
# uint8_t ept,
# openusb_isoc_request_t *isoc);
lib.openusb_isoc_xfer.argtypes = [
_openusb_dev_handle,
c_uint8,
c_uint8,
POINTER(_openusb_isoc_request)
]
lib.openusb_isoc_xfer.restype = c_int32
def _check(ret):
if hasattr(ret, 'value'):
ret = ret.value
if ret != 0:
raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret])
return ret
class _Context(_objfinalizer.AutoFinalizedObject):
def __init__(self):
self.handle = _openusb_handle()
_check(_lib.openusb_init(0, byref(self.handle)))
def _finalize_object(self):
_lib.openusb_fini(self.handle)
class _BusIterator(_objfinalizer.AutoFinalizedObject):
def __init__(self):
self.buslist = POINTER(_openusb_busid)()
num_busids = c_uint32()
_check(_lib.openusb_get_busid_list(_ctx.handle,
byref(self.buslist),
byref(num_busids)))
self.num_busids = num_busids.value
def __iter__(self):
for i in range(self.num_busids):
yield self.buslist[i]
def _finalize_object(self):
_lib.openusb_free_busid_list(self.buslist)
class _DevIterator(_objfinalizer.AutoFinalizedObject):
def __init__(self, busid):
self.devlist = POINTER(_openusb_devid)()
num_devids = c_uint32()
_check(_lib.openusb_get_devids_by_bus(_ctx.handle,
busid,
byref(self.devlist),
byref(num_devids)))
self.num_devids = num_devids.value
def __iter__(self):
for i in range(self.num_devids):
yield self.devlist[i]
def _finalize_object(self):
_lib.openusb_free_devid_list(self.devlist)
class _OpenUSB(usb.backend.IBackend):
@methodtrace(_logger)
def enumerate_devices(self):
for bus in _BusIterator():
for devid in _DevIterator(bus):
yield devid
@methodtrace(_logger)
def get_device_descriptor(self, dev):
desc = _usb_device_desc()
_check(_lib.openusb_parse_device_desc(_ctx.handle,
dev,
None,
0,
byref(desc)))
desc.bus = None
desc.address = None
desc.port_number = None
desc.port_numbers = None
desc.speed = None
return desc
@methodtrace(_logger)
def get_configuration_descriptor(self, dev, config):
desc = _usb_config_desc()
_check(_lib.openusb_parse_config_desc(_ctx.handle,
dev,
None,
0,
config,
byref(desc)))
desc.extra_descriptors = None
return desc
@methodtrace(_logger)
def get_interface_descriptor(self, dev, intf, alt, config):
desc = _usb_interface_desc()
_check(_lib.openusb_parse_interface_desc(_ctx.handle,
dev,
None,
0,
config,
intf,
alt,
byref(desc)))
desc.extra_descriptors = None
return desc
@methodtrace(_logger)
def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
desc = _usb_endpoint_desc()
_check(_lib.openusb_parse_endpoint_desc(_ctx.handle,
dev,
None,
0,
config,
intf,
alt,
ep,
byref(desc)))
desc.extra_descriptors = None
return desc
@methodtrace(_logger)
def open_device(self, dev):
handle = _openusb_dev_handle()
_check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle)))
return handle
@methodtrace(_logger)
def close_device(self, dev_handle):
_lib.openusb_close_device(dev_handle)
@methodtrace(_logger)
def set_configuration(self, dev_handle, config_value):
_check(_lib.openusb_set_configuration(dev_handle, config_value))
@methodtrace(_logger)
def get_configuration(self, dev_handle):
config = c_uint8()
_check(_lib.openusb_get_configuration(dev_handle, byref(config)))
return config.value
@methodtrace(_logger)
def set_interface_altsetting(self, dev_handle, intf, altsetting):
_check(_lib.openusb_set_altsetting(dev_handle, intf, altsetting))
@methodtrace(_logger)
def claim_interface(self, dev_handle, intf):
_check(_lib.openusb_claim_interface(dev_handle, intf, 0))
@methodtrace(_logger)
def release_interface(self, dev_handle, intf):
_lib.openusb_release_interface(dev_handle, intf)
@methodtrace(_logger)
def bulk_write(self, dev_handle, ep, intf, data, timeout):
request = _openusb_bulk_request()
memset(byref(request), 0, sizeof(request))
payload, request.length = data.buffer_info()
request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
return request.result.transferred_bytes
@methodtrace(_logger)
def bulk_read(self, dev_handle, ep, intf, buff, timeout):
request = _openusb_bulk_request()
memset(byref(request), 0, sizeof(request))
payload, request.length = buff.buffer_info()
request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
return request.result.transferred_bytes
@methodtrace(_logger)
def intr_write(self, dev_handle, ep, intf, data, timeout):
request = _openusb_intr_request()
memset(byref(request), 0, sizeof(request))
payload, request.length = data.buffer_info()
request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
return request.result.transferred_bytes
@methodtrace(_logger)
def intr_read(self, dev_handle, ep, intf, buff, timeout):
request = _openusb_intr_request()
memset(byref(request), 0, sizeof(request))
payload, request.length = buff.buffer_info()
request.payload = cast(payload, POINTER(c_uint8))
request.timeout = timeout
_check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
return request.result.transferred_bytes
# TODO: implement isochronous
# @methodtrace(_logger)
# def iso_write(self, dev_handle, ep, intf, data, timeout):
# pass
# @methodtrace(_logger)
# def iso_read(self, dev_handle, ep, intf, size, timeout):
# pass
@methodtrace(_logger)
def ctrl_transfer(self,
dev_handle,
bmRequestType,
bRequest,
wValue,
wIndex,
data,
timeout):
request = _openusb_ctrl_request()
request.setup.bmRequestType = bmRequestType
request.setup.bRequest = bRequest
request.setup.wValue
request.setup.wIndex
request.timeout = timeout
direction = usb.util.ctrl_direction(bmRequestType)
payload, request.length = data.buffer_info()
request.length *= data.itemsize
request.payload = cast(payload, POINTER(c_uint8))
_check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request)))
return request.result.transferred_bytes
@methodtrace(_logger)
def reset_device(self, dev_handle):
_check(_lib.openusb_reset(dev_handle))
@methodtrace(_logger)
def clear_halt(self, dev_handle, ep):
bmRequestType = util.build_request_type(
util.CTRL_OUT,
util.CTRL_TYPE_STANDARD,
util.CTRL_RECIPIENT_ENDPOINT)
self.ctrl_transfer(
dev_handle,
bmRequestType,
0x03,
0,
ep,
_interop.as_array(),
1000)
def get_backend(find_library=None):
try:
global _lib, _ctx
if _lib is None:
_lib = _load_library(find_library)
_setup_prototypes(_lib)
_ctx = _Context()
return _OpenUSB()
except usb.libloader.LibaryException:
# exception already logged (if any)
_logger.error('Error loading OpenUSB backend', exc_info=False)
return None
except Exception:
_logger.error('Error loading OpenUSB backend', exc_info=True)
return None
pyusb-1.0.0/usb/backend/libusb1.py 0000664 0001750 0001750 00000104742 12661452153 017546 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
from ctypes import *
import usb.util
import sys
import logging
from usb._debug import methodtrace
import usb._interop as _interop
import usb._objfinalizer as _objfinalizer
import errno
import math
from usb.core import USBError
import usb.libloader
__author__ = 'Wander Lairson Costa'
__all__ = [
'get_backend',
'LIBUSB_SUCESS',
'LIBUSB_ERROR_IO',
'LIBUSB_ERROR_INVALID_PARAM',
'LIBUSB_ERROR_ACCESS',
'LIBUSB_ERROR_NO_DEVICE',
'LIBUSB_ERROR_NOT_FOUND',
'LIBUSB_ERROR_BUSY',
'LIBUSB_ERROR_TIMEOUT',
'LIBUSB_ERROR_OVERFLOW',
'LIBUSB_ERROR_PIPE',
'LIBUSB_ERROR_INTERRUPTED',
'LIBUSB_ERROR_NO_MEM',
'LIBUSB_ERROR_NOT_SUPPORTED',
'LIBUSB_ERROR_OTHER'
'LIBUSB_TRANSFER_COMPLETED',
'LIBUSB_TRANSFER_ERROR',
'LIBUSB_TRANSFER_TIMED_OUT',
'LIBUSB_TRANSFER_CANCELLED',
'LIBUSB_TRANSFER_STALL',
'LIBUSB_TRANSFER_NO_DEVICE',
'LIBUSB_TRANSFER_OVERFLOW'
]
_logger = logging.getLogger('usb.backend.libusb1')
# libusb.h
# transfer_type codes
# Control endpoint
_LIBUSB_TRANSFER_TYPE_CONTROL = 0,
# Isochronous endpoint
_LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1
# Bulk endpoint
_LIBUSB_TRANSFER_TYPE_BULK = 2
# Interrupt endpoint
_LIBUSB_TRANSFER_TYPE_INTERRUPT = 3
# return codes
LIBUSB_SUCCESS = 0
LIBUSB_ERROR_IO = -1
LIBUSB_ERROR_INVALID_PARAM = -2
LIBUSB_ERROR_ACCESS = -3
LIBUSB_ERROR_NO_DEVICE = -4
LIBUSB_ERROR_NOT_FOUND = -5
LIBUSB_ERROR_BUSY = -6
LIBUSB_ERROR_TIMEOUT = -7
LIBUSB_ERROR_OVERFLOW = -8
LIBUSB_ERROR_PIPE = -9
LIBUSB_ERROR_INTERRUPTED = -10
LIBUSB_ERROR_NO_MEM = -11
LIBUSB_ERROR_NOT_SUPPORTED = -12
LIBUSB_ERROR_OTHER = -99
# map return codes to strings
_str_error_map = {
LIBUSB_SUCCESS:'Success (no error)',
LIBUSB_ERROR_IO:'Input/output error',
LIBUSB_ERROR_INVALID_PARAM:'Invalid parameter',
LIBUSB_ERROR_ACCESS:'Access denied (insufficient permissions)',
LIBUSB_ERROR_NO_DEVICE:'No such device (it may have been disconnected)',
LIBUSB_ERROR_NOT_FOUND:'Entity not found',
LIBUSB_ERROR_BUSY:'Resource busy',
LIBUSB_ERROR_TIMEOUT:'Operation timed out',
LIBUSB_ERROR_OVERFLOW:'Overflow',
LIBUSB_ERROR_PIPE:'Pipe error',
LIBUSB_ERROR_INTERRUPTED:'System call interrupted (perhaps due to signal)',
LIBUSB_ERROR_NO_MEM:'Insufficient memory',
LIBUSB_ERROR_NOT_SUPPORTED:'Operation not supported or unimplemented on this platform',
LIBUSB_ERROR_OTHER:'Unknown error'
}
# map return code to errno values
_libusb_errno = {
0:None,
LIBUSB_ERROR_IO:errno.__dict__.get('EIO', None),
LIBUSB_ERROR_INVALID_PARAM:errno.__dict__.get('EINVAL', None),
LIBUSB_ERROR_ACCESS:errno.__dict__.get('EACCES', None),
LIBUSB_ERROR_NO_DEVICE:errno.__dict__.get('ENODEV', None),
LIBUSB_ERROR_NOT_FOUND:errno.__dict__.get('ENOENT', None),
LIBUSB_ERROR_BUSY:errno.__dict__.get('EBUSY', None),
LIBUSB_ERROR_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),
LIBUSB_ERROR_OVERFLOW:errno.__dict__.get('EOVERFLOW', None),
LIBUSB_ERROR_PIPE:errno.__dict__.get('EPIPE', None),
LIBUSB_ERROR_INTERRUPTED:errno.__dict__.get('EINTR', None),
LIBUSB_ERROR_NO_MEM:errno.__dict__.get('ENOMEM', None),
LIBUSB_ERROR_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),
LIBUSB_ERROR_OTHER:None
}
# Transfer status codes:
# Note that this does not indicate
# that the entire amount of requested data was transferred.
LIBUSB_TRANSFER_COMPLETED = 0
LIBUSB_TRANSFER_ERROR = 1
LIBUSB_TRANSFER_TIMED_OUT = 2
LIBUSB_TRANSFER_CANCELLED = 3
LIBUSB_TRANSFER_STALL = 4
LIBUSB_TRANSFER_NO_DEVICE = 5
LIBUSB_TRANSFER_OVERFLOW = 6
# map return codes to strings
_str_transfer_error = {
LIBUSB_TRANSFER_COMPLETED:'Success (no error)',
LIBUSB_TRANSFER_ERROR:'Transfer failed',
LIBUSB_TRANSFER_TIMED_OUT:'Transfer timed out',
LIBUSB_TRANSFER_CANCELLED:'Transfer was cancelled',
LIBUSB_TRANSFER_STALL:'For bulk/interrupt endpoints: halt condition '\
'detected (endpoint stalled). For control '\
'endpoints: control request not supported.',
LIBUSB_TRANSFER_NO_DEVICE:'Device was disconnected',
LIBUSB_TRANSFER_OVERFLOW:'Device sent more data than requested'
}
# map transfer codes to errno codes
_transfer_errno = {
LIBUSB_TRANSFER_COMPLETED:0,
LIBUSB_TRANSFER_ERROR:errno.__dict__.get('EIO', None),
LIBUSB_TRANSFER_TIMED_OUT:errno.__dict__.get('ETIMEDOUT', None),
LIBUSB_TRANSFER_CANCELLED:errno.__dict__.get('EAGAIN', None),
LIBUSB_TRANSFER_STALL:errno.__dict__.get('EIO', None),
LIBUSB_TRANSFER_NO_DEVICE:errno.__dict__.get('ENODEV', None),
LIBUSB_TRANSFER_OVERFLOW:errno.__dict__.get('EOVERFLOW', None)
}
def _strerror(errcode):
try:
return _lib.libusb_strerror(errcode).decode('utf8')
except AttributeError:
return _str_error_map[errcode]
# Data structures
class _libusb_endpoint_descriptor(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bEndpointAddress', c_uint8),
('bmAttributes', c_uint8),
('wMaxPacketSize', c_uint16),
('bInterval', c_uint8),
('bRefresh', c_uint8),
('bSynchAddress', c_uint8),
('extra', POINTER(c_ubyte)),
('extra_length', c_int)]
class _libusb_interface_descriptor(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bInterfaceNumber', c_uint8),
('bAlternateSetting', c_uint8),
('bNumEndpoints', c_uint8),
('bInterfaceClass', c_uint8),
('bInterfaceSubClass', c_uint8),
('bInterfaceProtocol', c_uint8),
('iInterface', c_uint8),
('endpoint', POINTER(_libusb_endpoint_descriptor)),
('extra', POINTER(c_ubyte)),
('extra_length', c_int)]
class _libusb_interface(Structure):
_fields_ = [('altsetting', POINTER(_libusb_interface_descriptor)),
('num_altsetting', c_int)]
class _libusb_config_descriptor(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('wTotalLength', c_uint16),
('bNumInterfaces', c_uint8),
('bConfigurationValue', c_uint8),
('iConfiguration', c_uint8),
('bmAttributes', c_uint8),
('bMaxPower', c_uint8),
('interface', POINTER(_libusb_interface)),
('extra', POINTER(c_ubyte)),
('extra_length', c_int)]
class _libusb_device_descriptor(Structure):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bcdUSB', c_uint16),
('bDeviceClass', c_uint8),
('bDeviceSubClass', c_uint8),
('bDeviceProtocol', c_uint8),
('bMaxPacketSize0', c_uint8),
('idVendor', c_uint16),
('idProduct', c_uint16),
('bcdDevice', c_uint16),
('iManufacturer', c_uint8),
('iProduct', c_uint8),
('iSerialNumber', c_uint8),
('bNumConfigurations', c_uint8)]
# Isochronous packet descriptor.
class _libusb_iso_packet_descriptor(Structure):
_fields_ = [('length', c_uint),
('actual_length', c_uint),
('status', c_int)] # enum libusb_transfer_status
_libusb_device_handle = c_void_p
class _libusb_transfer(Structure):
pass
_libusb_transfer_p = POINTER(_libusb_transfer)
_libusb_transfer_cb_fn_p = CFUNCTYPE(None, _libusb_transfer_p)
_libusb_transfer._fields_ = [('dev_handle', _libusb_device_handle),
('flags', c_uint8),
('endpoint', c_uint8),
('type', c_uint8),
('timeout', c_uint),
('status', c_int), # enum libusb_transfer_status
('length', c_int),
('actual_length', c_int),
('callback', _libusb_transfer_cb_fn_p),
('user_data', py_object),
('buffer', c_void_p),
('num_iso_packets', c_int),
('iso_packet_desc', _libusb_iso_packet_descriptor)
]
def _get_iso_packet_list(transfer):
list_type = _libusb_iso_packet_descriptor * transfer.num_iso_packets
return list_type.from_address(addressof(transfer.iso_packet_desc))
_lib = None
def _load_library(find_library=None):
# Windows backend uses stdcall calling convention
#
# On FreeBSD 8/9, libusb 1.0 and libusb 0.1 are in the same shared
# object libusb.so, so if we found libusb library name, we must assure
# it is 1.0 version. We just try to get some symbol from 1.0 version
if sys.platform == 'win32':
win_cls = WinDLL
else:
win_cls = None
return usb.libloader.load_locate_library(
('usb-1.0', 'libusb-1.0', 'usb'),
'cygusb-1.0.dll', 'Libusb 1',
win_cls=win_cls,
find_library=find_library, check_symbols=('libusb_init',))
def _setup_prototypes(lib):
# void libusb_set_debug (libusb_context *ctx, int level)
lib.libusb_set_debug.argtypes = [c_void_p, c_int]
# int libusb_init (libusb_context **context)
lib.libusb_init.argtypes = [POINTER(c_void_p)]
# void libusb_exit (struct libusb_context *ctx)
lib.libusb_exit.argtypes = [c_void_p]
# ssize_t libusb_get_device_list (libusb_context *ctx,
# libusb_device ***list)
lib.libusb_get_device_list.argtypes = [
c_void_p,
POINTER(POINTER(c_void_p))
]
# void libusb_free_device_list (libusb_device **list,
# int unref_devices)
lib.libusb_free_device_list.argtypes = [
POINTER(c_void_p),
c_int
]
# libusb_device *libusb_ref_device (libusb_device *dev)
lib.libusb_ref_device.argtypes = [c_void_p]
lib.libusb_ref_device.restype = c_void_p
# void libusb_unref_device(libusb_device *dev)
lib.libusb_unref_device.argtypes = [c_void_p]
# int libusb_open(libusb_device *dev, libusb_device_handle **handle)
lib.libusb_open.argtypes = [c_void_p, POINTER(_libusb_device_handle)]
# void libusb_close(libusb_device_handle *dev_handle)
lib.libusb_close.argtypes = [_libusb_device_handle]
# int libusb_set_configuration(libusb_device_handle *dev,
# int configuration)
lib.libusb_set_configuration.argtypes = [_libusb_device_handle, c_int]
# int libusb_get_configuration(libusb_device_handle *dev,
# int *config)
lib.libusb_get_configuration.argtypes = [_libusb_device_handle, POINTER(c_int)]
# int libusb_claim_interface(libusb_device_handle *dev,
# int interface_number)
lib.libusb_claim_interface.argtypes = [_libusb_device_handle, c_int]
# int libusb_release_interface(libusb_device_handle *dev,
# int interface_number)
lib.libusb_release_interface.argtypes = [_libusb_device_handle, c_int]
# int libusb_set_interface_alt_setting(libusb_device_handle *dev,
# int interface_number,
# int alternate_setting)
lib.libusb_set_interface_alt_setting.argtypes = [
_libusb_device_handle,
c_int,
c_int
]
# int libusb_reset_device (libusb_device_handle *dev)
lib.libusb_reset_device.argtypes = [_libusb_device_handle]
# int libusb_kernel_driver_active(libusb_device_handle *dev,
# int interface)
lib.libusb_kernel_driver_active.argtypes = [
_libusb_device_handle,
c_int
]
# int libusb_detach_kernel_driver(libusb_device_handle *dev,
# int interface)
lib.libusb_detach_kernel_driver.argtypes = [
_libusb_device_handle,
c_int
]
# int libusb_attach_kernel_driver(libusb_device_handle *dev,
# int interface)
lib.libusb_attach_kernel_driver.argtypes = [
_libusb_device_handle,
c_int
]
# int libusb_get_device_descriptor(
# libusb_device *dev,
# struct libusb_device_descriptor *desc
# )
lib.libusb_get_device_descriptor.argtypes = [
c_void_p,
POINTER(_libusb_device_descriptor)
]
# int libusb_get_config_descriptor(
# libusb_device *dev,
# uint8_t config_index,
# struct libusb_config_descriptor **config
# )
lib.libusb_get_config_descriptor.argtypes = [
c_void_p,
c_uint8,
POINTER(POINTER(_libusb_config_descriptor))
]
# void libusb_free_config_descriptor(
# struct libusb_config_descriptor *config
# )
lib.libusb_free_config_descriptor.argtypes = [
POINTER(_libusb_config_descriptor)
]
# int libusb_get_string_descriptor_ascii(libusb_device_handle *dev,
# uint8_t desc_index,
# unsigned char *data,
# int length)
lib.libusb_get_string_descriptor_ascii.argtypes = [
_libusb_device_handle,
c_uint8,
POINTER(c_ubyte),
c_int
]
# int libusb_control_transfer(libusb_device_handle *dev_handle,
# uint8_t bmRequestType,
# uint8_t bRequest,
# uint16_t wValue,
# uint16_t wIndex,
# unsigned char *data,
# uint16_t wLength,
# unsigned int timeout)
lib.libusb_control_transfer.argtypes = [
_libusb_device_handle,
c_uint8,
c_uint8,
c_uint16,
c_uint16,
POINTER(c_ubyte),
c_uint16,
c_uint
]
#int libusb_bulk_transfer(
# struct libusb_device_handle *dev_handle,
# unsigned char endpoint,
# unsigned char *data,
# int length,
# int *transferred,
# unsigned int timeout
# )
lib.libusb_bulk_transfer.argtypes = [
_libusb_device_handle,
c_ubyte,
POINTER(c_ubyte),
c_int,
POINTER(c_int),
c_uint
]
# int libusb_interrupt_transfer(
# libusb_device_handle *dev_handle,
# unsigned char endpoint,
# unsigned char *data,
# int length,
# int *actual_length,
# unsigned int timeout
# );
lib.libusb_interrupt_transfer.argtypes = [
_libusb_device_handle,
c_ubyte,
POINTER(c_ubyte),
c_int,
POINTER(c_int),
c_uint
]
# libusb_transfer* libusb_alloc_transfer(int iso_packets);
lib.libusb_alloc_transfer.argtypes = [c_int]
lib.libusb_alloc_transfer.restype = POINTER(_libusb_transfer)
# void libusb_free_transfer(struct libusb_transfer *transfer)
lib.libusb_free_transfer.argtypes = [POINTER(_libusb_transfer)]
# int libusb_submit_transfer(struct libusb_transfer *transfer);
lib.libusb_submit_transfer.argtypes = [POINTER(_libusb_transfer)]
if hasattr(lib, 'libusb_strerror'):
# const char *libusb_strerror(enum libusb_error errcode)
lib.libusb_strerror.argtypes = [c_uint]
lib.libusb_strerror.restype = c_char_p
# int libusb_clear_halt(libusb_device_handle *dev, unsigned char endpoint)
lib.libusb_clear_halt.argtypes = [_libusb_device_handle, c_ubyte]
# void libusb_set_iso_packet_lengths(
# libusb_transfer* transfer,
# unsigned int length
# );
def libusb_set_iso_packet_lengths(transfer_p, length):
r"""This function is inline in the libusb.h file, so we must implement
it.
lib.libusb_set_iso_packet_lengths.argtypes = [
POINTER(_libusb_transfer),
c_int
]
"""
transfer = transfer_p.contents
for iso_packet_desc in _get_iso_packet_list(transfer):
iso_packet_desc.length = length
lib.libusb_set_iso_packet_lengths = libusb_set_iso_packet_lengths
#int libusb_get_max_iso_packet_size(libusb_device* dev,
# unsigned char endpoint);
lib.libusb_get_max_iso_packet_size.argtypes = [c_void_p,
c_ubyte]
# void libusb_fill_iso_transfer(
# struct libusb_transfer* transfer,
# libusb_device_handle* dev_handle,
# unsigned char endpoint,
# unsigned char* buffer,
# int length,
# int num_iso_packets,
# libusb_transfer_cb_fn callback,
# void * user_data,
# unsigned int timeout
# );
def libusb_fill_iso_transfer(_libusb_transfer_p, dev_handle, endpoint, buffer, length,
num_iso_packets, callback, user_data, timeout):
r"""This function is inline in the libusb.h file, so we must implement
it.
lib.libusb_fill_iso_transfer.argtypes = [
_libusb_transfer,
_libusb_device_handle,
c_ubyte,
POINTER(c_ubyte),
c_int,
c_int,
_libusb_transfer_cb_fn_p,
c_void_p,
c_uint
]
"""
transfer = _libusb_transfer_p.contents
transfer.dev_handle = dev_handle
transfer.endpoint = endpoint
transfer.type = _LIBUSB_TRANSFER_TYPE_ISOCHRONOUS
transfer.timeout = timeout
transfer.buffer = cast(buffer, c_void_p)
transfer.length = length
transfer.num_iso_packets = num_iso_packets
transfer.user_data = user_data
transfer.callback = callback
lib.libusb_fill_iso_transfer = libusb_fill_iso_transfer
# uint8_t libusb_get_bus_number(libusb_device *dev)
lib.libusb_get_bus_number.argtypes = [c_void_p]
lib.libusb_get_bus_number.restype = c_uint8
# uint8_t libusb_get_device_address(libusb_device *dev)
lib.libusb_get_device_address.argtypes = [c_void_p]
lib.libusb_get_device_address.restype = c_uint8
try:
# uint8_t libusb_get_device_speed(libusb_device *dev)
lib.libusb_get_device_speed.argtypes = [c_void_p]
lib.libusb_get_device_speed.restype = c_uint8
except AttributeError:
pass
try:
# uint8_t libusb_get_port_number(libusb_device *dev)
lib.libusb_get_port_number.argtypes = [c_void_p]
lib.libusb_get_port_number.restype = c_uint8
except AttributeError:
pass
try:
# int libusb_get_port_numbers(libusb_device *dev,
# uint8_t* port_numbers,
# int port_numbers_len)
lib.libusb_get_port_numbers.argtypes = [
c_void_p,
POINTER(c_uint8),
c_int
]
lib.libusb_get_port_numbers.restype = c_int
except AttributeError:
pass
#int libusb_handle_events(libusb_context *ctx);
lib.libusb_handle_events.argtypes = [c_void_p]
# check a libusb function call
def _check(ret):
if hasattr(ret, 'value'):
ret = ret.value
if ret < 0:
if ret == LIBUSB_ERROR_NOT_SUPPORTED:
raise NotImplementedError(_strerror(ret))
else:
raise USBError(_strerror(ret), ret, _libusb_errno[ret])
return ret
# wrap a device
class _Device(_objfinalizer.AutoFinalizedObject):
def __init__(self, devid):
self.devid = _lib.libusb_ref_device(devid)
def _finalize_object(self):
_lib.libusb_unref_device(self.devid)
# wrap a descriptor and keep a reference to another object
# Thanks to Thomas Reitmayr.
class _WrapDescriptor(object):
def __init__(self, desc, obj = None):
self.obj = obj
self.desc = desc
def __getattr__(self, name):
return getattr(self.desc, name)
# wrap a configuration descriptor
class _ConfigDescriptor(_objfinalizer.AutoFinalizedObject):
def __init__(self, desc):
self.desc = desc
def _finalize_object(self):
_lib.libusb_free_config_descriptor(self.desc)
def __getattr__(self, name):
return getattr(self.desc.contents, name)
# iterator for libusb devices
class _DevIterator(_objfinalizer.AutoFinalizedObject):
def __init__(self, ctx):
self.dev_list = POINTER(c_void_p)()
self.num_devs = _check(_lib.libusb_get_device_list(
ctx,
byref(self.dev_list))
)
def __iter__(self):
for i in range(self.num_devs):
yield _Device(self.dev_list[i])
def _finalize_object(self):
_lib.libusb_free_device_list(self.dev_list, 1)
class _DeviceHandle(object):
def __init__(self, dev):
self.handle = _libusb_device_handle()
self.devid = dev.devid
_check(_lib.libusb_open(self.devid, byref(self.handle)))
class _IsoTransferHandler(_objfinalizer.AutoFinalizedObject):
def __init__(self, dev_handle, ep, buff, timeout):
address, length = buff.buffer_info()
packet_length = _lib.libusb_get_max_iso_packet_size(dev_handle.devid, ep)
packet_count = int(math.ceil(float(length) / packet_length))
self.transfer = _lib.libusb_alloc_transfer(packet_count)
_lib.libusb_fill_iso_transfer(self.transfer,
dev_handle.handle,
ep,
cast(address, POINTER(c_ubyte)),
length,
packet_count,
_libusb_transfer_cb_fn_p(self.__callback),
None,
timeout)
self.__set_packets_length(length, packet_length)
def _finalize_object(self):
_lib.libusb_free_transfer(self.transfer)
def submit(self, ctx = None):
self.__callback_done = 0
_check(_lib.libusb_submit_transfer(self.transfer))
while not self.__callback_done:
_check(_lib.libusb_handle_events(ctx))
status = int(self.transfer.contents.status)
if status != LIBUSB_TRANSFER_COMPLETED:
raise usb.USBError(_str_transfer_error[status],
status,
_transfer_errno[status])
return self.__compute_size_transf_data()
def __compute_size_transf_data(self):
return sum([t.actual_length for t in
_get_iso_packet_list(self.transfer.contents)])
def __set_packets_length(self, n, packet_length):
_lib.libusb_set_iso_packet_lengths(self.transfer, packet_length)
r = n % packet_length
if r:
iso_packets = _get_iso_packet_list(self.transfer.contents)
# When the device is disconnected, this list may
# return with length 0
if len(iso_packets):
iso_packets[-1].length = r
def __callback(self, transfer):
self.__callback_done = 1
# implementation of libusb 1.0 backend
class _LibUSB(usb.backend.IBackend):
@methodtrace(_logger)
def __init__(self, lib):
usb.backend.IBackend.__init__(self)
self.lib = lib
self.ctx = c_void_p()
_check(self.lib.libusb_init(byref(self.ctx)))
@methodtrace(_logger)
def _finalize_object(self):
self.lib.libusb_exit(self.ctx)
@methodtrace(_logger)
def enumerate_devices(self):
return _DevIterator(self.ctx)
@methodtrace(_logger)
def get_device_descriptor(self, dev):
dev_desc = _libusb_device_descriptor()
_check(self.lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc)))
dev_desc.bus = self.lib.libusb_get_bus_number(dev.devid)
dev_desc.address = self.lib.libusb_get_device_address(dev.devid)
# Only available in newer versions of libusb
try:
dev_desc.speed = self.lib.libusb_get_device_speed(dev.devid)
except AttributeError:
dev_desc.speed = None
# Only available in newer versions of libusb
try:
dev_desc.port_number = self.lib.libusb_get_port_number(dev.devid)
except AttributeError:
dev_desc.port_number = None
# Only available in newer versions of libusb
try:
buff = (c_uint8 * 7)() # USB 3.0 maximum depth is 7
written = dev_desc.port_numbers = self.lib.libusb_get_port_numbers(
dev.devid, buff, len(buff))
if written > 0:
dev_desc.port_numbers = tuple(buff[:written])
else:
dev_desc.port_numbers = None
except AttributeError:
dev_desc.port_numbers = None
return dev_desc
@methodtrace(_logger)
def get_configuration_descriptor(self, dev, config):
cfg = POINTER(_libusb_config_descriptor)()
_check(self.lib.libusb_get_config_descriptor(
dev.devid,
config, byref(cfg)))
config_desc = _ConfigDescriptor(cfg)
config_desc.extra_descriptors = (
config_desc.extra[:config_desc.extra_length])
return config_desc
@methodtrace(_logger)
def get_interface_descriptor(self, dev, intf, alt, config):
cfg = self.get_configuration_descriptor(dev, config)
if intf >= cfg.bNumInterfaces:
raise IndexError('Invalid interface index ' + str(intf))
i = cfg.interface[intf]
if alt >= i.num_altsetting:
raise IndexError('Invalid alternate setting index ' + str(alt))
intf_desc = i.altsetting[alt]
intf_desc.extra_descriptors = intf_desc.extra[:intf_desc.extra_length]
return _WrapDescriptor(intf_desc, cfg)
@methodtrace(_logger)
def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
i = self.get_interface_descriptor(dev, intf, alt, config)
if ep > i.bNumEndpoints:
raise IndexError('Invalid endpoint index ' + str(ep))
ep_desc = i.endpoint[ep]
ep_desc.extra_descriptors = ep_desc.extra[:ep_desc.extra_length]
return _WrapDescriptor(ep_desc, i)
@methodtrace(_logger)
def open_device(self, dev):
return _DeviceHandle(dev)
@methodtrace(_logger)
def close_device(self, dev_handle):
self.lib.libusb_close(dev_handle.handle)
@methodtrace(_logger)
def set_configuration(self, dev_handle, config_value):
_check(self.lib.libusb_set_configuration(dev_handle.handle, config_value))
@methodtrace(_logger)
def get_configuration(self, dev_handle):
config = c_int()
_check(self.lib.libusb_get_configuration(dev_handle.handle, byref(config)))
return config.value
@methodtrace(_logger)
def set_interface_altsetting(self, dev_handle, intf, altsetting):
_check(self.lib.libusb_set_interface_alt_setting(
dev_handle.handle,
intf,
altsetting))
@methodtrace(_logger)
def claim_interface(self, dev_handle, intf):
_check(self.lib.libusb_claim_interface(dev_handle.handle, intf))
@methodtrace(_logger)
def release_interface(self, dev_handle, intf):
_check(self.lib.libusb_release_interface(dev_handle.handle, intf))
@methodtrace(_logger)
def bulk_write(self, dev_handle, ep, intf, data, timeout):
return self.__write(self.lib.libusb_bulk_transfer,
dev_handle,
ep,
intf,
data,
timeout)
@methodtrace(_logger)
def bulk_read(self, dev_handle, ep, intf, buff, timeout):
return self.__read(self.lib.libusb_bulk_transfer,
dev_handle,
ep,
intf,
buff,
timeout)
@methodtrace(_logger)
def intr_write(self, dev_handle, ep, intf, data, timeout):
return self.__write(self.lib.libusb_interrupt_transfer,
dev_handle,
ep,
intf,
data,
timeout)
@methodtrace(_logger)
def intr_read(self, dev_handle, ep, intf, buff, timeout):
return self.__read(self.lib.libusb_interrupt_transfer,
dev_handle,
ep,
intf,
buff,
timeout)
@methodtrace(_logger)
def iso_write(self, dev_handle, ep, intf, data, timeout):
handler = _IsoTransferHandler(dev_handle, ep, data, timeout)
return handler.submit(self.ctx)
@methodtrace(_logger)
def iso_read(self, dev_handle, ep, intf, buff, timeout):
handler = _IsoTransferHandler(dev_handle, ep, buff, timeout)
return handler.submit(self.ctx)
@methodtrace(_logger)
def ctrl_transfer(self,
dev_handle,
bmRequestType,
bRequest,
wValue,
wIndex,
data,
timeout):
addr, length = data.buffer_info()
length *= data.itemsize
ret = _check(self.lib.libusb_control_transfer(
dev_handle.handle,
bmRequestType,
bRequest,
wValue,
wIndex,
cast(addr, POINTER(c_ubyte)),
length,
timeout))
return ret
@methodtrace(_logger)
def clear_halt(self, dev_handle, ep):
_check(self.lib.libusb_clear_halt(dev_handle.handle, ep))
@methodtrace(_logger)
def reset_device(self, dev_handle):
_check(self.lib.libusb_reset_device(dev_handle.handle))
@methodtrace(_logger)
def is_kernel_driver_active(self, dev_handle, intf):
return bool(_check(self.lib.libusb_kernel_driver_active(dev_handle.handle,
intf)))
@methodtrace(_logger)
def detach_kernel_driver(self, dev_handle, intf):
_check(self.lib.libusb_detach_kernel_driver(dev_handle.handle, intf))
@methodtrace(_logger)
def attach_kernel_driver(self, dev_handle, intf):
_check(self.lib.libusb_attach_kernel_driver(dev_handle.handle, intf))
def __write(self, fn, dev_handle, ep, intf, data, timeout):
address, length = data.buffer_info()
length *= data.itemsize
transferred = c_int()
retval = fn(dev_handle.handle,
ep,
cast(address, POINTER(c_ubyte)),
length,
byref(transferred),
timeout)
# do not assume LIBUSB_ERROR_TIMEOUT means no I/O.
if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT):
_check(retval)
return transferred.value
def __read(self, fn, dev_handle, ep, intf, buff, timeout):
address, length = buff.buffer_info()
length *= buff.itemsize
transferred = c_int()
retval = fn(dev_handle.handle,
ep,
cast(address, POINTER(c_ubyte)),
length,
byref(transferred),
timeout)
# do not assume LIBUSB_ERROR_TIMEOUT means no I/O.
if not (transferred.value and retval == LIBUSB_ERROR_TIMEOUT):
_check(retval)
return transferred.value
def get_backend(find_library=None):
global _lib
try:
if _lib is None:
_lib = _load_library(find_library=find_library)
_setup_prototypes(_lib)
return _LibUSB(_lib)
except usb.libloader.LibaryException:
# exception already logged (if any)
_logger.error('Error loading libusb 1.0 backend', exc_info=False)
return None
except Exception:
_logger.error('Error loading libusb 1.0 backend', exc_info=True)
return None
pyusb-1.0.0/usb/backend/libusb0.py 0000664 0001750 0001750 00000056346 12711231457 017551 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
from ctypes import *
import os
import usb.backend
import usb.util
import sys
from usb.core import USBError
from usb._debug import methodtrace
import usb._interop as _interop
import logging
import usb.libloader
__author__ = 'Wander Lairson Costa'
__all__ = ['get_backend']
_logger = logging.getLogger('usb.backend.libusb0')
# usb.h
if sys.platform.find('bsd') != -1 or sys.platform.find('mac') != -1 or \
sys.platform.find('darwin') != -1 or sys.platform.find('sunos5') != -1:
_PATH_MAX = 1024
elif sys.platform == 'win32' or sys.platform == 'cygwin':
_PATH_MAX = 511
else:
_PATH_MAX = os.pathconf('.', 'PC_PATH_MAX')
# libusb-win32 makes all structures packed, while
# default libusb only does for some structures
# _PackPolicy defines the structure packing according
# to the platform.
class _PackPolicy(object):
pass
if sys.platform == 'win32' or sys.platform == 'cygwin':
_PackPolicy._pack_ = 1
# Data structures
class _usb_descriptor_header(Structure):
_pack_ = 1
_fields_ = [('blength', c_uint8),
('bDescriptorType', c_uint8)]
class _usb_string_descriptor(Structure):
_pack_ = 1
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('wData', c_uint16)]
class _usb_endpoint_descriptor(Structure, _PackPolicy):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bEndpointAddress', c_uint8),
('bmAttributes', c_uint8),
('wMaxPacketSize', c_uint16),
('bInterval', c_uint8),
('bRefresh', c_uint8),
('bSynchAddress', c_uint8),
('extra', POINTER(c_uint8)),
('extralen', c_int)]
class _usb_interface_descriptor(Structure, _PackPolicy):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bInterfaceNumber', c_uint8),
('bAlternateSetting', c_uint8),
('bNumEndpoints', c_uint8),
('bInterfaceClass', c_uint8),
('bInterfaceSubClass', c_uint8),
('bInterfaceProtocol', c_uint8),
('iInterface', c_uint8),
('endpoint', POINTER(_usb_endpoint_descriptor)),
('extra', POINTER(c_uint8)),
('extralen', c_int)]
class _usb_interface(Structure, _PackPolicy):
_fields_ = [('altsetting', POINTER(_usb_interface_descriptor)),
('num_altsetting', c_int)]
class _usb_config_descriptor(Structure, _PackPolicy):
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('wTotalLength', c_uint16),
('bNumInterfaces', c_uint8),
('bConfigurationValue', c_uint8),
('iConfiguration', c_uint8),
('bmAttributes', c_uint8),
('bMaxPower', c_uint8),
('interface', POINTER(_usb_interface)),
('extra', POINTER(c_uint8)),
('extralen', c_int)]
class _usb_device_descriptor(Structure, _PackPolicy):
_pack_ = 1
_fields_ = [('bLength', c_uint8),
('bDescriptorType', c_uint8),
('bcdUSB', c_uint16),
('bDeviceClass', c_uint8),
('bDeviceSubClass', c_uint8),
('bDeviceProtocol', c_uint8),
('bMaxPacketSize0', c_uint8),
('idVendor', c_uint16),
('idProduct', c_uint16),
('bcdDevice', c_uint16),
('iManufacturer', c_uint8),
('iProduct', c_uint8),
('iSerialNumber', c_uint8),
('bNumConfigurations', c_uint8)]
class _usb_device(Structure, _PackPolicy):
pass
class _usb_bus(Structure, _PackPolicy):
pass
_usb_device._fields_ = [('next', POINTER(_usb_device)),
('prev', POINTER(_usb_device)),
('filename', c_int8 * (_PATH_MAX + 1)),
('bus', POINTER(_usb_bus)),
('descriptor', _usb_device_descriptor),
('config', POINTER(_usb_config_descriptor)),
('dev', c_void_p),
('devnum', c_uint8),
('num_children', c_ubyte),
('children', POINTER(POINTER(_usb_device)))]
_usb_bus._fields_ = [('next', POINTER(_usb_bus)),
('prev', POINTER(_usb_bus)),
('dirname', c_char * (_PATH_MAX + 1)),
('devices', POINTER(_usb_device)),
('location', c_uint32),
('root_dev', POINTER(_usb_device))]
_usb_dev_handle = c_void_p
class _DeviceDescriptor:
def __init__(self, dev):
desc = dev.descriptor
self.bLength = desc.bLength
self.bDescriptorType = desc.bDescriptorType
self.bcdUSB = desc.bcdUSB
self.bDeviceClass = desc.bDeviceClass
self.bDeviceSubClass = desc.bDeviceSubClass
self.bDeviceProtocol = desc.bDeviceProtocol
self.bMaxPacketSize0 = desc.bMaxPacketSize0
self.idVendor = desc.idVendor
self.idProduct = desc.idProduct
self.bcdDevice = desc.bcdDevice
self.iManufacturer = desc.iManufacturer
self.iProduct = desc.iProduct
self.iSerialNumber = desc.iSerialNumber
self.bNumConfigurations = desc.bNumConfigurations
self.address = dev.devnum
self.bus = dev.bus[0].location
self.port_number = None
self.port_numbers = None
self.speed = None
_lib = None
def _load_library(find_library=None):
return usb.libloader.load_locate_library(
('usb-0.1', 'usb', 'libusb0'),
'cygusb0.dll', 'Libusb 0',
find_library=find_library
)
def _setup_prototypes(lib):
# usb_dev_handle *usb_open(struct usb_device *dev);
lib.usb_open.argtypes = [POINTER(_usb_device)]
lib.usb_open.restype = _usb_dev_handle
# int usb_close(usb_dev_handle *dev);
lib.usb_close.argtypes = [_usb_dev_handle]
# int usb_get_string(usb_dev_handle *dev,
# int index,
# int langid,
# char *buf,
# size_t buflen);
lib.usb_get_string.argtypes = [
_usb_dev_handle,
c_int,
c_int,
c_char_p,
c_size_t
]
# int usb_get_string_simple(usb_dev_handle *dev,
# int index,
# char *buf,
# size_t buflen);
lib.usb_get_string_simple.argtypes = [
_usb_dev_handle,
c_int,
c_char_p,
c_size_t
]
# int usb_get_descriptor_by_endpoint(usb_dev_handle *udev,
# int ep,
# unsigned char type,
# unsigned char index,
# void *buf,
# int size);
lib.usb_get_descriptor_by_endpoint.argtypes = [
_usb_dev_handle,
c_int,
c_ubyte,
c_ubyte,
c_void_p,
c_int
]
# int usb_get_descriptor(usb_dev_handle *udev,
# unsigned char type,
# unsigned char index,
# void *buf,
# int size);
lib.usb_get_descriptor.argtypes = [
_usb_dev_handle,
c_ubyte,
c_ubyte,
c_void_p,
c_int
]
# int usb_bulk_write(usb_dev_handle *dev,
# int ep,
# const char *bytes,
# int size,
# int timeout);
lib.usb_bulk_write.argtypes = [
_usb_dev_handle,
c_int,
c_char_p,
c_int,
c_int
]
# int usb_bulk_read(usb_dev_handle *dev,
# int ep,
# char *bytes,
# int size,
# int timeout);
lib.usb_bulk_read.argtypes = [
_usb_dev_handle,
c_int,
c_char_p,
c_int,
c_int
]
# int usb_interrupt_write(usb_dev_handle *dev,
# int ep,
# const char *bytes,
# int size,
# int timeout);
lib.usb_interrupt_write.argtypes = [
_usb_dev_handle,
c_int,
c_char_p,
c_int,
c_int
]
# int usb_interrupt_read(usb_dev_handle *dev,
# int ep,
# char *bytes,
# int size,
# int timeout);
lib.usb_interrupt_read.argtypes = [
_usb_dev_handle,
c_int,
c_char_p,
c_int,
c_int
]
# int usb_control_msg(usb_dev_handle *dev,
# int requesttype,
# int request,
# int value,
# int index,
# char *bytes,
# int size,
# int timeout);
lib.usb_control_msg.argtypes = [
_usb_dev_handle,
c_int,
c_int,
c_int,
c_int,
c_char_p,
c_int,
c_int
]
# int usb_set_configuration(usb_dev_handle *dev, int configuration);
lib.usb_set_configuration.argtypes = [_usb_dev_handle, c_int]
# int usb_claim_interface(usb_dev_handle *dev, int interface);
lib.usb_claim_interface.argtypes = [_usb_dev_handle, c_int]
# int usb_release_interface(usb_dev_handle *dev, int interface);
lib.usb_release_interface.argtypes = [_usb_dev_handle, c_int]
# int usb_set_altinterface(usb_dev_handle *dev, int alternate);
lib.usb_set_altinterface.argtypes = [_usb_dev_handle, c_int]
# int usb_resetep(usb_dev_handle *dev, unsigned int ep);
lib.usb_resetep.argtypes = [_usb_dev_handle, c_int]
# int usb_clear_halt(usb_dev_handle *dev, unsigned int ep);
lib.usb_clear_halt.argtypes = [_usb_dev_handle, c_int]
# int usb_reset(usb_dev_handle *dev);
lib.usb_reset.argtypes = [_usb_dev_handle]
# char *usb_strerror(void);
lib.usb_strerror.argtypes = []
lib.usb_strerror.restype = c_char_p
# void usb_set_debug(int level);
lib.usb_set_debug.argtypes = [c_int]
# struct usb_device *usb_device(usb_dev_handle *dev);
lib.usb_device.argtypes = [_usb_dev_handle]
lib.usb_device.restype = POINTER(_usb_device)
# struct usb_bus *usb_get_busses(void);
lib.usb_get_busses.restype = POINTER(_usb_bus)
# linux only
# int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface);
if hasattr(lib, 'usb_detach_kernel_driver_np'):
lib.usb_detach_kernel_driver_np.argtypes = [_usb_dev_handle, c_int]
# libusb-win32 only
# int usb_isochronous_setup_async(usb_dev_handle *dev,
# void **context,
# unsigned char ep,
# int pktsize)
if hasattr(lib, 'usb_isochronous_setup_async'):
lib.usb_isochronous_setup_async.argtypes = \
[_usb_dev_handle, POINTER(c_void_p), c_uint8, c_int]
# int usb_bulk_setup_async(usb_dev_handle *dev,
# void **context,
# unsigned char ep)
if hasattr(lib, 'usb_bulk_setup_async'):
lib.usb_bulk_setup_async.argtypes = \
[_usb_dev_handle, POINTER(c_void_p), c_uint8]
# int usb_interrupt_setup_async(usb_dev_handle *dev,
# void **context,
# unsigned char ep)
if hasattr(lib, 'usb_interrupt_setup_async'):
lib.usb_interrupt_setup_async.argtypes = \
[_usb_dev_handle, POINTER(c_void_p), c_uint8]
# int usb_submit_async(void *context, char *bytes, int size)
if hasattr(lib, 'usb_submit_async'):
lib.usb_submit_async.argtypes = [c_void_p, c_char_p, c_int]
# int usb_reap_async(void *context, int timeout)
if hasattr(lib, 'usb_reap_async'):
lib.usb_reap_async.argtypes = [c_void_p, c_int]
# int usb_reap_async_nocancel(void *context, int timeout)
if hasattr(lib, 'usb_reap_async_nocancel'):
lib.usb_reap_async_nocancel.argtypes = [c_void_p, c_int]
# int usb_cancel_async(void *context)
if hasattr(lib, 'usb_cancel_async'):
lib.usb_cancel_async.argtypes = [c_void_p]
# int usb_free_async(void **context)
if hasattr(lib, 'usb_free_async'):
lib.usb_free_async.argtypes = [POINTER(c_void_p)]
def _check(ret):
if ret is None:
errmsg = _lib.usb_strerror()
else:
if hasattr(ret, 'value'):
ret = ret.value
if ret < 0:
errmsg = _lib.usb_strerror()
# No error means that we need to get the error
# message from the return code
# Thanks to Nicholas Wheeler to point out the problem...
# Also see issue #2860940
if errmsg.lower() == 'no error':
errmsg = os.strerror(-ret)
else:
return ret
raise USBError(errmsg, ret)
def _has_iso_transfer():
return hasattr(_lib, 'usb_isochronous_setup_async')
# implementation of libusb 0.1.x backend
class _LibUSB(usb.backend.IBackend):
@methodtrace(_logger)
def enumerate_devices(self):
_check(_lib.usb_find_busses())
_check(_lib.usb_find_devices())
bus = _lib.usb_get_busses()
while bool(bus):
dev = bus[0].devices
while bool(dev):
yield dev[0]
dev = dev[0].next
bus = bus[0].next
@methodtrace(_logger)
def get_device_descriptor(self, dev):
return _DeviceDescriptor(dev)
@methodtrace(_logger)
def get_configuration_descriptor(self, dev, config):
if config >= dev.descriptor.bNumConfigurations:
raise IndexError('Invalid configuration index ' + str(config))
config_desc = dev.config[config]
config_desc.extra_descriptors = config_desc.extra[:config_desc.extralen]
return config_desc
@methodtrace(_logger)
def get_interface_descriptor(self, dev, intf, alt, config):
cfgdesc = self.get_configuration_descriptor(dev, config)
if intf >= cfgdesc.bNumInterfaces:
raise IndexError('Invalid interface index ' + str(intf))
interface = cfgdesc.interface[intf]
if alt >= interface.num_altsetting:
raise IndexError('Invalid alternate setting index ' + str(alt))
intf_desc = interface.altsetting[alt]
intf_desc.extra_descriptors = intf_desc.extra[:intf_desc.extralen]
return intf_desc
@methodtrace(_logger)
def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
interface = self.get_interface_descriptor(dev, intf, alt, config)
if ep >= interface.bNumEndpoints:
raise IndexError('Invalid endpoint index ' + str(ep))
ep_desc = interface.endpoint[ep]
ep_desc.extra_descriptors = ep_desc.extra[:ep_desc.extralen]
return ep_desc
@methodtrace(_logger)
def open_device(self, dev):
return _check(_lib.usb_open(dev))
@methodtrace(_logger)
def close_device(self, dev_handle):
_check(_lib.usb_close(dev_handle))
@methodtrace(_logger)
def set_configuration(self, dev_handle, config_value):
_check(_lib.usb_set_configuration(dev_handle, config_value))
@methodtrace(_logger)
def get_configuration(self, dev_handle):
bmRequestType = usb.util.build_request_type(
usb.util.CTRL_IN,
usb.util.CTRL_TYPE_STANDARD,
usb.util.CTRL_RECIPIENT_DEVICE
)
buff = usb.util.create_buffer(1)
ret = self.ctrl_transfer(
dev_handle,
bmRequestType,
0x08,
0,
0,
buff,
100)
assert ret == 1
return buff[0]
@methodtrace(_logger)
def set_interface_altsetting(self, dev_handle, intf, altsetting):
_check(_lib.usb_set_altinterface(dev_handle, altsetting))
@methodtrace(_logger)
def claim_interface(self, dev_handle, intf):
_check(_lib.usb_claim_interface(dev_handle, intf))
@methodtrace(_logger)
def release_interface(self, dev_handle, intf):
_check(_lib.usb_release_interface(dev_handle, intf))
@methodtrace(_logger)
def bulk_write(self, dev_handle, ep, intf, data, timeout):
return self.__write(_lib.usb_bulk_write,
dev_handle,
ep,
intf,
data, timeout)
@methodtrace(_logger)
def bulk_read(self, dev_handle, ep, intf, buff, timeout):
return self.__read(_lib.usb_bulk_read,
dev_handle,
ep,
intf,
buff,
timeout)
@methodtrace(_logger)
def intr_write(self, dev_handle, ep, intf, data, timeout):
return self.__write(_lib.usb_interrupt_write,
dev_handle,
ep,
intf,
data,
timeout)
@methodtrace(_logger)
def intr_read(self, dev_handle, ep, intf, buff, timeout):
return self.__read(_lib.usb_interrupt_read,
dev_handle,
ep,
intf,
buff,
timeout)
@methodtrace(_logger)
def iso_write(self, dev_handle, ep, intf, data, timeout):
if not _has_iso_transfer():
return usb.backend.IBackend.iso_write(self, dev_handle, ep, intf, data, timeout)
return self.__iso_transfer(dev_handle, ep, intf, data, timeout)
@methodtrace(_logger)
def iso_read(self, dev_handle, ep, intf, buff, timeout):
if not _has_iso_transfer():
return usb.backend.IBackend.iso_read(self, dev_handle, ep, intf, buff, timeout)
return self.__iso_transfer(dev_handle, ep, intf, buff, timeout)
@methodtrace(_logger)
def ctrl_transfer(self,
dev_handle,
bmRequestType,
bRequest,
wValue,
wIndex,
data,
timeout):
address, length = data.buffer_info()
length *= data.itemsize
return _check(_lib.usb_control_msg(
dev_handle,
bmRequestType,
bRequest,
wValue,
wIndex,
cast(address, c_char_p),
length,
timeout
))
@methodtrace(_logger)
def clear_halt(self, dev_handle, ep):
_check(_lib.usb_clear_halt(dev_handle, ep))
@methodtrace(_logger)
def reset_device(self, dev_handle):
_check(_lib.usb_reset(dev_handle))
@methodtrace(_logger)
def detach_kernel_driver(self, dev_handle, intf):
_check(_lib.usb_detach_kernel_driver_np(dev_handle, intf))
def __write(self, fn, dev_handle, ep, intf, data, timeout):
address, length = data.buffer_info()
length *= data.itemsize
return int(_check(fn(
dev_handle,
ep,
cast(address, c_char_p),
length,
timeout
)))
def __read(self, fn, dev_handle, ep, intf, buff, timeout):
address, length = buff.buffer_info()
length *= buff.itemsize
ret = int(_check(fn(
dev_handle,
ep,
cast(address, c_char_p),
length,
timeout
)))
return ret
def __iso_transfer(self, dev_handle, ep, intf, data, timeout):
context = c_void_p()
buff, length = data.buffer_info()
length *= data.itemsize
_check(_lib.usb_isochronous_setup_async(
dev_handle,
byref(context),
ep,
0))
transmitted = 0
try:
while transmitted < length:
_check(_lib.usb_submit_async(
context,
cast(buff + transmitted, c_char_p),
length - transmitted))
ret = _check(_lib.usb_reap_async(context, timeout))
if not ret:
return transmitted
transmitted += ret
except:
if not transmitted:
raise
finally:
_check(_lib.usb_free_async(byref(context)))
return transmitted
def get_backend(find_library=None):
global _lib
try:
if _lib is None:
_lib = _load_library(find_library)
_setup_prototypes(_lib)
_lib.usb_init()
return _LibUSB()
except usb.libloader.LibaryException:
# exception already logged (if any)
_logger.error('Error loading libusb 0.1 backend', exc_info=False)
return None
except Exception:
_logger.error('Error loading libusb 0.1 backend', exc_info=True)
return None
pyusb-1.0.0/usb/__init__.py 0000664 0001750 0001750 00000006736 12711231522 016350 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
r"""PyUSB - Easy USB access in Python
This package exports the following modules and subpackages:
core - the main USB implementation
legacy - the compatibility layer with 0.x version
backend - the support for backend implementations.
control - USB standard control requests.
libloader - helper module for backend library loading.
Since version 1.0, main PyUSB implementation lives in the 'usb.core'
module. New applications are encouraged to use it.
"""
import logging
import os
__author__ = 'Wander Lairson Costa'
# Use Semantic Versioning, http://semver.org/
version_info = (1, 0, 0)
__version__ = '%d.%d.%d' % version_info
__all__ = ['legacy', 'control', 'core', 'backend', 'util', 'libloader']
def _setup_log():
from usb import _debug
logger = logging.getLogger('usb')
debug_level = os.getenv('PYUSB_DEBUG')
if debug_level is not None:
_debug.enable_tracing(True)
filename = os.getenv('PYUSB_LOG_FILENAME')
LEVELS = {'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL}
level = LEVELS.get(debug_level, logging.CRITICAL + 10)
logger.setLevel(level = level)
try:
handler = logging.FileHandler(filename)
except:
handler = logging.StreamHandler()
fmt = logging.Formatter('%(asctime)s %(levelname)s:%(name)s:%(message)s')
handler.setFormatter(fmt)
logger.addHandler(handler)
else:
class NullHandler(logging.Handler):
def emit(self, record):
pass
# We set the log level to avoid delegation to the
# parent log handler (if there is one).
# Thanks to Chris Clark to pointing this out.
logger.setLevel(logging.CRITICAL + 10)
logger.addHandler(NullHandler())
_setup_log()
# We import all 'legacy' module symbols to provide compatibility
# with applications that use 0.x versions.
from usb.legacy import *
pyusb-1.0.0/usb/_lookup.py 0000664 0001750 0001750 00000006273 12661452153 016266 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Walker Inman
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
r"""usb._lookups - Lookup tables for USB
"""
descriptors = {
0x1 : "Device",
0x2 : "Configuration",
0x3 : "String",
0x4 : "Interface",
0x5 : "Endpoint",
0x6 : "Device qualifier",
0x7 : "Other speed configuration",
0x8 : "Interface power",
0x9 : "OTG",
0xA : "Debug",
0xB : "Interface association",
0xC : "Security",
0xD : "Key",
0xE : "Encryption type",
0xF : "Binary device object store (BOS)",
0x10 : "Device capability",
0x11 : "Wireless endpoint companion",
0x30 : "SuperSpeed endpoint companion",
}
device_classes = {
0x0 : "Specified at interface",
0x2 : "Communications Device",
0x9 : "Hub",
0xF : "Personal Healthcare Device",
0xDC : "Diagnostic Device",
0xE0 : "Wireless Controller",
0xEF : "Miscellaneous",
0xFF : "Vendor-specific",
}
interface_classes = {
0x0 : "Reserved",
0x1 : "Audio",
0x2 : "CDC Communication",
0x3 : "Human Interface Device",
0x5 : "Physical",
0x6 : "Image",
0x7 : "Printer",
0x8 : "Mass Storage",
0x9 : "Hub",
0xA : "CDC Data",
0xB : "Smart Card",
0xD : "Content Security",
0xE : "Video",
0xF : "Personal Healthcare",
0xDC : "Diagnostic Device",
0xE0 : "Wireless Controller",
0xEF : "Miscellaneous",
0xFE : "Application Specific",
0xFF : "Vendor Specific",
}
ep_attributes = {
0x0 : "Control",
0x1 : "Isochronous",
0x2 : "Bulk",
0x3 : "Interrupt",
}
MAX_POWER_UNITS_USB2p0 = 2 # mA
MAX_POWER_UNITS_USB_SUPERSPEED = 8 # mA
pyusb-1.0.0/usb/control.py 0000664 0001750 0001750 00000021043 12661452153 016266 0 ustar wander wander 0000000 0000000 # Copyright (C) 2009-2014 Wander Lairson Costa
#
# The following terms apply to all files associated
# with the software unless explicitly disclaimed in individual files.
#
# The authors hereby grant permission to use, copy, modify, distribute,
# and license this software and its documentation for any purpose, provided
# that existing copyright notices are retained in all copies and that this
# notice is included verbatim in any distributions. No written agreement,
# license, or royalty fee is required for any of the authorized uses.
# Modifications to this software may be copyrighted by their authors
# and need not follow the licensing terms described here, provided that
# the new terms are clearly indicated on the first page of each file where
# they apply.
#
# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
# MODIFICATIONS.
r"""usb.control - USB standard control requests
This module exports:
get_status - get recipeint status
clear_feature - clear a recipient feature
set_feature - set a recipient feature
get_descriptor - get a device descriptor
set_descriptor - set a device descriptor
get_configuration - get a device configuration
set_configuration - set a device configuration
get_interface - get a device interface
set_interface - set a device interface
"""
__author__ = 'Wander Lairson Costa'
__all__ = ['get_status',
'clear_feature',
'set_feature',
'get_descriptor',
'set_descriptor',
'get_configuration',
'set_configuration',
'get_interface',
'set_interface',
'ENDPOINT_HALT',
'FUNCTION_SUSPEND',
'DEVICE_REMOTE_WAKEUP',
'U1_ENABLE',
'U2_ENABLE',
'LTM_ENABLE']
import usb.util as util
import usb.core as core
def _parse_recipient(recipient, direction):
if recipient is None:
r = util.CTRL_RECIPIENT_DEVICE
wIndex = 0
elif isinstance(recipient, core.Interface):
r = util.CTRL_RECIPIENT_INTERFACE
wIndex = recipient.bInterfaceNumber
elif isinstance(recipient, core.Endpoint):
r = util.CTRL_RECIPIENT_ENDPOINT
wIndex = recipient.bEndpointAddress
else:
raise ValueError('Invalid recipient.')
bmRequestType = util.build_request_type(
direction,
util.CTRL_TYPE_STANDARD,
r
)
return (bmRequestType, wIndex)
# standard feature selectors from USB 2.0/3.0
ENDPOINT_HALT = 0
FUNCTION_SUSPEND = 0
DEVICE_REMOTE_WAKEUP = 1
U1_ENABLE = 48
U2_ENABLE = 49
LTM_ENABLE = 50
def get_status(dev, recipient = None):
r"""Return the status for the specified recipient.
dev is the Device object to which the request will be
sent to.
The recipient can be None (on which the status will be queried
from the device), an Interface or Endpoint descriptors.
The status value is returned as an integer with the lower
word being the two bytes status value.
"""
bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_IN)
ret = dev.ctrl_transfer(bmRequestType = bmRequestType,
bRequest = 0x00,
wIndex = wIndex,
data_or_wLength = 2)
return ret[0] | (ret[1] << 8)
def clear_feature(dev, feature, recipient = None):
r"""Clear/disable a specific feature.
dev is the Device object to which the request will be
sent to.
feature is the feature you want to disable.
The recipient can be None (on which the status will be queried
from the device), an Interface or Endpoint descriptors.
"""
if feature == ENDPOINT_HALT:
dev.clear_halt(recipient)
else:
bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT)
dev.ctrl_transfer(bmRequestType = bmRequestType,
bRequest = 0x01,
wIndex = wIndex,
wValue = feature)
def set_feature(dev, feature, recipient = None):
r"""Set/enable a specific feature.
dev is the Device object to which the request will be
sent to.
feature is the feature you want to enable.
The recipient can be None (on which the status will be queried
from the device), an Interface or Endpoint descriptors.
"""
bmRequestType, wIndex = _parse_recipient(recipient, util.CTRL_OUT)
dev.ctrl_transfer(bmRequestType = bmRequestType,
bRequest = 0x03,
wIndex = wIndex,
wValue = feature)
def get_descriptor(dev, desc_size, desc_type, desc_index, wIndex = 0):
r"""Return the specified descriptor.
dev is the Device object to which the request will be
sent to.
desc_size is the descriptor size.
desc_type and desc_index are the descriptor type and index,
respectively. wIndex index is used for string descriptors
and represents the Language ID. For other types of descriptors,
it is zero.
"""
wValue = desc_index | (desc_type << 8)
bmRequestType = util.build_request_type(
util.CTRL_IN,
util.CTRL_TYPE_STANDARD,
util.CTRL_RECIPIENT_DEVICE)
return dev.ctrl_transfer(
bmRequestType = bmRequestType,
bRequest = 0x06,
wValue = wValue,
wIndex = wIndex,
data_or_wLength = desc_size)
def set_descriptor(dev, desc, desc_type, desc_index, wIndex = None):
r"""Update an existing descriptor or add a new one.
dev is the Device object to which the request will be
sent to.
The desc parameter is the descriptor to be sent to the device.
desc_type and desc_index are the descriptor type and index,
respectively. wIndex index is used for string descriptors
and represents the Language ID. For other types of descriptors,
it is zero.
"""
wValue = desc_index | (desc_type << 8)
bmRequestType = util.build_request_type(
util.CTRL_OUT,
util.CTRL_TYPE_STANDARD,
util.CTRL_RECIPIENT_DEVICE)
dev.ctrl_transfer(
bmRequestType = bmRequestType,
bRequest = 0x07,
wValue = wValue,
wIndex = wIndex,
data_or_wLength = desc)
def get_configuration(dev):
r"""Get the current active configuration of the device.
dev is the Device object to which the request will be
sent to.
This function differs from the Device.get_active_configuration
method because the later may use cached data, while this
function always does a device request.
"""
bmRequestType = util.build_request_type(
util.CTRL_IN,
util.CTRL_TYPE_STANDARD,
util.CTRL_RECIPIENT_DEVICE)
return dev.ctrl_transfer(
bmRequestType,
bRequest = 0x08,
data_or_wLength = 1)[0]
def set_configuration(dev, bConfigurationNumber):
r"""Set the current device configuration.
dev is the Device object to which the request will be
sent to.
"""
dev.set_configuration(bConfigurationNumber)
def get_interface(dev, bInterfaceNumber):
r"""Get the current alternate setting of the interface.
dev is the Device object to which the request will be
sent to.
"""
bmRequestType = util.build_request_type(
util.CTRL_IN,
util.CTRL_TYPE_STANDARD,
util.CTRL_RECIPIENT_INTERFACE)
return dev.ctrl_transfer(
bmRequestType = bmRequestType,
bRequest = 0x0a,
wIndex = bInterfaceNumber,
data_or_wLength = 1)[0]
def set_interface(dev, bInterfaceNumber, bAlternateSetting):
r"""Set the alternate setting of the interface.
dev is the Device object to which the request will be
sent to.
"""
dev.set_interface_altsetting(bInterfaceNumber, bAlternateSetting)
pyusb-1.0.0/PKG-INFO 0000664 0001750 0001750 00000004246 12711232524 014540 0 ustar wander wander 0000000 0000000 Metadata-Version: 1.1
Name: pyusb
Version: 1.0.0
Summary: Python USB access module
Home-page: http://pyusb.sourceforge.net
Author: Wander Lairson Costa
Author-email: wander.lairson@gmail.com
License: BSD
Description:
PyUSB offers easy USB devices communication in Python.
It should work without additional code in any environment with
Python >= 2.4, ctypes and an pre-built usb backend library
(currently, libusb 0.1.x, libusb 1.x, and OpenUSB).
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: Manufacturing
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: System Administrators
Classifier: Intended Audience :: Telecommunications Industry
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows :: Windows Vista
Classifier: Operating System :: Microsoft :: Windows :: Windows 7
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
Classifier: Operating System :: POSIX :: BSD :: NetBSD
Classifier: Operating System :: POSIX :: BSD :: OpenBSD
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: POSIX :: SunOS/Solaris
Classifier: Programming Language :: Python :: 2.4
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: IronPython
Classifier: Programming Language :: Python :: Implementation :: Jython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Hardware :: Hardware Drivers