1# Copyright (C) 2009-2014 Wander Lairson Costa
2#
3# The following terms apply to all files associated
4# with the software unless explicitly disclaimed in individual files.
5#
6# The authors hereby grant permission to use, copy, modify, distribute,
7# and license this software and its documentation for any purpose, provided
8# that existing copyright notices are retained in all copies and that this
9# notice is included verbatim in any distributions. No written agreement,
10# license, or royalty fee is required for any of the authorized uses.
11# Modifications to this software may be copyrighted by their authors
12# and need not follow the licensing terms described here, provided that
13# the new terms are clearly indicated on the first page of each file where
14# they apply.
15#
16# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
17# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
18# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
19# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
20# POSSIBILITY OF SUCH DAMAGE.
21#
22# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
23# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
24# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
25# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
26# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
27# MODIFICATIONS.
28
29from ctypes import *
30import ctypes.util
31import usb.util
32from usb._debug import methodtrace
33import logging
34import errno
35import sys
36import usb._interop as _interop
37import usb._objfinalizer as _objfinalizer
38import usb.util as util
39import usb.libloader
40from usb.core import USBError
41
42__author__ = 'Wander Lairson Costa'
43
44__all__ = [
45            'get_backend'
46            'OPENUSB_SUCCESS'
47            'OPENUSB_PLATFORM_FAILURE'
48            'OPENUSB_NO_RESOURCES'
49            'OPENUSB_NO_BANDWIDTH'
50            'OPENUSB_NOT_SUPPORTED'
51            'OPENUSB_HC_HARDWARE_ERROR'
52            'OPENUSB_INVALID_PERM'
53            'OPENUSB_BUSY'
54            'OPENUSB_BADARG'
55            'OPENUSB_NOACCESS'
56            'OPENUSB_PARSE_ERROR'
57            'OPENUSB_UNKNOWN_DEVICE'
58            'OPENUSB_INVALID_HANDLE'
59            'OPENUSB_SYS_FUNC_FAILURE'
60            'OPENUSB_NULL_LIST'
61            'OPENUSB_CB_CONTINUE'
62            'OPENUSB_CB_TERMINATE'
63            'OPENUSB_IO_STALL'
64            'OPENUSB_IO_CRC_ERROR'
65            'OPENUSB_IO_DEVICE_HUNG'
66            'OPENUSB_IO_REQ_TOO_BIG'
67            'OPENUSB_IO_BIT_STUFFING'
68            'OPENUSB_IO_UNEXPECTED_PID'
69            'OPENUSB_IO_DATA_OVERRUN'
70            'OPENUSB_IO_DATA_UNDERRUN'
71            'OPENUSB_IO_BUFFER_OVERRUN'
72            'OPENUSB_IO_BUFFER_UNDERRUN'
73            'OPENUSB_IO_PID_CHECK_FAILURE'
74            'OPENUSB_IO_DATA_TOGGLE_MISMATCH'
75            'OPENUSB_IO_TIMEOUT'
76            'OPENUSB_IO_CANCELED'
77        ]
78
79_logger = logging.getLogger('usb.backend.openusb')
80
81OPENUSB_SUCCESS = 0
82OPENUSB_PLATFORM_FAILURE = -1
83OPENUSB_NO_RESOURCES = -2
84OPENUSB_NO_BANDWIDTH = -3
85OPENUSB_NOT_SUPPORTED = -4
86OPENUSB_HC_HARDWARE_ERROR = -5
87OPENUSB_INVALID_PERM = -6
88OPENUSB_BUSY = -7
89OPENUSB_BADARG = -8
90OPENUSB_NOACCESS = -9
91OPENUSB_PARSE_ERROR = -10
92OPENUSB_UNKNOWN_DEVICE = -11
93OPENUSB_INVALID_HANDLE = -12
94OPENUSB_SYS_FUNC_FAILURE = -13
95OPENUSB_NULL_LIST = -14
96OPENUSB_CB_CONTINUE = -20
97OPENUSB_CB_TERMINATE = -21
98OPENUSB_IO_STALL = -50
99OPENUSB_IO_CRC_ERROR = -51
100OPENUSB_IO_DEVICE_HUNG = -52
101OPENUSB_IO_REQ_TOO_BIG = -53
102OPENUSB_IO_BIT_STUFFING = -54
103OPENUSB_IO_UNEXPECTED_PID = -55
104OPENUSB_IO_DATA_OVERRUN = -56
105OPENUSB_IO_DATA_UNDERRUN = -57
106OPENUSB_IO_BUFFER_OVERRUN = -58
107OPENUSB_IO_BUFFER_UNDERRUN = -59
108OPENUSB_IO_PID_CHECK_FAILURE = -60
109OPENUSB_IO_DATA_TOGGLE_MISMATCH = -61
110OPENUSB_IO_TIMEOUT = -62
111OPENUSB_IO_CANCELED = -63
112
113_openusb_errno = {
114    OPENUSB_SUCCESS:None,
115    OPENUSB_PLATFORM_FAILURE:None,
116    OPENUSB_NO_RESOURCES:errno.__dict__.get('ENOMEM', None),
117    OPENUSB_NO_BANDWIDTH:None,
118    OPENUSB_NOT_SUPPORTED:errno.__dict__.get('ENOSYS', None),
119    OPENUSB_HC_HARDWARE_ERROR:errno.__dict__.get('EIO', None),
120    OPENUSB_INVALID_PERM:errno.__dict__.get('EBADF', None),
121    OPENUSB_BUSY:errno.__dict__.get('EBUSY', None),
122    OPENUSB_BADARG:errno.__dict__.get('EINVAL', None),
123    OPENUSB_NOACCESS:errno.__dict__.get('EACCES', None),
124    OPENUSB_PARSE_ERROR:None,
125    OPENUSB_UNKNOWN_DEVICE:errno.__dict__.get('ENODEV', None),
126    OPENUSB_INVALID_HANDLE:errno.__dict__.get('EINVAL', None),
127    OPENUSB_SYS_FUNC_FAILURE:None,
128    OPENUSB_NULL_LIST:None,
129    OPENUSB_CB_CONTINUE:None,
130    OPENUSB_CB_TERMINATE:None,
131    OPENUSB_IO_STALL:errno.__dict__.get('EIO', None),
132    OPENUSB_IO_CRC_ERROR:errno.__dict__.get('EIO', None),
133    OPENUSB_IO_DEVICE_HUNG:errno.__dict__.get('EIO', None),
134    OPENUSB_IO_REQ_TOO_BIG:errno.__dict__.get('E2BIG', None),
135    OPENUSB_IO_BIT_STUFFING:None,
136    OPENUSB_IO_UNEXPECTED_PID:errno.__dict__.get('ESRCH', None),
137    OPENUSB_IO_DATA_OVERRUN:errno.__dict__.get('EOVERFLOW', None),
138    OPENUSB_IO_DATA_UNDERRUN:None,
139    OPENUSB_IO_BUFFER_OVERRUN:errno.__dict__.get('EOVERFLOW', None),
140    OPENUSB_IO_BUFFER_UNDERRUN:None,
141    OPENUSB_IO_PID_CHECK_FAILURE:None,
142    OPENUSB_IO_DATA_TOGGLE_MISMATCH:None,
143    OPENUSB_IO_TIMEOUT:errno.__dict__.get('ETIMEDOUT', None),
144    OPENUSB_IO_CANCELED:errno.__dict__.get('EINTR', None)
145}
146
147class _usb_endpoint_desc(Structure):
148    _fields_ = [('bLength', c_uint8),
149                ('bDescriptorType', c_uint8),
150                ('bEndpointAddress', c_uint8),
151                ('bmAttributes', c_uint8),
152                ('wMaxPacketSize', c_uint16),
153                ('bInterval', c_uint8),
154                ('bRefresh', c_uint8),
155                ('bSynchAddress', c_uint8)]
156
157class _usb_interface_desc(Structure):
158    _fields_ = [('bLength', c_uint8),
159                ('bDescriptorType', c_uint8),
160                ('bInterfaceNumber', c_uint8),
161                ('bAlternateSetting', c_uint8),
162                ('bNumEndpoints', c_uint8),
163                ('bInterfaceClass', c_uint8),
164                ('bInterfaceSubClass', c_uint8),
165                ('bInterfaceProtocol', c_uint8),
166                ('iInterface', c_uint8)]
167
168class _usb_config_desc(Structure):
169    _fields_ = [('bLength', c_uint8),
170                ('bDescriptorType', c_uint8),
171                ('wTotalLength', c_uint16),
172                ('bNumInterfaces', c_uint8),
173                ('bConfigurationValue', c_uint8),
174                ('iConfiguration', c_uint8),
175                ('bmAttributes', c_uint8),
176                ('bMaxPower', c_uint8)]
177
178class _usb_device_desc(Structure):
179    _fields_ = [('bLength', c_uint8),
180                ('bDescriptorType', c_uint8),
181                ('bcdUSB', c_uint16),
182                ('bDeviceClass', c_uint8),
183                ('bDeviceSubClass', c_uint8),
184                ('bDeviceProtocol', c_uint8),
185                ('bMaxPacketSize0', c_uint8),
186                ('idVendor', c_uint16),
187                ('idProduct', c_uint16),
188                ('bcdDevice', c_uint16),
189                ('iManufacturer', c_uint8),
190                ('iProduct', c_uint8),
191                ('iSerialNumber', c_uint8),
192                ('bNumConfigurations', c_uint8)]
193
194class _openusb_request_result(Structure):
195    _fields_ = [('status', c_int32),
196                ('transferred_bytes', c_uint32)]
197
198class _openusb_ctrl_request(Structure):
199    def __init__(self):
200        super(_openusb_ctrl_request, self).__init__()
201        self.setup.bmRequestType = 0
202        self.setup.bRequest = 0
203        self.setup.wValue = 0
204        self.setup.wIndex = 0
205        self.payload = None
206        self.length = 0
207        self.timeout = 0
208        self.flags = 0
209        self.result.status = 0
210        self.result.transferred_bytes = 0
211        self.next = None
212
213    class _openusb_ctrl_setup(Structure):
214        _fields_ = [('bmRequestType', c_uint8),
215                    ('bRequest', c_uint8),
216                    ('wValue', c_uint16),
217                    ('wIndex', c_uint16)]
218    _fields_ = [('setup', _openusb_ctrl_setup),
219                ('payload', POINTER(c_uint8)),
220                ('length', c_uint32),
221                ('timeout', c_uint32),
222                ('flags', c_uint32),
223                ('result', _openusb_request_result),
224                ('next', c_void_p)]
225
226class _openusb_intr_request(Structure):
227    _fields_ = [('interval', c_uint16),
228                ('payload', POINTER(c_uint8)),
229                ('length', c_uint32),
230                ('timeout', c_uint32),
231                ('flags', c_uint32),
232                ('result', _openusb_request_result),
233                ('next', c_void_p)]
234
235class _openusb_bulk_request(Structure):
236    _fields_ = [('payload', POINTER(c_uint8)),
237                ('length', c_uint32),
238                ('timeout', c_uint32),
239                ('flags', c_uint32),
240                ('result', _openusb_request_result),
241                ('next', c_void_p)]
242
243class _openusb_isoc_pkts(Structure):
244    class _openusb_isoc_packet(Structure):
245        _fields_ = [('payload', POINTER(c_uint8)),
246                    ('length', c_uint32)]
247    _fields_ = [('num_packets', c_uint32),
248                ('packets', POINTER(_openusb_isoc_packet))]
249
250class _openusb_isoc_request(Structure):
251    _fields_ = [('start_frame', c_uint32),
252                ('flags', c_uint32),
253                ('pkts', _openusb_isoc_pkts),
254                ('isoc_results', POINTER(_openusb_request_result)),
255                ('isoc_status', c_int32),
256                ('next', c_void_p)]
257
258_openusb_devid = c_uint64
259_openusb_busid = c_uint64
260_openusb_handle = c_uint64
261_openusb_dev_handle = c_uint64
262
263_lib = None
264_ctx = None
265
266def _load_library(find_library=None):
267    # FIXME: cygwin name is "openusb"?
268    #        (that's what the original _load_library() function
269    #         would have searched for)
270    return usb.libloader.load_locate_library(
271        ('openusb',), 'openusb', "OpenUSB library", find_library=find_library
272    )
273
274def _setup_prototypes(lib):
275    # int32_t openusb_init(uint32_t flags , openusb_handle_t *handle);
276    lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)]
277    lib.openusb_init.restype = c_int32
278
279    # void openusb_fini(openusb_handle_t handle );
280    lib.openusb_fini.argtypes = [_openusb_handle]
281
282    # uint32_t openusb_get_busid_list(openusb_handle_t handle,
283    #                                 openusb_busid_t **busids,
284    #                                 uint32_t *num_busids);
285    lib.openusb_get_busid_list.argtypes = [
286            _openusb_handle,
287            POINTER(POINTER(_openusb_busid)),
288            POINTER(c_uint32)
289        ]
290
291    # void openusb_free_busid_list(openusb_busid_t * busids);
292    lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)]
293
294    # uint32_t openusb_get_devids_by_bus(openusb_handle_t handle,
295    #                                    openusb_busid_t busid,
296    #                                    openusb_devid_t **devids,
297    #                                    uint32_t *num_devids);
298    lib.openusb_get_devids_by_bus.argtypes = [
299                _openusb_handle,
300                _openusb_busid,
301                POINTER(POINTER(_openusb_devid)),
302                POINTER(c_uint32)
303            ]
304
305    lib.openusb_get_devids_by_bus.restype = c_int32
306
307    # void openusb_free_devid_list(openusb_devid_t * devids);
308    lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)]
309
310    # int32_t openusb_open_device(openusb_handle_t handle,
311    #                             openusb_devid_t devid ,
312    #                             uint32_t flags,
313    #                             openusb_dev_handle_t *dev);
314    lib.openusb_open_device.argtypes = [
315                _openusb_handle,
316                _openusb_devid,
317                c_uint32,
318                POINTER(_openusb_dev_handle)
319            ]
320
321    lib.openusb_open_device.restype = c_int32
322
323    # int32_t openusb_close_device(openusb_dev_handle_t dev);
324    lib.openusb_close_device.argtypes = [_openusb_dev_handle]
325    lib.openusb_close_device.restype = c_int32
326
327    # int32_t openusb_set_configuration(openusb_dev_handle_t dev,
328    #                                   uint8_t cfg);
329    lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8]
330    lib.openusb_set_configuration.restype = c_int32
331
332    # int32_t openusb_get_configuration(openusb_dev_handle_t dev,
333    #                                   uint8_t *cfg);
334    lib.openusb_get_configuration.argtypes = [_openusb_dev_handle, POINTER(c_uint8)]
335    lib.openusb_get_configuration.restype = c_int32
336
337    # int32_t openusb_claim_interface(openusb_dev_handle_t dev,
338    #                                 uint8_t ifc,
339    #                                 openusb_init_flag_t flags);
340    lib.openusb_claim_interface.argtypes = [
341            _openusb_dev_handle,
342            c_uint8,
343            c_int
344        ]
345
346    lib.openusb_claim_interface.restype = c_int32
347
348    # int32_t openusb_release_interface(openusb_dev_handle_t dev,
349    #                                   uint8_t ifc);
350    lib.openusb_release_interface.argtypes = [
351            _openusb_dev_handle,
352            c_uint8
353        ]
354
355    lib.openusb_release_interface.restype = c_int32
356
357    # int32_topenusb_set_altsetting(openusb_dev_handle_t dev,
358    #                               uint8_t ifc,
359    #                               uint8_t alt);
360    lib.openusb_set_altsetting.argtypes = [
361            _openusb_dev_handle,
362            c_uint8,
363            c_uint8
364        ]
365    lib.openusb_set_altsetting.restype = c_int32
366
367    # int32_t openusb_reset(openusb_dev_handle_t dev);
368    lib.openusb_reset.argtypes = [_openusb_dev_handle]
369    lib.openusb_reset.restype = c_int32
370
371    # int32_t openusb_parse_device_desc(openusb_handle_t handle,
372    #                                   openusb_devid_t devid,
373    #                                   uint8_t *buffer,
374    #                                   uint16_t buflen,
375    #                                   usb_device_desc_t *devdesc);
376    lib.openusb_parse_device_desc.argtypes = [
377            _openusb_handle,
378            _openusb_devid,
379            POINTER(c_uint8),
380            c_uint16,
381            POINTER(_usb_device_desc)
382        ]
383
384    lib.openusb_parse_device_desc.restype = c_int32
385
386    # int32_t openusb_parse_config_desc(openusb_handle_t handle,
387    #                                   openusb_devid_t devid,
388    #                                   uint8_t *buffer,
389    #                                   uint16_t buflen,
390    #                                   uint8_t cfgidx,
391    #                                   usb_config_desc_t *cfgdesc);
392    lib.openusb_parse_config_desc.argtypes = [
393                _openusb_handle,
394                _openusb_devid,
395                POINTER(c_uint8),
396                c_uint16,
397                c_uint8,
398                POINTER(_usb_config_desc)
399            ]
400    lib.openusb_parse_config_desc.restype = c_int32
401
402    # int32_t openusb_parse_interface_desc(openusb_handle_t handle,
403    #                                      openusb_devid_t devid,
404    #                                      uint8_t *buffer,
405    #                                      uint16_t buflen,
406    #                                      uint8_t cfgidx,
407    #                                      uint8_t ifcidx,
408    #                                      uint8_t alt,
409    #                                      usb_interface_desc_t *ifcdesc);
410    lib.openusb_parse_interface_desc.argtypes = [
411                    _openusb_handle,
412                    _openusb_devid,
413                    POINTER(c_uint8),
414                    c_uint16,
415                    c_uint8,
416                    c_uint8,
417                    c_uint8,
418                    POINTER(_usb_interface_desc)
419                ]
420
421    lib.openusb_parse_interface_desc.restype = c_int32
422
423    # int32_t openusb_parse_endpoint_desc(openusb_handle_t handle,
424    #                                     openusb_devid_t devid,
425    #                                     uint8_t *buffer,
426    #                                     uint16_t buflen,
427    #                                     uint8_t cfgidx,
428    #                                     uint8_t ifcidx,
429    #                                     uint8_t alt,
430    #                                     uint8_t eptidx,
431    #                                     usb_endpoint_desc_t *eptdesc);
432    lib.openusb_parse_endpoint_desc.argtypes = [
433                    _openusb_handle,
434                    _openusb_devid,
435                    POINTER(c_uint8),
436                    c_uint16,
437                    c_uint8,
438                    c_uint8,
439                    c_uint8,
440                    c_uint8,
441                    POINTER(_usb_endpoint_desc)
442                ]
443
444    lib.openusb_parse_interface_desc.restype = c_int32
445
446    # const char *openusb_strerror(int32_t error );
447    lib.openusb_strerror.argtypes = [c_int32]
448    lib.openusb_strerror.restype = c_char_p
449
450    # int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev,
451    #                           uint8_t ifc,
452    #                           uint8_t ept,
453    #                           openusb_ctrl_request_t *ctrl);
454    lib.openusb_ctrl_xfer.argtypes = [
455            _openusb_dev_handle,
456            c_uint8,
457            c_uint8,
458            POINTER(_openusb_ctrl_request)
459        ]
460
461    lib.openusb_ctrl_xfer.restype = c_int32
462
463    # int32_t openusb_intr_xfer(openusb_dev_handle_t dev,
464    #                           uint8_t ifc,
465    #                           uint8_t ept,
466    #                           openusb_intr_request_t *intr);
467    lib.openusb_intr_xfer.argtypes = [
468                _openusb_dev_handle,
469                c_uint8,
470                c_uint8,
471                POINTER(_openusb_intr_request)
472            ]
473
474    lib.openusb_bulk_xfer.restype = c_int32
475
476    # int32_t openusb_bulk_xfer(openusb_dev_handle_t dev,
477    #                           uint8_t ifc,
478    #                           uint8_t ept,
479    #                           openusb_bulk_request_t *bulk);
480    lib.openusb_bulk_xfer.argtypes = [
481            _openusb_dev_handle,
482            c_uint8,
483            c_uint8,
484            POINTER(_openusb_bulk_request)
485        ]
486
487    lib.openusb_bulk_xfer.restype = c_int32
488
489    # int32_t openusb_isoc_xfer(openusb_dev_handle_t dev,
490    #                           uint8_t ifc,
491    #                           uint8_t ept,
492    #                           openusb_isoc_request_t *isoc);
493    lib.openusb_isoc_xfer.argtypes = [
494            _openusb_dev_handle,
495            c_uint8,
496            c_uint8,
497            POINTER(_openusb_isoc_request)
498        ]
499
500    lib.openusb_isoc_xfer.restype = c_int32
501
502def _check(ret):
503    if hasattr(ret, 'value'):
504        ret = ret.value
505
506    if ret != 0:
507        raise USBError(_lib.openusb_strerror(ret), ret, _openusb_errno[ret])
508    return ret
509
510class _Context(_objfinalizer.AutoFinalizedObject):
511    def __init__(self):
512        self.handle = _openusb_handle()
513        _check(_lib.openusb_init(0, byref(self.handle)))
514    def _finalize_object(self):
515        _lib.openusb_fini(self.handle)
516
517class _BusIterator(_objfinalizer.AutoFinalizedObject):
518    def __init__(self):
519        self.buslist = POINTER(_openusb_busid)()
520        num_busids = c_uint32()
521        _check(_lib.openusb_get_busid_list(_ctx.handle,
522                                           byref(self.buslist),
523                                           byref(num_busids)))
524        self.num_busids = num_busids.value
525    def __iter__(self):
526        for i in range(self.num_busids):
527            yield self.buslist[i]
528    def _finalize_object(self):
529        _lib.openusb_free_busid_list(self.buslist)
530
531class _DevIterator(_objfinalizer.AutoFinalizedObject):
532    def __init__(self, busid):
533        self.devlist = POINTER(_openusb_devid)()
534        num_devids = c_uint32()
535        _check(_lib.openusb_get_devids_by_bus(_ctx.handle,
536                                              busid,
537                                              byref(self.devlist),
538                                              byref(num_devids)))
539        self.num_devids = num_devids.value
540    def __iter__(self):
541        for i in range(self.num_devids):
542            yield self.devlist[i]
543    def _finalize_object(self):
544        _lib.openusb_free_devid_list(self.devlist)
545
546class _OpenUSB(usb.backend.IBackend):
547    @methodtrace(_logger)
548    def enumerate_devices(self):
549        for bus in _BusIterator():
550            for devid in _DevIterator(bus):
551                yield devid
552
553    @methodtrace(_logger)
554    def get_device_descriptor(self, dev):
555        desc = _usb_device_desc()
556        _check(_lib.openusb_parse_device_desc(_ctx.handle,
557                                              dev,
558                                              None,
559                                              0,
560                                              byref(desc)))
561        desc.bus = None
562        desc.address = None
563        desc.port_number = None
564        desc.port_numbers = None
565        desc.speed = None
566        return desc
567
568    @methodtrace(_logger)
569    def get_configuration_descriptor(self, dev, config):
570        desc = _usb_config_desc()
571        _check(_lib.openusb_parse_config_desc(_ctx.handle,
572                                              dev,
573                                              None,
574                                              0,
575                                              config,
576                                              byref(desc)))
577        desc.extra_descriptors = None
578        return desc
579
580    @methodtrace(_logger)
581    def get_interface_descriptor(self, dev, intf, alt, config):
582        desc = _usb_interface_desc()
583        _check(_lib.openusb_parse_interface_desc(_ctx.handle,
584                                                 dev,
585                                                 None,
586                                                 0,
587                                                 config,
588                                                 intf,
589                                                 alt,
590                                                 byref(desc)))
591        desc.extra_descriptors = None
592        return desc
593
594    @methodtrace(_logger)
595    def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
596        desc = _usb_endpoint_desc()
597        _check(_lib.openusb_parse_endpoint_desc(_ctx.handle,
598                                                dev,
599                                                None,
600                                                0,
601                                                config,
602                                                intf,
603                                                alt,
604                                                ep,
605                                                byref(desc)))
606        desc.extra_descriptors = None
607        return desc
608
609    @methodtrace(_logger)
610    def open_device(self, dev):
611        handle = _openusb_dev_handle()
612        _check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle)))
613        return handle
614
615    @methodtrace(_logger)
616    def close_device(self, dev_handle):
617        _lib.openusb_close_device(dev_handle)
618
619    @methodtrace(_logger)
620    def set_configuration(self, dev_handle, config_value):
621        _check(_lib.openusb_set_configuration(dev_handle, config_value))
622
623    @methodtrace(_logger)
624    def get_configuration(self, dev_handle):
625        config = c_uint8()
626        _check(_lib.openusb_get_configuration(dev_handle, byref(config)))
627        return config.value
628
629    @methodtrace(_logger)
630    def set_interface_altsetting(self, dev_handle, intf, altsetting):
631        _check(_lib.openusb_set_altsetting(dev_handle, intf, altsetting))
632
633    @methodtrace(_logger)
634    def claim_interface(self, dev_handle, intf):
635        _check(_lib.openusb_claim_interface(dev_handle, intf, 0))
636
637    @methodtrace(_logger)
638    def release_interface(self, dev_handle, intf):
639        _lib.openusb_release_interface(dev_handle, intf)
640
641    @methodtrace(_logger)
642    def bulk_write(self, dev_handle, ep, intf, data, timeout):
643        request = _openusb_bulk_request()
644        memset(byref(request), 0, sizeof(request))
645        payload, request.length = data.buffer_info()
646        request.payload = cast(payload, POINTER(c_uint8))
647        request.timeout = timeout
648        _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
649        return request.result.transferred_bytes
650
651    @methodtrace(_logger)
652    def bulk_read(self, dev_handle, ep, intf, buff, timeout):
653        request = _openusb_bulk_request()
654        memset(byref(request), 0, sizeof(request))
655        payload, request.length = buff.buffer_info()
656        request.payload = cast(payload, POINTER(c_uint8))
657        request.timeout = timeout
658        _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
659        return request.result.transferred_bytes
660
661    @methodtrace(_logger)
662    def intr_write(self, dev_handle, ep, intf, data, timeout):
663        request = _openusb_intr_request()
664        memset(byref(request), 0, sizeof(request))
665        payload, request.length = data.buffer_info()
666        request.payload = cast(payload, POINTER(c_uint8))
667        request.timeout = timeout
668        _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
669        return request.result.transferred_bytes
670
671    @methodtrace(_logger)
672    def intr_read(self, dev_handle, ep, intf, buff, timeout):
673        request = _openusb_intr_request()
674        memset(byref(request), 0, sizeof(request))
675        payload, request.length = buff.buffer_info()
676        request.payload = cast(payload, POINTER(c_uint8))
677        request.timeout = timeout
678        _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
679        return request.result.transferred_bytes
680
681# TODO: implement isochronous
682#    @methodtrace(_logger)
683#    def iso_write(self, dev_handle, ep, intf, data, timeout):
684#       pass
685
686#    @methodtrace(_logger)
687#    def iso_read(self, dev_handle, ep, intf, size, timeout):
688#        pass
689
690    @methodtrace(_logger)
691    def ctrl_transfer(self,
692                      dev_handle,
693                      bmRequestType,
694                      bRequest,
695                      wValue,
696                      wIndex,
697                      data,
698                      timeout):
699        request = _openusb_ctrl_request()
700        request.setup.bmRequestType = bmRequestType
701        request.setup.bRequest = bRequest
702        request.setup.wValue
703        request.setup.wIndex
704        request.timeout = timeout
705
706        direction = usb.util.ctrl_direction(bmRequestType)
707
708        payload, request.length = data.buffer_info()
709        request.length *= data.itemsize
710        request.payload = cast(payload, POINTER(c_uint8))
711
712        _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request)))
713
714        return request.result.transferred_bytes
715
716    @methodtrace(_logger)
717    def reset_device(self, dev_handle):
718        _check(_lib.openusb_reset(dev_handle))
719
720    @methodtrace(_logger)
721    def clear_halt(self, dev_handle, ep):
722        bmRequestType = util.build_request_type(
723                            util.CTRL_OUT,
724                            util.CTRL_TYPE_STANDARD,
725                            util.CTRL_RECIPIENT_ENDPOINT)
726        self.ctrl_transfer(
727            dev_handle,
728            bmRequestType,
729            0x03,
730            0,
731            ep,
732            _interop.as_array(),
733            1000)
734
735def get_backend(find_library=None):
736    try:
737        global _lib, _ctx
738        if _lib is None:
739            _lib = _load_library(find_library)
740            _setup_prototypes(_lib)
741            _ctx = _Context()
742        return _OpenUSB()
743    except usb.libloader.LibraryException:
744        # exception already logged (if any)
745        _logger.error('Error loading OpenUSB backend', exc_info=False)
746        return None
747    except Exception:
748        _logger.error('Error loading OpenUSB backend', exc_info=True)
749        return None
750