0
# Device Access and Configuration
1
2
USB device access involves two main classes: USBDevice for device enumeration and descriptor access, and USBDeviceHandle for actual communication and configuration. This separation allows efficient device discovery without claiming system resources until communication is needed.
3
4
## Capabilities
5
6
### Device Information and Properties
7
8
Access device identification, location, and capability information without opening the device for communication.
9
10
```python { .api }
11
class USBDevice:
12
def getBusNumber(self):
13
"""
14
Get device's bus number.
15
16
Returns:
17
int: Bus number
18
"""
19
20
def getPortNumber(self):
21
"""
22
Get device's port number.
23
24
Returns:
25
int: Port number
26
"""
27
28
def getPortNumberList(self):
29
"""
30
Get list of port numbers from root hub to device.
31
32
Returns:
33
list[int]: Port numbers along the path
34
"""
35
36
def getDeviceAddress(self):
37
"""
38
Get device's address on the bus.
39
40
Returns:
41
int: Device address (1-127)
42
"""
43
44
def getVendorID(self):
45
"""
46
Get device's vendor ID.
47
48
Returns:
49
int: 16-bit vendor ID
50
"""
51
52
def getProductID(self):
53
"""
54
Get device's product ID.
55
56
Returns:
57
int: 16-bit product ID
58
"""
59
60
def getbcdUSB(self):
61
"""
62
Get USB specification version in BCD format.
63
64
Returns:
65
int: USB version (e.g. 0x0200 for USB 2.0)
66
"""
67
68
def getbcdDevice(self):
69
"""
70
Get device release number in BCD format.
71
72
Returns:
73
int: Device release number
74
"""
75
76
def getDeviceClass(self):
77
"""
78
Get device class code.
79
80
Returns:
81
int: Device class (0 if specified at interface level)
82
"""
83
84
def getDeviceSubClass(self):
85
"""
86
Get device subclass code.
87
88
Returns:
89
int: Device subclass
90
"""
91
92
def getDeviceProtocol(self):
93
"""
94
Get device protocol code.
95
96
Returns:
97
int: Device protocol
98
"""
99
100
def getDeviceSpeed(self):
101
"""
102
Get device operating speed.
103
104
Returns:
105
int: Speed constant (SPEED_LOW, SPEED_FULL, SPEED_HIGH, SPEED_SUPER, SPEED_SUPER_PLUS)
106
"""
107
108
def getMaxPacketSize0(self):
109
"""
110
Get maximum packet size for endpoint 0 (control endpoint).
111
112
Returns:
113
int: Maximum packet size in bytes
114
"""
115
116
def getMaxPacketSize(self, endpoint):
117
"""
118
Get maximum packet size for specified endpoint.
119
120
Args:
121
endpoint (int): Endpoint address
122
123
Returns:
124
int: Maximum packet size in bytes
125
126
Warning:
127
May not always give expected results. Consult endpoint descriptor instead.
128
"""
129
130
def getMaxISOPacketSize(self, endpoint):
131
"""
132
Get maximum isochronous packet size for endpoint.
133
134
Args:
135
endpoint (int): Endpoint address
136
137
Returns:
138
int: Maximum ISO packet size in bytes
139
140
Warning:
141
May not always give expected results. Consult endpoint descriptor instead.
142
"""
143
144
def getNumConfigurations(self):
145
"""
146
Get number of possible configurations.
147
148
Returns:
149
int: Number of configurations
150
"""
151
```
152
153
### Device Opening and Closing
154
155
Open devices for communication and manage device handle lifecycle.
156
157
```python { .api }
158
class USBDevice:
159
def open(self):
160
"""
161
Open device for communication.
162
163
Returns:
164
USBDeviceHandle: Handle for device communication
165
166
Raises:
167
USBError: If device cannot be opened
168
"""
169
170
def close(self):
171
"""Close device and release resources."""
172
173
class USBDeviceHandle:
174
def close(self):
175
"""
176
Close device handle and release resources.
177
178
Note:
179
Cancels any in-flight transfers. May block until transfers complete.
180
"""
181
182
def getDevice(self):
183
"""
184
Get USBDevice instance for this handle.
185
186
Returns:
187
USBDevice: Associated device instance
188
"""
189
```
190
191
### String Descriptor Access
192
193
Retrieve human-readable device information including manufacturer, product name, and serial number.
194
195
```python { .api }
196
class USBDevice:
197
def getManufacturer(self):
198
"""
199
Get manufacturer string (opens device temporarily).
200
201
Returns:
202
str or None: Manufacturer name or None if not available
203
"""
204
205
def getProduct(self):
206
"""
207
Get product string (opens device temporarily).
208
209
Returns:
210
str or None: Product name or None if not available
211
"""
212
213
def getSerialNumber(self):
214
"""
215
Get serial number string (opens device temporarily).
216
217
Returns:
218
str or None: Serial number or None if not available
219
"""
220
221
def getSupportedLanguageList(self):
222
"""
223
Get list of supported language IDs (opens device temporarily).
224
225
Returns:
226
list[int]: List of language IDs
227
"""
228
229
class USBDeviceHandle:
230
def getManufacturer(self):
231
"""
232
Get manufacturer string.
233
234
Returns:
235
str or None: Manufacturer name or None if not available
236
"""
237
238
def getProduct(self):
239
"""
240
Get product string.
241
242
Returns:
243
str or None: Product name or None if not available
244
"""
245
246
def getSerialNumber(self):
247
"""
248
Get serial number string.
249
250
Returns:
251
str or None: Serial number or None if not available
252
"""
253
254
def getSupportedLanguageList(self):
255
"""
256
Get list of supported language IDs.
257
258
Returns:
259
list[int]: List of USB language identifiers
260
"""
261
262
def getStringDescriptor(self, descriptor, lang_id, errors='strict'):
263
"""
264
Get string descriptor in specified language.
265
266
Args:
267
descriptor (int): String descriptor index
268
lang_id (int): Language ID
269
errors (str): Error handling mode ('strict', 'ignore', 'replace')
270
271
Returns:
272
str or None: String content or None if not found
273
"""
274
275
def getASCIIStringDescriptor(self, descriptor, errors='strict'):
276
"""
277
Get string descriptor in first available language as ASCII.
278
279
Args:
280
descriptor (int): String descriptor index
281
errors (str): Error handling mode ('strict', 'ignore', 'replace')
282
283
Returns:
284
str or None: String content or None if not found
285
"""
286
```
287
288
### Configuration Management
289
290
Get and set device configuration, the top-level organizational unit for device functionality.
291
292
```python { .api }
293
class USBDeviceHandle:
294
def getConfiguration(self):
295
"""
296
Get current configuration number.
297
298
Returns:
299
int: Configuration value (1-based, 0 = unconfigured)
300
"""
301
302
def setConfiguration(self, configuration):
303
"""
304
Set device configuration.
305
306
Args:
307
configuration (int): Configuration value (1-based, 0 = unconfigure)
308
309
Raises:
310
USBError: If configuration cannot be set
311
"""
312
```
313
314
### Interface Management
315
316
Claim and release interfaces for exclusive access, and manage alternate settings within interfaces.
317
318
```python { .api }
319
class USBDeviceHandle:
320
def claimInterface(self, interface):
321
"""
322
Claim interface for exclusive access.
323
324
Args:
325
interface (int): Interface number
326
327
Returns:
328
_ReleaseInterface: Context manager that auto-releases on exit
329
330
Raises:
331
USBError: If interface cannot be claimed
332
333
Usage:
334
with handle.claimInterface(0):
335
# perform operations
336
pass
337
# interface automatically released
338
"""
339
340
def releaseInterface(self, interface):
341
"""
342
Release interface, allowing other processes to claim it.
343
344
Args:
345
interface (int): Interface number
346
347
Raises:
348
USBError: If interface cannot be released
349
"""
350
351
def setInterfaceAltSetting(self, interface, alt_setting):
352
"""
353
Set alternate setting for interface.
354
355
Args:
356
interface (int): Interface number
357
alt_setting (int): Alternate setting number
358
359
Raises:
360
USBError: If alternate setting cannot be set
361
"""
362
```
363
364
### Endpoint Management
365
366
Manage endpoint states and clear error conditions.
367
368
```python { .api }
369
class USBDeviceHandle:
370
def clearHalt(self, endpoint):
371
"""
372
Clear halt/stall condition on endpoint.
373
374
Args:
375
endpoint (int): Endpoint address
376
377
Raises:
378
USBError: If halt cannot be cleared
379
"""
380
```
381
382
### Device Reset
383
384
Reset device to initial state, potentially causing disconnection and reconnection.
385
386
```python { .api }
387
class USBDeviceHandle:
388
def resetDevice(self):
389
"""
390
Reset device to initial state.
391
392
Raises:
393
USBErrorNotFound: If device disconnects and must be rediscovered
394
USBError: If reset fails
395
396
Note:
397
May cause device to disconnect and reconnect with new address.
398
"""
399
```
400
401
### Kernel Driver Management
402
403
Manage kernel driver attachment and detachment for interface access on Linux and similar systems.
404
405
```python { .api }
406
class USBDeviceHandle:
407
def kernelDriverActive(self, interface):
408
"""
409
Check if kernel driver is active on interface.
410
411
Args:
412
interface (int): Interface number
413
414
Returns:
415
bool: True if kernel driver is active
416
"""
417
418
def detachKernelDriver(self, interface):
419
"""
420
Detach kernel driver from interface.
421
422
Args:
423
interface (int): Interface number
424
425
Raises:
426
USBError: If driver cannot be detached
427
428
Note:
429
Required on Linux before claiming some interfaces.
430
"""
431
432
def attachKernelDriver(self, interface):
433
"""
434
Re-attach kernel driver to interface.
435
436
Args:
437
interface (int): Interface number
438
439
Raises:
440
USBError: If driver cannot be attached
441
"""
442
443
def setAutoDetachKernelDriver(self, enable):
444
"""
445
Enable/disable automatic kernel driver detachment.
446
447
Args:
448
enable (bool): True to enable auto-detach
449
450
Raises:
451
USBError: If auto-detach cannot be configured
452
"""
453
```
454
455
### Asynchronous Transfer Creation
456
457
Create transfer objects for asynchronous operations.
458
459
```python { .api }
460
class USBDeviceHandle:
461
def getTransfer(self, iso_packets=0, short_is_error=False, add_zero_packet=False):
462
"""
463
Create transfer object for asynchronous operations.
464
465
Args:
466
iso_packets (int): Number of isochronous packet descriptors
467
short_is_error (bool): Treat short transfers as errors
468
add_zero_packet (bool): Add zero-length packet for transfers that are multiples of endpoint size
469
470
Returns:
471
USBTransfer: Transfer object for async operations
472
"""
473
```
474
475
## Usage Examples
476
477
### Basic Device Access
478
479
```python
480
import usb1
481
482
with usb1.USBContext() as context:
483
# Find device by vendor/product ID
484
device = context.getByVendorIDAndProductID(0x1234, 0x5678)
485
if not device:
486
print("Device not found")
487
return
488
489
# Display device information
490
print(f"Device: {device.getVendorID():04x}:{device.getProductID():04x}")
491
print(f"Bus {device.getBusNumber():03d}, Address {device.getDeviceAddress():03d}")
492
print(f"USB {device.getbcdUSB() >> 8}.{(device.getbcdUSB() >> 4) & 0xf}")
493
print(f"Speed: {device.getDeviceSpeed()}")
494
print(f"Class: {device.getDeviceClass()}")
495
496
# Access string descriptors
497
try:
498
print(f"Manufacturer: {device.getManufacturer()}")
499
print(f"Product: {device.getProduct()}")
500
print(f"Serial: {device.getSerialNumber()}")
501
except usb1.USBError as e:
502
print(f"Error reading strings: {e}")
503
```
504
505
### Device Configuration and Interface Claiming
506
507
```python
508
import usb1
509
510
with usb1.USBContext() as context:
511
device = context.getByVendorIDAndProductID(0x1234, 0x5678)
512
if device:
513
with device.open() as handle:
514
# Check current configuration
515
current_config = handle.getConfiguration()
516
print(f"Current configuration: {current_config}")
517
518
# Set configuration if needed
519
if current_config != 1:
520
handle.setConfiguration(1)
521
print("Set configuration to 1")
522
523
# Check for kernel driver and detach if necessary
524
interface_num = 0
525
if handle.kernelDriverActive(interface_num):
526
print("Detaching kernel driver")
527
handle.detachKernelDriver(interface_num)
528
529
# Claim interface with automatic release
530
with handle.claimInterface(interface_num):
531
print(f"Claimed interface {interface_num}")
532
533
# Set alternate setting if needed
534
handle.setInterfaceAltSetting(interface_num, 0)
535
print("Set alternate setting 0")
536
537
# Perform operations here
538
# ...
539
540
print("Interface automatically released")
541
```
542
543
### Comprehensive Device Information
544
545
```python
546
import usb1
547
548
def print_device_info(device):
549
"""Print comprehensive device information."""
550
print(f"\nDevice {device.getVendorID():04x}:{device.getProductID():04x}")
551
print(f" Bus: {device.getBusNumber():03d}")
552
print(f" Address: {device.getDeviceAddress():03d}")
553
print(f" Port path: {' -> '.join(map(str, device.getPortNumberList()))}")
554
print(f" USB version: {device.getbcdUSB() >> 8}.{(device.getbcdUSB() >> 4) & 0xf}")
555
print(f" Device version: {device.getbcdDevice() >> 8}.{(device.getbcdDevice() >> 4) & 0xf}")
556
print(f" Speed: {device.getDeviceSpeed()}")
557
print(f" Class: {device.getDeviceClass()}")
558
print(f" Subclass: {device.getDeviceSubClass()}")
559
print(f" Protocol: {device.getDeviceProtocol()}")
560
print(f" Max packet size (EP0): {device.getMaxPacketSize0()}")
561
print(f" Configurations: {device.getNumConfigurations()}")
562
563
# Try to get string descriptors
564
try:
565
manufacturer = device.getManufacturer()
566
product = device.getProduct()
567
serial = device.getSerialNumber()
568
languages = device.getSupportedLanguageList()
569
570
if manufacturer:
571
print(f" Manufacturer: {manufacturer}")
572
if product:
573
print(f" Product: {product}")
574
if serial:
575
print(f" Serial: {serial}")
576
if languages:
577
print(f" Languages: {[hex(lang) for lang in languages]}")
578
579
except usb1.USBError as e:
580
print(f" Error reading strings: {e}")
581
582
with usb1.USBContext() as context:
583
for device in context.getDeviceIterator(skip_on_error=True):
584
print_device_info(device)
585
```
586
587
### Error Handling and Resource Management
588
589
```python
590
import usb1
591
592
def safe_device_operation(vendor_id, product_id):
593
"""Demonstrate safe device operation with proper error handling."""
594
context = None
595
device = None
596
handle = None
597
598
try:
599
# Create context
600
context = usb1.USBContext()
601
context.open()
602
603
# Find device
604
device = context.getByVendorIDAndProductID(vendor_id, product_id)
605
if not device:
606
print("Device not found")
607
return False
608
609
# Open device
610
handle = device.open()
611
612
# Detach kernel driver if needed
613
interface_num = 0
614
kernel_attached = False
615
616
try:
617
if handle.kernelDriverActive(interface_num):
618
handle.detachKernelDriver(interface_num)
619
kernel_attached = True
620
print("Detached kernel driver")
621
except usb1.USBErrorNotSupported:
622
print("Kernel driver operations not supported")
623
624
# Claim interface
625
interface_claimed = False
626
try:
627
handle.claimInterface(interface_num)
628
interface_claimed = True
629
print("Claimed interface")
630
631
# Perform operations here
632
print("Performing device operations...")
633
634
return True
635
636
except usb1.USBError as e:
637
print(f"Error claiming interface: {e}")
638
return False
639
640
finally:
641
# Clean up in reverse order
642
if interface_claimed:
643
try:
644
handle.releaseInterface(interface_num)
645
print("Released interface")
646
except usb1.USBError as e:
647
print(f"Error releasing interface: {e}")
648
649
if kernel_attached:
650
try:
651
handle.attachKernelDriver(interface_num)
652
print("Re-attached kernel driver")
653
except usb1.USBError as e:
654
print(f"Error re-attaching kernel driver: {e}")
655
656
except usb1.USBError as e:
657
print(f"USB error: {e}")
658
return False
659
660
finally:
661
# Clean up resources
662
if handle:
663
handle.close()
664
if device:
665
device.close()
666
if context:
667
context.close()
668
669
# Usage
670
safe_device_operation(0x1234, 0x5678)
671
```