diff options
Diffstat (limited to 'plugins/wedo_plugin/usb/backend')
-rw-r--r-- | plugins/wedo_plugin/usb/backend/__init__.py | 2 | ||||
-rw-r--r-- | plugins/wedo_plugin/usb/backend/libusb0.py | 590 | ||||
-rw-r--r-- | plugins/wedo_plugin/usb/backend/libusb1.py | 901 | ||||
-rw-r--r-- | plugins/wedo_plugin/usb/backend/openusb.py | 66 |
4 files changed, 1532 insertions, 27 deletions
diff --git a/plugins/wedo_plugin/usb/backend/__init__.py b/plugins/wedo_plugin/usb/backend/__init__.py index 67ee00f..e08d7bc 100644 --- a/plugins/wedo_plugin/usb/backend/__init__.py +++ b/plugins/wedo_plugin/usb/backend/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2009-2011 Wander Lairson Costa +# Copyright (C) 2009-2013 Wander Lairson Costa # # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. diff --git a/plugins/wedo_plugin/usb/backend/libusb0.py b/plugins/wedo_plugin/usb/backend/libusb0.py new file mode 100644 index 0000000..8738335 --- /dev/null +++ b/plugins/wedo_plugin/usb/backend/libusb0.py @@ -0,0 +1,590 @@ +# Copyright (C) 2009-2013 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +from ctypes import * +import ctypes.util +import os +import usb.backend +import usb.util +import sys +from usb.core import USBError +from usb._debug import methodtrace +import usb._interop as _interop +import logging + +__author__ = 'Wander Lairson Costa' + +__all__ = ['get_backend'] + +_logger = logging.getLogger('usb.backend.libusb0') + +# usb.h + +_PC_PATH_MAX = 4 + +if sys.platform.find('bsd') != -1 or sys.platform.find('mac') != -1 or \ + sys.platform.find('darwin') != -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 +_lib = None + +def _load_library(): + if sys.platform != 'cygwin': + candidates = ('usb-0.1', 'usb', 'libusb0') + for candidate in candidates: + # Workaround for CPython 3.3 issue#16283 / pyusb #14 + if sys.platform == 'win32': + candidate = candidate + '.dll' + + libname = ctypes.util.find_library(candidate) + if libname is not None: break + else: + # corner cases + # cygwin predefines library names with 'cyg' instead of 'lib' + try: + return CDLL('cygusb0.dll') + except: + _logger.error('Libusb 0 could not be loaded in cygwin', exc_info=True) + + raise OSError('USB library could not be found') + return CDLL(libname) + +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) + +def _check(retval): + if retval is None: + errmsg = _lib.usb_strerror() + else: + ret = int(retval) + if ret < 0: + errmsg = _lib.usb_strerror() + # No error means that we need to get the error + # message from the return code + # Thanks to Nicholas Wheeler to point out the problem... + # Also see issue #2860940 + if errmsg.lower() == 'no error': + errmsg = os.strerror(-ret) + else: + return ret + raise USBError(errmsg, ret) + +# 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)) + return dev.config[config] + + @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(interface)) + interface = cfgdesc.interface[intf] + if alt >= interface.num_altsetting: + raise IndexError('Invalid alternate setting index ' + str(alt)) + return interface.altsetting[alt] + + @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)) + return interface.endpoint[ep] + + @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 set_interface_altsetting(self, dev_handle, intf, altsetting): + _check(_lib.usb_set_altinterface(dev_handle, altsetting)) + + @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 + ) + return self.ctrl_transfer(dev_handle, + bmRequestType, + 0x08, + 0, + 0, + 1, + 100 + )[0] + + + @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, size, timeout): + return self.__read(_lib.usb_bulk_read, + dev_handle, + ep, + intf, + size, + 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, size, timeout): + return self.__read(_lib.usb_interrupt_read, + dev_handle, + ep, + intf, + size, + timeout) + + @methodtrace(_logger) + def ctrl_transfer(self, + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + data_or_wLength, + timeout): + if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: + address, length = data_or_wLength.buffer_info() + length *= data_or_wLength.itemsize + return _check(_lib.usb_control_msg( + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + cast(address, c_char_p), + length, + timeout + )) + else: + data = _interop.as_array((0,) * data_or_wLength) + read = int(_check(_lib.usb_control_msg( + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + cast(data.buffer_info()[0], + c_char_p), + data_or_wLength, + timeout + ))) + return data[:read] + + @methodtrace(_logger) + def reset_device(self, dev_handle): + _check(_lib.usb_reset(dev_handle)) + + @methodtrace(_logger) + def detach_kernel_driver(self, dev_handle, intf): + _check(_lib.usb_detach_kernel_driver_np(dev_handle, intf)) + + def __write(self, fn, dev_handle, ep, intf, data, timeout): + address, length = data.buffer_info() + length *= data.itemsize + return int(_check(fn( + dev_handle, + ep, + cast(address, c_char_p), + length, + timeout + ))) + + def __read(self, fn, dev_handle, ep, intf, size, timeout): + data = _interop.as_array('\x00' * size) + address, length = data.buffer_info() + length *= data.itemsize + ret = int(_check(fn( + dev_handle, + ep, + cast(address, c_char_p), + length, + timeout + ))) + return data[:ret] + +def get_backend(): + global _lib + try: + if _lib is None: + _lib = _load_library() + _setup_prototypes(_lib) + _lib.usb_init() + return _LibUSB() + except Exception: + _logger.error('Error loading libusb 0.1 backend', exc_info=True) + return None diff --git a/plugins/wedo_plugin/usb/backend/libusb1.py b/plugins/wedo_plugin/usb/backend/libusb1.py new file mode 100644 index 0000000..5396092 --- /dev/null +++ b/plugins/wedo_plugin/usb/backend/libusb1.py @@ -0,0 +1,901 @@ +# Copyright (C) 2009-2013 Wander Lairson Costa +# +# The following terms apply to all files associated +# with the software unless explicitly disclaimed in individual files. +# +# The authors hereby grant permission to use, copy, modify, distribute, +# and license this software and its documentation for any purpose, provided +# that existing copyright notices are retained in all copies and that this +# notice is included verbatim in any distributions. No written agreement, +# license, or royalty fee is required for any of the authorized uses. +# Modifications to this software may be copyrighted by their authors +# and need not follow the licensing terms described here, provided that +# the new terms are clearly indicated on the first page of each file where +# they apply. +# +# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +# MODIFICATIONS. + +from ctypes import * +import ctypes.util +import usb.util +import sys +import logging +from usb._debug import methodtrace +import usb._interop as _interop +import errno +import math +from usb.core import USBError + +__author__ = 'Wander Lairson Costa' + +__all__ = [ + 'get_backend', + 'LIBUSB_SUCESS', + 'LIBUSB_ERROR_IO', + 'LIBUSB_ERROR_INVALID_PARAM', + 'LIBUSB_ERROR_ACCESS', + 'LIBUSB_ERROR_NO_DEVICE', + 'LIBUSB_ERROR_NOT_FOUND', + 'LIBUSB_ERROR_BUSY', + 'LIBUSB_ERROR_TIMEOUT', + 'LIBUSB_ERROR_OVERFLOW', + 'LIBUSB_ERROR_PIPE', + 'LIBUSB_ERROR_INTERRUPTED', + 'LIBUSB_ERROR_NO_MEM', + 'LIBUSB_ERROR_NOT_SUPPORTED', + 'LIBUSB_ERROR_OTHER' + 'LIBUSB_TRANSFER_COMPLETED', + 'LIBUSB_TRANSFER_ERROR', + 'LIBUSB_TRANSFER_TIMED_OUT', + 'LIBUSB_TRANSFER_CANCELLED', + 'LIBUSB_TRANSFER_STALL', + 'LIBUSB_TRANSFER_NO_DEVICE', + 'LIBUSB_TRANSFER_OVERFLOW' + ] + +_logger = logging.getLogger('usb.backend.libusb1') + +# libusb.h + +# transfer_type codes +# Control endpoint +_LIBUSB_TRANSFER_TYPE_CONTROL = 0, +# Isochronous endpoint +_LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1 +# Bulk endpoint +_LIBUSB_TRANSFER_TYPE_BULK = 2 +# Interrupt endpoint +_LIBUSB_TRANSFER_TYPE_INTERRUPT = 3 + +# return codes + +LIBUSB_SUCCESS = 0 +LIBUSB_ERROR_IO = -1 +LIBUSB_ERROR_INVALID_PARAM = -2 +LIBUSB_ERROR_ACCESS = -3 +LIBUSB_ERROR_NO_DEVICE = -4 +LIBUSB_ERROR_NOT_FOUND = -5 +LIBUSB_ERROR_BUSY = -6 +LIBUSB_ERROR_TIMEOUT = -7 +LIBUSB_ERROR_OVERFLOW = -8 +LIBUSB_ERROR_PIPE = -9 +LIBUSB_ERROR_INTERRUPTED = -10 +LIBUSB_ERROR_NO_MEM = -11 +LIBUSB_ERROR_NOT_SUPPORTED = -12 +LIBUSB_ERROR_OTHER = -99 + +# map return codes to strings +_str_error = { + 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) +} + +# Data structures + +class _libusb_endpoint_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bEndpointAddress', c_uint8), + ('bmAttributes', c_uint8), + ('wMaxPacketSize', c_uint16), + ('bInterval', c_uint8), + ('bRefresh', c_uint8), + ('bSynchAddress', c_uint8), + ('extra', POINTER(c_ubyte)), + ('extra_length', c_int)] + +class _libusb_interface_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bInterfaceNumber', c_uint8), + ('bAlternateSetting', c_uint8), + ('bNumEndpoints', c_uint8), + ('bInterfaceClass', c_uint8), + ('bInterfaceSubClass', c_uint8), + ('bInterfaceProtocol', c_uint8), + ('iInterface', c_uint8), + ('endpoint', POINTER(_libusb_endpoint_descriptor)), + ('extra', POINTER(c_ubyte)), + ('extra_length', c_int)] + +class _libusb_interface(Structure): + _fields_ = [('altsetting', POINTER(_libusb_interface_descriptor)), + ('num_altsetting', c_int)] + +class _libusb_config_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('wTotalLength', c_uint16), + ('bNumInterfaces', c_uint8), + ('bConfigurationValue', c_uint8), + ('iConfiguration', c_uint8), + ('bmAttributes', c_uint8), + ('bMaxPower', c_uint8), + ('interface', POINTER(_libusb_interface)), + ('extra', POINTER(c_ubyte)), + ('extra_length', c_int)] + +class _libusb_device_descriptor(Structure): + _fields_ = [('bLength', c_uint8), + ('bDescriptorType', c_uint8), + ('bcdUSB', c_uint16), + ('bDeviceClass', c_uint8), + ('bDeviceSubClass', c_uint8), + ('bDeviceProtocol', c_uint8), + ('bMaxPacketSize0', c_uint8), + ('idVendor', c_uint16), + ('idProduct', c_uint16), + ('bcdDevice', c_uint16), + ('iManufacturer', c_uint8), + ('iProduct', c_uint8), + ('iSerialNumber', c_uint8), + ('bNumConfigurations', c_uint8)] + + +# Isochronous packet descriptor. +class _libusb_iso_packet_descriptor(Structure): + _fields_ = [('length', c_uint), + ('actual_length', c_uint), + ('status', c_int)] # enum libusb_transfer_status + +_libusb_device_handle = c_void_p + +class _libusb_transfer(Structure): + pass +_libusb_transfer_p = POINTER(_libusb_transfer) + +_libusb_transfer_cb_fn_p = CFUNCTYPE(None, _libusb_transfer_p) + +_libusb_transfer._fields_ = [('dev_handle', _libusb_device_handle), + ('flags', c_uint8), + ('endpoint', c_uint8), + ('type', c_uint8), + ('timeout', c_uint), + ('status', c_int), # enum libusb_transfer_status + ('length', c_int), + ('actual_length', c_int), + ('callback', _libusb_transfer_cb_fn_p), + ('user_data', py_object), + ('buffer', c_void_p), + ('num_iso_packets', c_int), + ('iso_packet_desc', _libusb_iso_packet_descriptor) +] + +def _get_iso_packet_list(transfer): + list_type = _libusb_iso_packet_descriptor * transfer.num_iso_packets + return list_type.from_address(addressof(transfer.iso_packet_desc)) + +_lib = None + +def _load_library(): + if sys.platform != 'cygwin': + candidates = ('usb-1.0', 'libusb-1.0', 'usb') + for candidate in candidates: + if sys.platform == 'win32': + candidate = candidate + '.dll' + + libname = ctypes.util.find_library(candidate) + if libname is not None: break + else: + # corner cases + # cygwin predefines library names with 'cyg' instead of 'lib' + try: + return CDLL('cygusb-1.0.dll') + except Exception: + _logger.error('Libusb 1.0 could not be loaded in cygwin', exc_info=True) + + raise OSError('USB library could not be found') + # Windows backend uses stdcall calling convention + if sys.platform == 'win32': + l = WinDLL(libname) + else: + l = CDLL(libname) + # 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 not hasattr(l, 'libusb_init'): + raise OSError('USB library could not be found') + return l + +def _setup_prototypes(lib): + # void libusb_set_debug (libusb_context *ctx, int level) + lib.libusb_set_debug.argtypes = [c_void_p, c_int] + + # int libusb_init (libusb_context **context) + lib.libusb_init.argtypes = [POINTER(c_void_p)] + + # void libusb_exit (struct libusb_context *ctx) + lib.libusb_exit.argtypes = [c_void_p] + + # ssize_t libusb_get_device_list (libusb_context *ctx, + # libusb_device ***list) + lib.libusb_get_device_list.argtypes = [ + c_void_p, + POINTER(POINTER(c_void_p)) + ] + + # void libusb_free_device_list (libusb_device **list, + # int unref_devices) + lib.libusb_free_device_list.argtypes = [ + POINTER(c_void_p), + c_int + ] + + # libusb_device *libusb_ref_device (libusb_device *dev) + lib.libusb_ref_device.argtypes = [c_void_p] + lib.libusb_ref_device.restype = c_void_p + + # void libusb_unref_device(libusb_device *dev) + lib.libusb_unref_device.argtypes = [c_void_p] + + # int libusb_open(libusb_device *dev, libusb_device_handle **handle) + lib.libusb_open.argtypes = [c_void_p, POINTER(_libusb_device_handle)] + + # void libusb_close(libusb_device_handle *dev_handle) + lib.libusb_close.argtypes = [_libusb_device_handle] + + # int libusb_set_configuration(libusb_device_handle *dev, + # int configuration) + lib.libusb_set_configuration.argtypes = [_libusb_device_handle, c_int] + + # int libusb_get_configuration(libusb_device_handle *dev, + # int *config) + lib.libusb_get_configuration.argtypes = [_libusb_device_handle, POINTER(c_int)] + + # int libusb_claim_interface(libusb_device_handle *dev, + # int interface_number) + lib.libusb_claim_interface.argtypes = [_libusb_device_handle, c_int] + + # int libusb_release_interface(libusb_device_handle *dev, + # int interface_number) + lib.libusb_release_interface.argtypes = [_libusb_device_handle, c_int] + + # int libusb_set_interface_alt_setting(libusb_device_handle *dev, + # int interface_number, + # int alternate_setting) + lib.libusb_set_interface_alt_setting.argtypes = [ + _libusb_device_handle, + c_int, + c_int + ] + + # int libusb_reset_device (libusb_device_handle *dev) + lib.libusb_reset_device.argtypes = [_libusb_device_handle] + + # int libusb_kernel_driver_active(libusb_device_handle *dev, + # int interface) + lib.libusb_kernel_driver_active.argtypes = [ + _libusb_device_handle, + c_int + ] + + # int libusb_detach_kernel_driver(libusb_device_handle *dev, + # int interface) + lib.libusb_detach_kernel_driver.argtypes = [ + _libusb_device_handle, + c_int + ] + + # int libusb_attach_kernel_driver(libusb_device_handle *dev, + # int interface) + lib.libusb_attach_kernel_driver.argtypes = [ + _libusb_device_handle, + c_int + ] + + # int libusb_get_device_descriptor( + # libusb_device *dev, + # struct libusb_device_descriptor *desc + # ) + lib.libusb_get_device_descriptor.argtypes = [ + c_void_p, + POINTER(_libusb_device_descriptor) + ] + + # int libusb_get_config_descriptor( + # libusb_device *dev, + # uint8_t config_index, + # struct libusb_config_descriptor **config + # ) + lib.libusb_get_config_descriptor.argtypes = [ + c_void_p, + c_uint8, + POINTER(POINTER(_libusb_config_descriptor)) + ] + + # void libusb_free_config_descriptor( + # struct libusb_config_descriptor *config + # ) + lib.libusb_free_config_descriptor.argtypes = [ + POINTER(_libusb_config_descriptor) + ] + + # int libusb_get_string_descriptor_ascii(libusb_device_handle *dev, + # uint8_t desc_index, + # unsigned char *data, + # int length) + lib.libusb_get_string_descriptor_ascii.argtypes = [ + _libusb_device_handle, + c_uint8, + POINTER(c_ubyte), + c_int + ] + + # int libusb_control_transfer(libusb_device_handle *dev_handle, + # uint8_t bmRequestType, + # uint8_t bRequest, + # uint16_t wValue, + # uint16_t wIndex, + # unsigned char *data, + # uint16_t wLength, + # unsigned int timeout) + lib.libusb_control_transfer.argtypes = [ + _libusb_device_handle, + c_uint8, + c_uint8, + c_uint16, + c_uint16, + POINTER(c_ubyte), + c_uint16, + c_uint + ] + + #int libusb_bulk_transfer( + # struct libusb_device_handle *dev_handle, + # unsigned char endpoint, + # unsigned char *data, + # int length, + # int *transferred, + # unsigned int timeout + # ) + lib.libusb_bulk_transfer.argtypes = [ + _libusb_device_handle, + c_ubyte, + POINTER(c_ubyte), + c_int, + POINTER(c_int), + c_uint + ] + + # int libusb_interrupt_transfer( + # libusb_device_handle *dev_handle, + # unsigned char endpoint, + # unsigned char *data, + # int length, + # int *actual_length, + # unsigned int timeout + # ); + lib.libusb_interrupt_transfer.argtypes = [ + _libusb_device_handle, + c_ubyte, + POINTER(c_ubyte), + c_int, + POINTER(c_int), + c_uint + ] + + # libusb_transfer* libusb_alloc_transfer(int iso_packets); + lib.libusb_alloc_transfer.argtypes = [c_int] + lib.libusb_alloc_transfer.restype = POINTER(_libusb_transfer) + + # void libusb_free_transfer(struct libusb_transfer *transfer) + lib.libusb_free_transfer.argtypes = [POINTER(_libusb_transfer)] + + # int libusb_submit_transfer(struct libusb_transfer *transfer); + lib.libusb_submit_transfer.argtypes = [POINTER(_libusb_transfer)] + + # 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_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 + + #int libusb_handle_events(libusb_context *ctx); + lib.libusb_handle_events.argtypes = [c_void_p] + +# check a libusb function call +def _check(retval): + if isinstance(retval, int): + retval = c_int(retval) + if isinstance(retval, c_int): + if retval.value < 0: + ret = retval.value + raise USBError(_str_error[ret], ret, _libusb_errno[ret]) + return retval + +# wrap a device +class _Device(object): + def __init__(self, devid): + self.devid = _lib.libusb_ref_device(devid) + def __del__(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(object): + def __init__(self, desc): + self.desc = desc + def __del__(self): + _lib.libusb_free_config_descriptor(self.desc) + def __getattr__(self, name): + return getattr(self.desc.contents, name) + + +# iterator for libusb devices +class _DevIterator(object): + 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)) + ).value + def __iter__(self): + for i in range(self.num_devs): + yield _Device(self.dev_list[i]) + def __del__(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(object): + 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 __del__(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)) + + 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) + iso_packets[-1].length = r + + def __callback(self, transfer): + if transfer.contents.status == LIBUSB_TRANSFER_COMPLETED: + self.__callback_done = 1 + else: + status = int(transfer.contents.status) + raise usb.USBError(_str_transfer_error[status], + status, + _transfer_errno[status]) + +# 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 __del__(self): + self.lib.libusb_exit(self.ctx) + + + @methodtrace(_logger) + def enumerate_devices(self): + return _DevIterator(self.ctx) + + @methodtrace(_logger) + def get_device_descriptor(self, dev): + dev_desc = _libusb_device_descriptor() + _check(self.lib.libusb_get_device_descriptor(dev.devid, byref(dev_desc))) + dev_desc.bus = self.lib.libusb_get_bus_number(dev.devid) + dev_desc.address = self.lib.libusb_get_device_address(dev.devid) + + #Only available i newer versions of libusb + try: + dev_desc.port_number = self.lib.libusb_get_port_number(dev.devid) + except AttributeError: + dev_desc.port_number = 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))) + return _ConfigDescriptor(cfg) + + @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)) + return _WrapDescriptor(i.altsetting[alt], 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)) + return _WrapDescriptor(i.endpoint[ep], 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, size, timeout): + return self.__read(self.lib.libusb_bulk_transfer, + dev_handle, + ep, + intf, + size, + 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, size, timeout): + return self.__read(self.lib.libusb_interrupt_transfer, + dev_handle, + ep, + intf, + size, + 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, size, timeout): + data = _interop.as_array('\x00' * size) + handler = _IsoTransferHandler(dev_handle, ep, data, timeout) + return data[:handler.submit(self.ctx)] + + @methodtrace(_logger) + def ctrl_transfer(self, + dev_handle, + bmRequestType, + bRequest, + wValue, + wIndex, + data_or_wLength, + timeout): + if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: + buff = data_or_wLength + else: + buff = _interop.as_array((0,) * data_or_wLength) + + addr, length = buff.buffer_info() + length *= buff.itemsize + + ret = _check(self.lib.libusb_control_transfer( + dev_handle.handle, + bmRequestType, + bRequest, + wValue, + wIndex, + cast(addr, POINTER(c_ubyte)), + length, + timeout)) + + if usb.util.ctrl_direction(bmRequestType) == usb.util.CTRL_OUT: + return ret.value + else: + return buff[:ret.value] + + @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, size, timeout): + data = _interop.as_array('\x00' * size) + 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 data[:transferred.value] + +def get_backend(): + global _lib + try: + if _lib is None: + _lib = _load_library() + _setup_prototypes(_lib) + return _LibUSB(_lib) + except Exception: + _logger.error('Error loading libusb 1.0 backend', exc_info=True) + return None diff --git a/plugins/wedo_plugin/usb/backend/openusb.py b/plugins/wedo_plugin/usb/backend/openusb.py index 23e4d45..3398c4a 100644 --- a/plugins/wedo_plugin/usb/backend/openusb.py +++ b/plugins/wedo_plugin/usb/backend/openusb.py @@ -1,8 +1,8 @@ -# Copyright (C) 2009-2011 Wander Lairson Costa -# +# Copyright (C) 2009-2013 Wander Lairson Costa +# # The following terms apply to all files associated # with the software unless explicitly disclaimed in individual files. -# +# # The authors hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, provided # that existing copyright notices are retained in all copies and that this @@ -12,13 +12,13 @@ # and need not follow the licensing terms described here, provided that # the new terms are clearly indicated on the first page of each file where # they apply. -# +# # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -# +# # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE @@ -32,6 +32,8 @@ import usb.util from usb._debug import methodtrace import logging import errno +import sys +import usb._interop as _interop __author__ = 'Wander Lairson Costa' @@ -187,7 +189,7 @@ class _usb_device_desc(Structure): class _openusb_request_result(Structure): _fields_ = [('status', c_int32), - ('transfered_bytes', c_uint32)] + ('transferred_bytes', c_uint32)] class _openusb_ctrl_request(Structure): class _openusb_ctrl_setup(Structure): @@ -195,7 +197,8 @@ class _openusb_ctrl_request(Structure): ('bRequest', c_uint8), ('wValue', c_uint16), ('wIndex', c_uint16)] - _fields_ = [('payload', POINTER(c_uint8)), + _fields_ = [('setup', _openusb_ctrl_setup), + ('payload', POINTER(c_uint8)), ('length', c_uint32), ('timeout', c_uint32), ('flags', c_uint32), @@ -243,7 +246,12 @@ _lib = None _ctx = None def _load_library(): - libname = ctypes.util.find_library('openusb') + candidate = 'openusb' + # Workaround for CPython 3.3 issue#16283 / pyusb #14 + if sys.platform == 'win32': + candidate = candidate + '.dll' + + libname = ctypes.util.find_library(candidate) if libname is None: raise OSError('USB library could not be found') return CDLL(libname) @@ -396,7 +404,7 @@ def _setup_prototypes(lib): ] 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, @@ -477,7 +485,10 @@ def _setup_prototypes(lib): lib.openusb_isoc_xfer.restype = c_int32 def _check(retval): - ret = retval.value + if isinstance(retval, c_int): + ret = retval.value + else: + ret = retval if ret != 0: from usb.core import USBError raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret]) @@ -492,7 +503,7 @@ class _Context(object): class _BusIterator(object): def __init__(self): - self.buslist = POINTER(openusb_busid)() + self.buslist = POINTER(_openusb_busid)() num_busids = c_uint32() _check(_lib.openusb_get_busid_list(_ctx.handle, byref(self.buslist), @@ -536,6 +547,7 @@ class _OpenUSB(usb.backend.IBackend): byref(desc))) desc.bus = None desc.address = None + desc.port_number = None return desc @methodtrace(_logger) @@ -598,7 +610,7 @@ class _OpenUSB(usb.backend.IBackend): @methodtrace(_logger) def set_interface_altsetting(self, dev_handle, intf, altsetting): - _check(_lib.set_altsetting(dev_handle, intf, altsetting)) + _check(_lib.openusb_set_altsetting(dev_handle, intf, altsetting)) @methodtrace(_logger) def claim_interface(self, dev_handle, intf): @@ -612,20 +624,22 @@ class _OpenUSB(usb.backend.IBackend): def bulk_write(self, dev_handle, ep, intf, data, timeout): request = _openusb_bulk_request() memset(byref(request), 0, sizeof(request)) - request.payload, request.length = data.buffer_info() + 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.transfered_bytes.value + return request.result.transferred_bytes @methodtrace(_logger) def bulk_read(self, dev_handle, ep, intf, size, timeout): request = _openusb_bulk_request() - buffer = array.array('B', '\x00' * size) + buffer = _interop.as_array('\x00' * size) memset(byref(request), 0, sizeof(request)) - request.payload, request.length = buffer.buffer_info() + payload, request.length = buffer.buffer_info() + request.payload = cast(payload, POINTER(c_uint8)) request.timeout = timeout _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request))) - return buffer[:request.transfered_bytes.value] + return buffer[:request.result.transferred_bytes] @methodtrace(_logger) def intr_write(self, dev_handle, ep, intf, data, timeout): @@ -635,18 +649,18 @@ class _OpenUSB(usb.backend.IBackend): request.payload = cast(payload, POINTER(c_uint8)) request.timeout = timeout _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request))) - return request.transfered_bytes.value + return request.result.transferred_bytes @methodtrace(_logger) def intr_read(self, dev_handle, ep, intf, size, timeout): request = _openusb_intr_request() - buffer = array.array('B', '\x00' * size) + buffer = _interop.as_array('B', '\x00' * size) memset(byref(request), 0, sizeof(request)) payload, request.length = buffer.buffer_info() request.payload = cast(payload, POINTER(c_uint8)) request.timeout = timeout _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request))) - return buffer[:request.transfered_bytes.value] + return buffer[:request.result.transferred_bytes] # TODO: implement isochronous # @methodtrace(_logger) @@ -675,20 +689,20 @@ class _OpenUSB(usb.backend.IBackend): direction = usb.util.ctrl_direction(bmRequestType) - if direction == ENDPOINT_OUT: + if direction == usb.util.CTRL_OUT: buffer = data_or_wLength else: - buffer = array.array('B', '\x00' * data_or_wLength) + buffer = _interop.as_array('\x00' * data_or_wLength) payload, request.length = buffer.buffer_info() request.payload = cast(payload, POINTER(c_uint8)) - ret = _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request))) + _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request))) - if direction == ENDPOINT_OUT: - ret + if direction == usb.util.CTRL_OUT: + return request.result.transferred_bytes else: - buffer[:ret] + return buffer[:request.result.transferred_bytes] @methodtrace(_logger) def reset_device(self, dev_handle): |