moved a bunch of garbage (things that have nothing to do in root) to _trash

This commit is contained in:
mia 2025-06-15 22:42:02 +02:00
parent d094982b2c
commit 3226ed29ec
2610 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,110 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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/
try:
from usb._version import version as __version__
except ImportError:
__version__ = '0.0.0'
def _get_extended_version_info(version):
import re
m = re.match(r'(\d+)\.(\d+)(\.(\d+))?[.-]?(.*)', version)
major, minor, _, patch, suffix = m.groups()
return int(major), int(minor), int(patch or "0"), suffix
extended_version_info = _get_extended_version_info(__version__)
version_info = extended_version_info[:3]
__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 *

View file

@ -0,0 +1,79 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
__author__ = 'Wander Lairson Costa'
__all__ = ['methodtrace', 'functiontrace']
import functools
import logging
_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)
functools.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)
functools.update_wrapper(do_trace, f)
return do_trace
return decorator_logging

View file

@ -0,0 +1,69 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
# 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
import usb.util as util
__all__ = []
# we support Python >= 3.9
assert sys.hexversion >= 0x030900f0
def as_array(data_or_length=None):
"""Convert loosely specified `data_or_length` to a byte array.
The following types of `data_or_length` are supported:
- an `array('B')` value (no-op, returns it back);
- the `None` value (returns an new empty array);
- an integer length (returns a new array with the specified size);
- lists or iterables of small enough integers;
- strings.
"""
if isinstance(data_or_length, array.array) and data_or_length.typecode == 'B':
return data_or_length
if isinstance(data_or_length, str):
return array.array('B', data_or_length.encode('utf-8'))
if data_or_length is None:
return array.array('B')
try:
return util.create_buffer(data_or_length)
except TypeError:
return array.array('B', data_or_length)

View file

@ -0,0 +1,96 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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

View file

@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
#
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
__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()
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()

View file

@ -0,0 +1,16 @@
# file generated by setuptools_scm
# don't change, don't track in version control
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Tuple, Union
VERSION_TUPLE = Tuple[Union[int, str], ...]
else:
VERSION_TUPLE = object
version: str
__version__: str
__version_tuple__: VERSION_TUPLE
version_tuple: VERSION_TUPLE
__version__ = version = '1.3.1'
__version_tuple__ = version_tuple = (1, 3, 1)

View file

@ -0,0 +1,384 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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', 'libusb0', 'libusb1', '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_parent(self, dev):
"""Return the parent device of the given device."""
_not_implemented(self.get_parent)
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 respectively 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 milliseconds.
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 milliseconds.
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 milliseconds.
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 interrupt 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 milliseconds.
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 milliseconds.
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 milliseconds.
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 milliseconds.
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)

View file

@ -0,0 +1,748 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
from ctypes import *
import errno
import os
import usb.backend
import usb.util
import sys
from usb.core import USBError, USBTimeoutError
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')
_USBFS_MAXDRIVERNAME = 255
# 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_get_driver_np(usb_dev_handle *dev,
# int interface,
# char *name,
# unsigned int namelen);
if hasattr(lib, 'usb_get_driver_np'):
lib.usb_get_driver_np.argtypes = \
[_usb_dev_handle, c_int, c_char_p, c_uint]
# 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
if ret is not None and -ret == errno.ETIMEDOUT:
raise USBTimeoutError(errmsg, ret, -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 is_kernel_driver_active(self, dev_handle, intf):
if sys.platform == 'linux':
# based on the implementation of libusb_kernel_driver_active()
# (see op_kernel_driver_active() in libusb/os/linux_usbfs.c)
# and the fact that usb_get_driver_np() is a wrapper for
# IOCTL_USBFS_GETDRIVER
try:
driver_name = self.__get_driver_name(dev_handle, intf)
# 'usbfs' is not considered a [foreign] kernel driver because
# it is what we use to access the device from userspace
return driver_name != b'usbfs'
except USBError as err:
# ENODATA means that no kernel driver is attached
if err.backend_error_code == -errno.ENODATA:
return False
raise
elif sys.platform == 'darwin':
# on mac os/darwin we assume all users are running libusb-compat,
# which, in turn, uses libusb_kernel_driver_active()
try:
driver_name = self.__get_driver_name(dev_handle, intf)
return True
except USBError as err:
# ENODATA means that no kernel driver is attached
if err.backend_error_code == -errno.ENODATA:
return False
raise
elif sys.platform.startswith('freebsd') or sys.platform.startswith('dragonfly'):
# this is similar to the Linux implementation, but the generic
# driver is called 'ugen' and usb_get_driver_np() simply returns an
# empty string is no driver is attached (see comments on PR #366)
driver_name = self.__get_driver_name(dev_handle, intf)
# 'ugen' is not considered a [foreign] kernel driver because
# it is what we use to access the device from userspace
return driver_name != b'ugen'
else:
raise NotImplementedError(self.is_kernel_driver_active.__name__)
@methodtrace(_logger)
def detach_kernel_driver(self, dev_handle, intf):
if not hasattr(_lib, 'usb_detach_kernel_driver_np'):
raise NotImplementedError(self.detach_kernel_driver.__name__)
_check(_lib.usb_detach_kernel_driver_np(dev_handle, intf))
def __get_driver_name(self, dev_handle, intf):
if not hasattr(_lib, 'usb_get_driver_np'):
raise NotImplementedError('usb_get_driver_np')
buf = usb.util.create_buffer(_USBFS_MAXDRIVERNAME + 1)
name, length = buf.buffer_info()
length *= buf.itemsize
_check(_lib.usb_get_driver_np(
dev_handle,
intf,
cast(name, c_char_p),
length))
return cast(name, c_char_p).value
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.LibraryException:
# 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

View file

@ -0,0 +1,975 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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, USBTimeoutError
import usb.libloader
__author__ = 'Wander Lairson Costa'
__all__ = [
'get_backend',
'LIBUSB_SUCCESS',
'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
_lib_object = 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))
]
# libusb_device *libusb_get_parent (libusb_device *dev)
lib.libusb_get_parent.argtypes = [c_void_p]
lib.libusb_get_parent.restype = 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))
elif ret == LIBUSB_ERROR_TIMEOUT:
raise USBTimeoutError(_strerror(ret), ret, _libusb_errno[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)
@methodtrace(_logger)
def _finalize_object(self):
if hasattr(self, 'devid'):
_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):
if hasattr(self, 'desc'):
_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):
if hasattr(self, 'dev_list'):
_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):
if hasattr(self, 'transfer'):
_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):
if hasattr(self, 'ctx') and self.ctx:
self.lib.libusb_exit(self.ctx)
@methodtrace(_logger)
def enumerate_devices(self):
return _DevIterator(self.ctx)
@methodtrace(_logger)
def get_parent(self, dev):
_parent = self.lib.libusb_get_parent(dev.devid)
if _parent is None:
return None
else:
return _Device(_parent)
@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, _lib_object
try:
if _lib_object is None:
_lib = _load_library(find_library=find_library)
_setup_prototypes(_lib)
_lib_object = _LibUSB(_lib)
return _lib_object
except usb.libloader.LibraryException:
# 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

View file

@ -0,0 +1,759 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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, USBTimeoutError
__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_intr_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:
if ret == OPENUSB_IO_TIMEOUT:
raise USBTimeoutError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret])
else:
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):
if hasattr(self, 'handle'):
_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):
if hasattr(self, 'buslist'):
_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):
if hasattr(self, 'devlist'):
_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()
_logger.warning('OpenUSB backend deprecated (https://github.com/pyusb/pyusb/issues/284)')
return _OpenUSB()
except usb.libloader.LibraryException:
# 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

View file

@ -0,0 +1,262 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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
USBError = core.USBError
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)
desc = dev.ctrl_transfer(
bmRequestType = bmRequestType,
bRequest = 0x06,
wValue = wValue,
wIndex = wIndex,
data_or_wLength = desc_size)
if len(desc) < 2:
raise USBError('Invalid descriptor')
return desc
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)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,361 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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_WIRELESS_CONTROLLER = 224
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
PROTOCOL_BLUETOOTH_PRIMARY_CONTROLLER = 1
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
SUBCLASS_RF_CONTROLLER = 1
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):
if hasattr(self, 'dev') and self.dev:
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 milliseconds. (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 milliseconds. (default: 100)
Returns 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 milliseconds. (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 milliseconds. (default: 100)
Returns 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 milliseconds. (default: 100)
Returns 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 omitted, the first
language will be used.
"""
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 = dev.address
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.
Returns a DeviceHandle object
"""
return DeviceHandle(self.dev)
class Bus(object):
r"""Bus object."""
def __init__(self, devices):
self.dirname = ''
self.devices = [Device(d) for d in devices]
self.location = self.devices[0].dev.bus
def busses():
r"""Returns 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))

View file

@ -0,0 +1,208 @@
# -*- coding: utf-8 -*-
#
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
import ctypes
import ctypes.util
import logging
import os.path
import platform
import sys
__all__ = [
'LibraryException',
'LibraryNotFoundException',
'NoLibraryCandidatesException',
'LibraryNotLoadedException',
'LibraryMissingSymbolsException',
'locate_library',
'load_library',
'load_locate_library'
]
_LOGGER = logging.getLogger('usb.libloader')
class LibraryException(OSError):
pass
class LibraryNotFoundException(LibraryException):
pass
class NoLibraryCandidatesException(LibraryNotFoundException):
pass
class LibraryNotLoadedException(LibraryException):
pass
class LibraryMissingSymbolsException(LibraryException):
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
)
use_apple_silicon_workaround = (
sys.platform == 'darwin' and platform.machine() == 'arm64'
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
# On Apple Silicon, also check in `/opt/homebrew/lib`: homebrew patches
# the Python interpreters it distributes to check that directory, but
# other/stock interpreters don't know about it
if use_apple_silicon_workaround:
libname = "/opt/homebrew/lib/" + candidate + ".dylib"
if os.path.isfile(libname):
return libname
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).
* cygwin_cls -- library class for cygwin platforms.
Defaults to None (-> ctypes.CDLL).
* others_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:
_LOGGER.debug("%r found as %s", (name or candidates), 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

View file

@ -0,0 +1,321 @@
# Copyright 2009-2017 Wander Lairson Costa
# Copyright 2009-2021 PyUSB contributors
#
# 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. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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 COPYRIGHT
# HOLDER OR CONTRIBUTORS 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.
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
# 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
# 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 an array with `length` zeros or raise a `TypeError`.
return array.array('B', length * b"\x00")
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 all(tests) and (custom_match is None or custom_match(d)):
yield d
if find_all:
return desc_iter(**args)
else:
try:
return 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.
"""
if 0 == index:
return None
from usb.control import get_descriptor
if langid is None:
langids = dev.langids
if 0 == len(langids):
raise ValueError("The device has no langid"
" (permission issue, no string descriptors supported or device error)")
langid = langids[0]
buf = get_descriptor(
dev,
254, # maximum even length
DESC_TYPE_STRING,
index,
langid
)
blen = buf[0] & 0xfe # should be even, ignore any trailing byte (see #154)
return buf[2:blen].tobytes().decode('utf-16-le')