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