Shofel2_T124_python/venv/lib/python3.10/site-packages/usb/backend/libusb1.py

972 lines
35 KiB
Python
Raw Normal View History

2024-05-25 16:45:07 +00:00
# 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)
def _finalize_object(self):
_lib.libusb_unref_device(self.devid)
# wrap a descriptor and keep a reference to another object
# Thanks to Thomas Reitmayr.
class _WrapDescriptor(object):
def __init__(self, desc, obj = None):
self.obj = obj
self.desc = desc
def __getattr__(self, name):
return getattr(self.desc, name)
# wrap a configuration descriptor
class _ConfigDescriptor(_objfinalizer.AutoFinalizedObject):
def __init__(self, desc):
self.desc = desc
def _finalize_object(self):
_lib.libusb_free_config_descriptor(self.desc)
def __getattr__(self, name):
return getattr(self.desc.contents, name)
# iterator for libusb devices
class _DevIterator(_objfinalizer.AutoFinalizedObject):
def __init__(self, ctx):
self.dev_list = POINTER(c_void_p)()
self.num_devs = _check(_lib.libusb_get_device_list(
ctx,
byref(self.dev_list))
)
def __iter__(self):
for i in range(self.num_devs):
yield _Device(self.dev_list[i])
def _finalize_object(self):
_lib.libusb_free_device_list(self.dev_list, 1)
class _DeviceHandle(object):
def __init__(self, dev):
self.handle = _libusb_device_handle()
self.devid = dev.devid
_check(_lib.libusb_open(self.devid, byref(self.handle)))
class _IsoTransferHandler(_objfinalizer.AutoFinalizedObject):
def __init__(self, dev_handle, ep, buff, timeout):
address, length = buff.buffer_info()
packet_length = _lib.libusb_get_max_iso_packet_size(dev_handle.devid, ep)
packet_count = int(math.ceil(float(length) / packet_length))
self.transfer = _lib.libusb_alloc_transfer(packet_count)
_lib.libusb_fill_iso_transfer(self.transfer,
dev_handle.handle,
ep,
cast(address, POINTER(c_ubyte)),
length,
packet_count,
_libusb_transfer_cb_fn_p(self.__callback),
None,
timeout)
self.__set_packets_length(length, packet_length)
def _finalize_object(self):
_lib.libusb_free_transfer(self.transfer)
def submit(self, ctx = None):
self.__callback_done = 0
_check(_lib.libusb_submit_transfer(self.transfer))
while not self.__callback_done:
_check(_lib.libusb_handle_events(ctx))
status = int(self.transfer.contents.status)
if status != LIBUSB_TRANSFER_COMPLETED:
raise usb.USBError(_str_transfer_error[status],
status,
_transfer_errno[status])
return self.__compute_size_transf_data()
def __compute_size_transf_data(self):
return sum([t.actual_length for t in
_get_iso_packet_list(self.transfer.contents)])
def __set_packets_length(self, n, packet_length):
_lib.libusb_set_iso_packet_lengths(self.transfer, packet_length)
r = n % packet_length
if r:
iso_packets = _get_iso_packet_list(self.transfer.contents)
# When the device is disconnected, this list may
# return with length 0
if len(iso_packets):
iso_packets[-1].length = r
def __callback(self, transfer):
self.__callback_done = 1
# implementation of libusb 1.0 backend
class _LibUSB(usb.backend.IBackend):
@methodtrace(_logger)
def __init__(self, lib):
usb.backend.IBackend.__init__(self)
self.lib = lib
self.ctx = c_void_p()
_check(self.lib.libusb_init(byref(self.ctx)))
@methodtrace(_logger)
def _finalize_object(self):
if 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