openusb.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. # Copyright (C) 2009-2011 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. from ctypes import *
  29. import ctypes.util
  30. import usb.util
  31. from usb._debug import methodtrace
  32. import logging
  33. __author__ = 'Wander Lairson Costa'
  34. __all__ = ['get_backend']
  35. _logger = logging.getLogger('usb.backend.openusb')
  36. class _usb_endpoint_desc(Structure):
  37. _fields_ = [('bLength', c_uint8),
  38. ('bDescriptorType', c_uint8),
  39. ('bEndpointAddress', c_uint8),
  40. ('bmAttributes', c_uint8),
  41. ('wMaxPacketSize', c_uint16),
  42. ('bInterval', c_uint8),
  43. ('bRefresh', c_uint8),
  44. ('bSynchAddress', c_uint8)]
  45. class _usb_interface_desc(Structure):
  46. _fields_ = [('bLength', c_uint8),
  47. ('bDescriptorType', c_uint8),
  48. ('bInterfaceNumber', c_uint8),
  49. ('bAlternateSetting', c_uint8),
  50. ('bNumEndpoints', c_uint8),
  51. ('bInterfaceClass', c_uint8),
  52. ('bInterfaceSubClass', c_uint8),
  53. ('bInterfaceProtocol', c_uint8),
  54. ('iInterface', c_uint8)]
  55. class _usb_config_desc(Structure):
  56. _fields_ = [('bLength', c_uint8),
  57. ('bDescriptorType', c_uint8),
  58. ('wTotalLength', c_uint16),
  59. ('bNumInterfaces', c_uint8),
  60. ('bConfigurationValue', c_uint8),
  61. ('iConfiguration', c_uint8),
  62. ('bmAttributes', c_uint8),
  63. ('bMaxPower', c_uint8)]
  64. class _usb_device_desc(Structure):
  65. _fields_ = [('bLength', c_uint8),
  66. ('bDescriptorType', c_uint8),
  67. ('bcdUSB', c_uint16),
  68. ('bDeviceClass', c_uint8),
  69. ('bDeviceSubClass', c_uint8),
  70. ('bDeviceProtocol', c_uint8),
  71. ('bMaxPacketSize0', c_uint8),
  72. ('idVendor', c_uint16),
  73. ('idProduct', c_uint16),
  74. ('bcdDevice', c_uint16),
  75. ('iManufacturer', c_uint8),
  76. ('iProduct', c_uint8),
  77. ('iSerialNumber', c_uint8),
  78. ('bNumConfigurations', c_uint8)]
  79. class _openusb_request_result(Structure):
  80. _fields_ = [('status', c_int32),
  81. ('transfered_bytes', c_uint32)]
  82. class _openusb_ctrl_request(Structure):
  83. class _openusb_ctrl_setup(Structure):
  84. _fields_ = [('bmRequestType', c_uint8),
  85. ('bRequest', c_uint8),
  86. ('wValue', c_uint16),
  87. ('wIndex', c_uint16)]
  88. _fields_ = [('payload', POINTER(c_uint8)),
  89. ('length', c_uint32),
  90. ('timeout', c_uint32),
  91. ('flags', c_uint32),
  92. ('result', _openusb_request_result),
  93. ('next', c_void_p)]
  94. class _openusb_intr_request(Structure):
  95. _fields_ = [('interval', c_uint16),
  96. ('payload', POINTER(c_uint8)),
  97. ('length', c_uint32),
  98. ('timeout', c_uint32),
  99. ('flags', c_uint32),
  100. ('result', _openusb_request_result),
  101. ('next', c_void_p)]
  102. class _openusb_bulk_request(Structure):
  103. _fields_ = [('payload', POINTER(c_uint8)),
  104. ('length', c_uint32),
  105. ('timeout', c_uint32),
  106. ('flags', c_uint32),
  107. ('result', _openusb_request_result),
  108. ('next', c_void_p)]
  109. class _openusb_isoc_pkts(Structure):
  110. class _openusb_isoc_packet(Structure):
  111. _fields_ = [('payload', POINTER(c_uint8)),
  112. ('length', c_uint32)]
  113. _fields_ = [('num_packets', c_uint32),
  114. ('packets', POINTER(_openusb_isoc_packet))]
  115. class _openusb_isoc_request(Structure):
  116. _fields_ = [('start_frame', c_uint32),
  117. ('flags', c_uint32),
  118. ('pkts', _openusb_isoc_pkts),
  119. ('isoc_results', POINTER(_openusb_request_result)),
  120. ('isoc_status', c_int32),
  121. ('next', c_void_p)]
  122. _openusb_devid = c_uint64
  123. _openusb_busid = c_uint64
  124. _openusb_handle = c_uint64
  125. _openusb_dev_handle = c_uint64
  126. _lib = None
  127. _ctx = None
  128. def _load_library():
  129. libname = ctypes.util.find_library('openusb')
  130. if libname is None:
  131. raise OSError('USB library could not be found')
  132. return CDLL(libname)
  133. def _setup_prototypes(lib):
  134. # int32_t openusb_init(uint32_t flags , openusb_handle_t *handle);
  135. lib.openusb_init.argtypes = [c_uint32, POINTER(_openusb_handle)]
  136. lib.openusb_init.restype = c_int32
  137. # void openusb_fini(openusb_handle_t handle );
  138. lib.openusb_fini.argtypes = [_openusb_handle]
  139. # uint32_t openusb_get_busid_list(openusb_handle_t handle,
  140. # openusb_busid_t **busids,
  141. # uint32_t *num_busids);
  142. lib.openusb_get_busid_list.argtypes = [
  143. _openusb_handle,
  144. POINTER(POINTER(_openusb_busid)),
  145. POINTER(c_uint32)
  146. ]
  147. # void openusb_free_busid_list(openusb_busid_t * busids);
  148. lib.openusb_free_busid_list.argtypes = [POINTER(_openusb_busid)]
  149. # uint32_t openusb_get_devids_by_bus(openusb_handle_t handle,
  150. # openusb_busid_t busid,
  151. # openusb_devid_t **devids,
  152. # uint32_t *num_devids);
  153. lib.openusb_get_devids_by_bus.argtypes = [
  154. _openusb_handle,
  155. _openusb_busid,
  156. POINTER(POINTER(_openusb_devid)),
  157. POINTER(c_uint32)
  158. ]
  159. lib.openusb_get_devids_by_bus.restype = c_int32
  160. # void openusb_free_devid_list(openusb_devid_t * devids);
  161. lib.openusb_free_devid_list.argtypes = [POINTER(_openusb_devid)]
  162. # int32_t openusb_open_device(openusb_handle_t handle,
  163. # openusb_devid_t devid ,
  164. # uint32_t flags,
  165. # openusb_dev_handle_t *dev);
  166. lib.openusb_open_device.argtypes = [
  167. _openusb_handle,
  168. _openusb_devid,
  169. c_uint32,
  170. POINTER(_openusb_dev_handle)
  171. ]
  172. lib.openusb_open_device.restype = c_int32
  173. # int32_t openusb_close_device(openusb_dev_handle_t dev);
  174. lib.openusb_close_device.argtypes = [_openusb_dev_handle]
  175. lib.openusb_close_device.restype = c_int32
  176. # int32_t openusb_set_configuration(openusb_dev_handle_t dev,
  177. # uint8_t cfg);
  178. lib.openusb_set_configuration.argtypes = [_openusb_dev_handle, c_uint8]
  179. lib.openusb_set_configuration.restype = c_int32
  180. # int32_t openusb_get_configuration(openusb_dev_handle_t dev,
  181. # uint8_t *cfg);
  182. lib.openusb_get_configuration.argtypes = [_openusb_dev_handle, POINTER(c_uint8)]
  183. lib.openusb_get_configuration.restype = c_int32
  184. # int32_t openusb_claim_interface(openusb_dev_handle_t dev,
  185. # uint8_t ifc,
  186. # openusb_init_flag_t flags);
  187. lib.openusb_claim_interface.argtypes = [
  188. _openusb_dev_handle,
  189. c_uint8,
  190. c_int
  191. ]
  192. lib.openusb_claim_interface.restype = c_int32
  193. # int32_t openusb_release_interface(openusb_dev_handle_t dev,
  194. # uint8_t ifc);
  195. lib.openusb_release_interface.argtypes = [
  196. _openusb_dev_handle,
  197. c_uint8
  198. ]
  199. lib.openusb_release_interface.restype = c_int32
  200. # int32_topenusb_set_altsetting(openusb_dev_handle_t dev,
  201. # uint8_t ifc,
  202. # uint8_t alt);
  203. lib.openusb_set_altsetting.argtypes = [
  204. _openusb_dev_handle,
  205. c_uint8,
  206. c_uint8
  207. ]
  208. lib.openusb_set_altsetting.restype = c_int32
  209. # int32_t openusb_reset(openusb_dev_handle_t dev);
  210. lib.openusb_reset.argtypes = [_openusb_dev_handle]
  211. lib.openusb_reset.restype = c_int32
  212. # int32_t openusb_parse_device_desc(openusb_handle_t handle,
  213. # openusb_devid_t devid,
  214. # uint8_t *buffer,
  215. # uint16_t buflen,
  216. # usb_device_desc_t *devdesc);
  217. lib.openusb_parse_device_desc.argtypes = [
  218. _openusb_handle,
  219. _openusb_devid,
  220. POINTER(c_uint8),
  221. c_uint16,
  222. POINTER(_usb_device_desc)
  223. ]
  224. lib.openusb_parse_device_desc.restype = c_int32
  225. # int32_t openusb_parse_config_desc(openusb_handle_t handle,
  226. # openusb_devid_t devid,
  227. # uint8_t *buffer,
  228. # uint16_t buflen,
  229. # uint8_t cfgidx,
  230. # usb_config_desc_t *cfgdesc);
  231. lib.openusb_parse_config_desc.argtypes = [
  232. _openusb_handle,
  233. _openusb_devid,
  234. POINTER(c_uint8),
  235. c_uint16,
  236. c_uint8,
  237. POINTER(_usb_config_desc)
  238. ]
  239. lib.openusb_parse_config_desc.restype = c_int32
  240. # int32_t openusb_parse_interface_desc(openusb_handle_t handle,
  241. # openusb_devid_t devid,
  242. # uint8_t *buffer,
  243. # uint16_t buflen,
  244. # uint8_t cfgidx,
  245. # uint8_t ifcidx,
  246. # uint8_t alt,
  247. # usb_interface_desc_t *ifcdesc);
  248. lib.openusb_parse_interface_desc.argtypes = [
  249. _openusb_handle,
  250. _openusb_devid,
  251. POINTER(c_uint8),
  252. c_uint16,
  253. c_uint8,
  254. c_uint8,
  255. c_uint8,
  256. POINTER(_usb_interface_desc)
  257. ]
  258. lib.openusb_parse_interface_desc.restype = c_int32
  259. # int32_t openusb_parse_endpoint_desc(openusb_handle_t handle,
  260. # openusb_devid_t devid,
  261. # uint8_t *buffer,
  262. # uint16_t buflen,
  263. # uint8_t cfgidx,
  264. # uint8_t ifcidx,
  265. # uint8_t alt,
  266. # uint8_t eptidx,
  267. # usb_endpoint_desc_t *eptdesc);
  268. lib.openusb_parse_endpoint_desc.argtypes = [
  269. _openusb_handle,
  270. _openusb_devid,
  271. POINTER(c_uint8),
  272. c_uint16,
  273. c_uint8,
  274. c_uint8,
  275. c_uint8,
  276. c_uint8,
  277. POINTER(_usb_endpoint_desc)
  278. ]
  279. lib.openusb_parse_interface_desc.restype = c_int32
  280. # const char *openusb_strerror(int32_t error );
  281. lib.openusb_strerror.argtypes = [c_int32]
  282. lib.openusb_strerror.restype = c_char_p
  283. # int32_t openusb_ctrl_xfer(openusb_dev_handle_t dev,
  284. # uint8_t ifc,
  285. # uint8_t ept,
  286. # openusb_ctrl_request_t *ctrl);
  287. lib.openusb_ctrl_xfer.argtypes = [
  288. _openusb_dev_handle,
  289. c_uint8,
  290. c_uint8,
  291. POINTER(_openusb_ctrl_request)
  292. ]
  293. lib.openusb_ctrl_xfer.restype = c_int32
  294. # int32_t openusb_intr_xfer(openusb_dev_handle_t dev,
  295. # uint8_t ifc,
  296. # uint8_t ept,
  297. # openusb_intr_request_t *intr);
  298. lib.openusb_intr_xfer.argtypes = [
  299. _openusb_dev_handle,
  300. c_uint8,
  301. c_uint8,
  302. POINTER(_openusb_intr_request)
  303. ]
  304. lib.openusb_bulk_xfer.restype = c_int32
  305. # int32_t openusb_bulk_xfer(openusb_dev_handle_t dev,
  306. # uint8_t ifc,
  307. # uint8_t ept,
  308. # openusb_bulk_request_t *bulk);
  309. lib.openusb_bulk_xfer.argtypes = [
  310. _openusb_dev_handle,
  311. c_uint8,
  312. c_uint8,
  313. POINTER(_openusb_bulk_request)
  314. ]
  315. lib.openusb_bulk_xfer.restype = c_int32
  316. # int32_t openusb_isoc_xfer(openusb_dev_handle_t dev,
  317. # uint8_t ifc,
  318. # uint8_t ept,
  319. # openusb_isoc_request_t *isoc);
  320. lib.openusb_isoc_xfer.argtypes = [
  321. _openusb_dev_handle,
  322. c_uint8,
  323. c_uint8,
  324. POINTER(_openusb_isoc_request)
  325. ]
  326. lib.openusb_isoc_xfer.restype = c_int32
  327. def _check(retval):
  328. if retval.value != 0:
  329. from usb.core import USBError
  330. raise USBError(_lib.openusb_strerror(retval).value)
  331. return retval
  332. class _Context(object):
  333. def __init__(self):
  334. self.handle = _openusb_handle()
  335. _check(_lib.openusb_init(0, byref(self.handle)))
  336. def __del__(self):
  337. _lib.openusb_fini(self.handle)
  338. class _BusIterator(object):
  339. def __init__(self):
  340. self.buslist = POINTER(openusb_busid)()
  341. num_busids = c_uint32()
  342. _check(_lib.openusb_get_busid_list(_ctx.handle,
  343. byref(self.buslist),
  344. byref(num_busids)))
  345. self.num_busids = num_busids.value
  346. def __iter__(self):
  347. for i in range(self.num_busids):
  348. yield self.buslist[i]
  349. def __del__(self):
  350. _lib.openusb_free_busid_list(self.buslist)
  351. class _DevIterator(object):
  352. def __init__(self, busid):
  353. self.devlist = POINTER(_openusb_devid)()
  354. num_devids = c_uint32()
  355. _check(_lib.openusb_get_devids_by_bus(_ctx.handle,
  356. busid,
  357. byref(self.devlist),
  358. byref(num_devids)))
  359. self.num_devids = num_devids.value
  360. def __iter__(self):
  361. for i in range(self.num_devids):
  362. yield self.devlist[i]
  363. def __del__(self):
  364. _lib.openusb_free_devid_list(self.devlist)
  365. class _OpenUSB(usb.backend.IBackend):
  366. @methodtrace(_logger)
  367. def enumerate_devices(self):
  368. for bus in _BusIterator():
  369. for devid in _DevIterator(bus):
  370. yield devid
  371. @methodtrace(_logger)
  372. def get_device_descriptor(self, dev):
  373. desc = _usb_device_desc()
  374. _check(_lib.openusb_parse_device_desc(_ctx.handle,
  375. dev,
  376. None,
  377. 0,
  378. byref(desc)))
  379. return desc
  380. @methodtrace(_logger)
  381. def get_configuration_descriptor(self, dev, config):
  382. desc = _usb_config_desc()
  383. _check(_lib.openusb_parse_config_desc(_ctx.handle,
  384. dev,
  385. None,
  386. 0,
  387. config,
  388. byref(desc)))
  389. return desc
  390. @methodtrace(_logger)
  391. def get_interface_descriptor(self, dev, intf, alt, config):
  392. desc = _usb_interface_desc()
  393. _check(_lib.openusb_parse_interface_desc(_ctx.handle,
  394. dev,
  395. None,
  396. 0,
  397. config,
  398. intf,
  399. alt,
  400. byref(desc)))
  401. return desc
  402. @methodtrace(_logger)
  403. def get_endpoint_descriptor(self, dev, ep, intf, alt, config):
  404. desc = _usb_endpoint_desc()
  405. _check(_lib.openusb_parse_endpoint_desc(_ctx.handle,
  406. dev,
  407. None,
  408. 0,
  409. config,
  410. intf,
  411. alt,
  412. ep,
  413. byref(desc)))
  414. return desc
  415. @methodtrace(_logger)
  416. def open_device(self, dev):
  417. handle = _openusb_dev_handle()
  418. _check(_lib.openusb_open_device(_ctx.handle, dev, 0, byref(handle)))
  419. return handle
  420. @methodtrace(_logger)
  421. def close_device(self, dev_handle):
  422. _lib.openusb_close_device(dev_handle)
  423. @methodtrace(_logger)
  424. def set_configuration(self, dev_handle, config_value):
  425. _check(_lib.openusb_set_configuration(dev_handle, config_value))
  426. @methodtrace(_logger)
  427. def get_configuration(self, dev_handle):
  428. config = c_uint8()
  429. _check(_lib.openusb_get_configuration(dev_handle, byref(config)))
  430. return config.value
  431. @methodtrace(_logger)
  432. def set_interface_altsetting(self, dev_handle, intf, altsetting):
  433. _check(_lib.set_altsetting(dev_handle, intf, altsetting))
  434. @methodtrace(_logger)
  435. def claim_interface(self, dev_handle, intf):
  436. _check(_lib.openusb_claim_interface(dev_handle, intf, 0))
  437. @methodtrace(_logger)
  438. def release_interface(self, dev_handle, intf):
  439. _lib.openusb_release_interface(dev_handle, intf)
  440. @methodtrace(_logger)
  441. def bulk_write(self, dev_handle, ep, intf, data, timeout):
  442. request = _openusb_bulk_request()
  443. memset(byref(request), 0, sizeof(request))
  444. request.payload, request.length = data.buffer_info()
  445. request.timeout = timeout
  446. _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
  447. return request.transfered_bytes.value
  448. @methodtrace(_logger)
  449. def bulk_read(self, dev_handle, ep, intf, size, timeout):
  450. request = _openusb_bulk_request()
  451. buffer = array.array('B', '\x00' * size)
  452. memset(byref(request), 0, sizeof(request))
  453. request.payload, request.length = buffer.buffer_info()
  454. request.timeout = timeout
  455. _check(_lib.openusb_bulk_xfer(dev_handle, intf, ep, byref(request)))
  456. return buffer[:request.transfered_bytes.value]
  457. @methodtrace(_logger)
  458. def intr_write(self, dev_handle, ep, intf, data, timeout):
  459. request = _openusb_intr_request()
  460. memset(byref(request), 0, sizeof(request))
  461. payload, request.length = data.buffer_info()
  462. request.payload = cast(payload, POINTER(c_uint8))
  463. request.timeout = timeout
  464. _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
  465. return request.transfered_bytes.value
  466. @methodtrace(_logger)
  467. def intr_read(self, dev_handle, ep, intf, size, timeout):
  468. request = _openusb_intr_request()
  469. buffer = array.array('B', '\x00' * size)
  470. memset(byref(request), 0, sizeof(request))
  471. payload, request.length = buffer.buffer_info()
  472. request.payload = cast(payload, POINTER(c_uint8))
  473. request.timeout = timeout
  474. _check(_lib.openusb_intr_xfer(dev_handle, intf, ep, byref(request)))
  475. return buffer[:request.transfered_bytes.value]
  476. # TODO: implement isochronous
  477. # @methodtrace(_logger)
  478. # def iso_write(self, dev_handle, ep, intf, data, timeout):
  479. # pass
  480. # @methodtrace(_logger)
  481. # def iso_read(self, dev_handle, ep, intf, size, timeout):
  482. # pass
  483. @methodtrace(_logger)
  484. def ctrl_transfer(self,
  485. dev_handle,
  486. bmRequestType,
  487. bRequest,
  488. wValue,
  489. wIndex,
  490. data_or_wLength,
  491. timeout):
  492. request = _openusb_ctrl_request()
  493. request.setup.bmRequestType = bmRequestType
  494. request.setup.bRequest = bRequest
  495. request.setup.wValue
  496. request.setup.wIndex
  497. request.timeout = timeout
  498. direction = usb.util.ctrl_direction(bmRequestType)
  499. if direction == ENDPOINT_OUT:
  500. buffer = data_or_wLength
  501. else:
  502. buffer = array.array('B', '\x00' * data_or_wLength)
  503. payload, request.length = buffer.buffer_info()
  504. request.payload = cast(payload, POINTER(c_uint8))
  505. ret = _check(_lib.openusb_ctrl_xfer(dev_handle, 0, 0, byref(request)))
  506. if direction == ENDPOINT_OUT:
  507. ret
  508. else:
  509. buffer[:ret]
  510. @methodtrace(_logger)
  511. def reset_device(self, dev_handle):
  512. _check(_lib.openusb_reset(dev_handle))
  513. def get_backend():
  514. try:
  515. global _lib, _ctx
  516. if _lib is None:
  517. _lib = _load_library()
  518. _setup_prototypes(_lib)
  519. _ctx = _Context()
  520. return _OpenUSB()
  521. except Exception:
  522. _logger.error('Error loading OpenUSB backend', exc_info=True)
  523. return None