-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathch9.py
More file actions
518 lines (457 loc) · 15.9 KB
/
ch9.py
File metadata and controls
518 lines (457 loc) · 15.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# This file is part of python-functionfs
# Copyright (C) 2016-2021 Vincent Pelletier <[email protected]>
#
# python-functionfs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# python-functionfs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with python-functionfs. If not, see <http://www.gnu.org/licenses/>.
"""
Python translation of USB-related macros and structures from linux/usb/ch9.h
"""
# pylint: disable=too-few-public-methods
import ctypes
from .common import USBDescriptorHeader, u8, le16, le32
# Translated from linux/usb/ch9.h
# CONTROL REQUEST SUPPORT
# USB directions
#
# This bit flag is used in endpoint descriptors' bEndpointAddress field.
# It's also one of three fields in control requests bRequestType.
USB_DIR_OUT = 0 # to device
USB_DIR_IN = 0x80 # to host
# USB types, the second of three bRequestType fields
USB_TYPE_MASK = 0x03 << 5
USB_TYPE_STANDARD = 0x00 << 5
USB_TYPE_CLASS = 0x01 << 5
USB_TYPE_VENDOR = 0x02 << 5
USB_TYPE_RESERVED = 0x03 << 5
# USB recipients, the third of three bRequestType fields
USB_RECIP_MASK = 0x1f
USB_RECIP_DEVICE = 0x00
USB_RECIP_INTERFACE = 0x01
USB_RECIP_ENDPOINT = 0x02
USB_RECIP_OTHER = 0x03
# From Wireless USB 1.0
USB_RECIP_PORT = 0x04
USB_RECIP_RPIPE = 0x05
# Standard requests, for the bRequest field of a SETUP packet.
#
# These are qualified by the bRequestType field, so that for example
# TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
# by a GET_STATUS request.
USB_REQ_GET_STATUS = 0x00
USB_REQ_CLEAR_FEATURE = 0x01
USB_REQ_SET_FEATURE = 0x03
USB_REQ_SET_ADDRESS = 0x05
USB_REQ_GET_DESCRIPTOR = 0x06
USB_REQ_SET_DESCRIPTOR = 0x07
USB_REQ_GET_CONFIGURATION = 0x08
USB_REQ_SET_CONFIGURATION = 0x09
USB_REQ_GET_INTERFACE = 0x0A
USB_REQ_SET_INTERFACE = 0x0B
USB_REQ_SYNCH_FRAME = 0x0C
USB_REQ_SET_SEL = 0x30
USB_REQ_SET_ISOCH_DELAY = 0x31
USB_REQ_SET_ENCRYPTION = 0x0D # Wireless USB
USB_REQ_GET_ENCRYPTION = 0x0E
USB_REQ_RPIPE_ABORT = 0x0E
USB_REQ_SET_HANDSHAKE = 0x0F
USB_REQ_RPIPE_RESET = 0x0F
USB_REQ_GET_HANDSHAKE = 0x10
USB_REQ_SET_CONNECTION = 0x11
USB_REQ_SET_SECURITY_DATA = 0x12
USB_REQ_GET_SECURITY_DATA = 0x13
USB_REQ_SET_WUSB_DATA = 0x14
USB_REQ_LOOPBACK_DATA_WRITE = 0x15
USB_REQ_LOOPBACK_DATA_READ = 0x16
USB_REQ_SET_INTERFACE_DS = 0x17
# specific requests for USB Power Delivery
USB_REQ_GET_PARTNER_PDO = 20
USB_REQ_GET_BATTERY_STATUS = 21
USB_REQ_SET_PDO = 22
USB_REQ_GET_VDM = 23
USB_REQ_SEND_VDM = 24
# The Link Power Management (LPM) ECN defines USB_REQ_TEST_AND_SET command,
# used by hubs to put ports into a new L1 suspend state, except that it
# forgot to define its number ...
# USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
# are read as a bit array returned by USB_REQ_GET_STATUS. (So there
# are at most sixteen features of each type.) Hubs may also support a
# new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend.
USB_DEVICE_SELF_POWERED = 0 # (read only)
USB_DEVICE_REMOTE_WAKEUP = 1 # dev may initiate wakeup
USB_DEVICE_TEST_MODE = 2 # (wired high speed only)
USB_DEVICE_BATTERY = 2 # (wireless)
USB_DEVICE_B_HNP_ENABLE = 3 # (otg) dev may initiate HNP
USB_DEVICE_WUSB_DEVICE = 3 # (wireless)
USB_DEVICE_A_HNP_SUPPORT = 4 # (otg) RH port supports HNP
USB_DEVICE_A_ALT_HNP_SUPPORT = 5 # (otg) other RH port does
USB_DEVICE_DEBUG_MODE = 6 # (special devices only)
# Test Mode Selectors
# See USB 2.0 spec Table 9-7
TEST_J = 1
TEST_K = 2
TEST_SE0_NAK = 3
TEST_PACKET = 4
TEST_FORCE_EN = 5
# New Feature Selectors as added by USB 3.0
# See USB 3.0 spec Table 9-7
USB_DEVICE_U1_ENABLE = 48 # dev may initiate U1 transition
USB_DEVICE_U2_ENABLE = 49 # dev may initiate U2 transition
USB_DEVICE_LTM_ENABLE = 50 # dev may send LTM
USB_INTRF_FUNC_SUSPEND = 0 # function suspend
USB_INTR_FUNC_SUSPEND_OPT_MASK = 0xFF00
# Suspend Options, Table 9-8 USB 3.0 spec
USB_INTRF_FUNC_SUSPEND_LP = 1 << (8 + 0)
USB_INTRF_FUNC_SUSPEND_RW = 1 << (8 + 1)
# Interface status, Figure 9-5 USB 3.0 spec
USB_INTRF_STAT_FUNC_RW_CAP = 1
USB_INTRF_STAT_FUNC_RW = 2
USB_ENDPOINT_HALT = 0 # IN/OUT will STALL
# Bit array elements as returned by the USB_REQ_GET_STATUS request.
USB_DEV_STAT_U1_ENABLED = 2 # transition into U1 state
USB_DEV_STAT_U2_ENABLED = 3 # transition into U2 state
USB_DEV_STAT_LTM_ENABLED = 4 # Latency tolerance messages
class USBCtrlRequest(ctypes.LittleEndianStructure):
"""
struct usb_ctrlrequest - SETUP data for a USB device control request
@bRequestType: matches the USB bmRequestType field
@bRequest: matches the USB bRequest field
@wValue: matches the USB wValue field (le16 byte order)
@wIndex: matches the USB wIndex field (le16 byte order)
@wLength: matches the USB wLength field (le16 byte order)
This structure is used to send control requests to a USB device. It matches
the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the
USB spec for a fuller description of the different fields, and what they are
used for.
Note that the driver for any interface can issue control requests.
For most devices, interfaces don't coordinate with each other, so
such requests may be made at any time.
"""
_pack_ = 1
_fields_ = [
('bRequestType', u8),
('bRequest', u8),
('wValue', le16),
('wIndex', le16),
('wLength', le16),
]
# STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
# (rarely) accepted by SET_DESCRIPTOR.
#
# Note that all multi-byte values here are encoded in little endian
# byte order "on the wire". Within the kernel and when exposed
# through the Linux-USB APIs, they are not converted to cpu byte
# order; it is the responsibility of the client code to do this.
# The single exception is when device and configuration descriptors (but
# not other descriptors) are read from usbfs (i.e. /proc/bus/usb/BBB/DDD);
# in this case the fields are converted to host endianness by the kernel.
# Descriptor types ... USB 2.0 spec table 9.5
USB_DT_DEVICE = 0x01
USB_DT_CONFIG = 0x02
USB_DT_STRING = 0x03
USB_DT_INTERFACE = 0x04
USB_DT_ENDPOINT = 0x05
USB_DT_DEVICE_QUALIFIER = 0x06
USB_DT_OTHER_SPEED_CONFIG = 0x07
USB_DT_INTERFACE_POWER = 0x08
# these are from a minor usb 2.0 revision (ECN)
USB_DT_OTG = 0x09
USB_DT_DEBUG = 0x0a
USB_DT_INTERFACE_ASSOCIATION = 0x0b
# these are from the Wireless USB spec
USB_DT_SECURITY = 0x0c
USB_DT_KEY = 0x0d
USB_DT_ENCRYPTION_TYPE = 0x0e
USB_DT_BOS = 0x0f
USB_DT_DEVICE_CAPABILITY = 0x10
USB_DT_WIRELESS_ENDPOINT_COMP = 0x11
USB_DT_WIRE_ADAPTER = 0x21
USB_DT_RPIPE = 0x22
USB_DT_CS_RADIO_CONTROL = 0x23
# From the T10 UAS specification
USB_DT_PIPE_USAGE = 0x24
# From the USB 3.0 spec
USB_DT_SS_ENDPOINT_COMP = 0x30
# From the USB 3.1 spec
USB_DT_SSP_ISOC_ENDPOINT_COMP = 0x31
# Conventional codes for class-specific descriptors. The convention is
# defined in the USB "Common Class" Spec (3.11). Individual class specs
# are authoritative for their usage, not the "common class" writeup.
USB_DT_CS_DEVICE = USB_TYPE_CLASS | USB_DT_DEVICE
USB_DT_CS_CONFIG = USB_TYPE_CLASS | USB_DT_CONFIG
USB_DT_CS_STRING = USB_TYPE_CLASS | USB_DT_STRING
USB_DT_CS_INTERFACE = USB_TYPE_CLASS | USB_DT_INTERFACE
USB_DT_CS_ENDPOINT = USB_TYPE_CLASS | USB_DT_ENDPOINT
# USBDescriptorHeader: from common.py
class USBDeviceDescriptor(USBDescriptorHeader):
"""
USB_DT_DEVICE: Device descriptor
"""
_bDescriptorType = USB_DT_DEVICE
_fields_ = [
('bcdUSB', le16),
('bDeviceClass', u8),
('bDeviceSubClass', u8),
('bDeviceProtocol', u8),
('bMaxPacketSize0', u8),
('idVendor', le16),
('idProduct', le16),
('bcdDevice', le16),
('iManufacturer', u8),
('iProduct', u8),
('iSerialNumber', u8),
('bNumConfigurations', u8),
]
USB_DT_DEVICE_SIZE = 18
assert ctypes.sizeof(USBDeviceDescriptor) == USB_DT_DEVICE_SIZE
# Device and/or Interface Class codes
# as found in bDeviceClass or bInterfaceClass
# and defined by www.usb.org documents
USB_CLASS_PER_INTERFACE = 0 # for DeviceClass
USB_CLASS_AUDIO = 1
USB_CLASS_COMM = 2
USB_CLASS_HID = 3
USB_CLASS_PHYSICAL = 5
USB_CLASS_STILL_IMAGE = 6
USB_CLASS_PRINTER = 7
USB_CLASS_MASS_STORAGE = 8
USB_CLASS_HUB = 9
USB_CLASS_CDC_DATA = 0x0a
USB_CLASS_CSCID = 0x0b # chip+ smart card
USB_CLASS_CONTENT_SEC = 0x0d # content security
USB_CLASS_VIDEO = 0x0e
USB_CLASS_WIRELESS_CONTROLLER = 0xe0
USB_CLASS_MISC = 0xef
USB_CLASS_APP_SPEC = 0xfe
USB_CLASS_VENDOR_SPEC = 0xff
USB_SUBCLASS_VENDOR_SPEC = 0xff
class USBConfigDescriptor(USBDescriptorHeader):
"""
USB_DT_CONFIG: Configuration descriptor information.
"""
_bDescriptorType = USB_DT_CONFIG
_fields_ = [
('wTotalLength', le16),
('bNumInterfaces', u8),
('bConfigurationValue', u8),
('iConfiguration', u8),
('bmAttributes', u8),
('bMaxPower', u8),
]
class USBOtherSpeedConfig(USBConfigDescriptor):
"""
USB_DT_OTHER_SPEED_CONFIG: Highspeed-capable devices can look
different depending on what speed they're currently running. Only
devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
descriptors.
"""
_bDescriptorType = USB_DT_OTHER_SPEED_CONFIG
USB_DT_CONFIG_SIZE = 9
assert ctypes.sizeof(USBOtherSpeedConfig) == USB_DT_CONFIG_SIZE
# from config descriptor bmAttributes
USB_CONFIG_ATT_ONE = 1 << 7 # must be set
USB_CONFIG_ATT_SELFPOWER = 1 << 6 # self powered
USB_CONFIG_ATT_WAKEUP = 1 << 5 # can wakeup
USB_CONFIG_ATT_BATTERY = 1 << 4 # battery powered
class USBStringDescriptor(USBConfigDescriptor):
"""
USB_DT_STRING: String descriptor
note that "string" zero is special, it holds language codes that
the device supports, not Unicode characters.
"""
_bDescriptorType = USB_DT_STRING
_fields_ = [
('wData', le16), # UTF-16LE encoded
]
class USBInterfaceDescriptor(USBDescriptorHeader):
"""
USB_DT_INTERFACE: Interface descriptor
"""
_bDescriptorType = USB_DT_INTERFACE
_fields_ = [
('bInterfaceNumber', u8),
('bAlternateSetting', u8),
('bNumEndpoints', u8),
('bInterfaceClass', u8),
('bInterfaceSubClass', u8),
('bInterfaceProtocol', u8),
('iInterface', u8),
]
USB_DT_INTERFACE_SIZE = 9
assert ctypes.sizeof(USBInterfaceDescriptor) == USB_DT_INTERFACE_SIZE
# Audio-less variant comes from functionfs.h
class USBEndpointDescriptorNoAudio(USBDescriptorHeader):
"""
USB_DT_ENDPOINT: Endpoint descriptor without audio fields.
"""
_bDescriptorType = USB_DT_ENDPOINT
_fields_ = [
('bEndpointAddress', u8),
('bmAttributes', u8),
('wMaxPacketSize', le16),
('bInterval', u8),
]
class USBEndpointDescriptor(USBEndpointDescriptorNoAudio):
"""
USB_DT_ENDPOINT: Endpoint descriptor
"""
_fields_ = [
# NOTE: these two are _only_ in audio endpoints.
('bRefresh', u8),
('bSynchAddress', u8),
]
USB_DT_ENDPOINT_SIZE = 7
USB_DT_ENDPOINT_AUDIO_SIZE = 9 # Audio extension
assert ctypes.sizeof(USBEndpointDescriptorNoAudio) == USB_DT_ENDPOINT_SIZE
assert ctypes.sizeof(USBEndpointDescriptor) == USB_DT_ENDPOINT_AUDIO_SIZE
# Endpoints
USB_ENDPOINT_NUMBER_MASK = 0x0f # in bEndpointAddress
USB_ENDPOINT_DIR_MASK = 0x80
USB_ENDPOINT_XFERTYPE_MASK = 0x03 # in bmAttributes
USB_ENDPOINT_XFER_CONTROL = 0
USB_ENDPOINT_XFER_ISOC = 1
USB_ENDPOINT_XFER_BULK = 2
USB_ENDPOINT_XFER_INT = 3
USB_ENDPOINT_MAX_ADJUSTABLE = 0x80
# The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type.
USB_ENDPOINT_INTRTYPE = 0x30
USB_ENDPOINT_INTR_PERIODIC = 0 << 4
USB_ENDPOINT_INTR_NOTIFICATION = 1 << 4
USB_ENDPOINT_SYNCTYPE = 0x0c
USB_ENDPOINT_SYNC_NONE = 0 << 2
USB_ENDPOINT_SYNC_ASYNC = 1 << 2
USB_ENDPOINT_SYNC_ADAPTIVE = 2 << 2
USB_ENDPOINT_SYNC_SYNC = 3 << 2
USB_ENDPOINT_USAGE_MASK = 0x30
USB_ENDPOINT_USAGE_DATA = 0x00
USB_ENDPOINT_USAGE_FEEDBACK = 0x10
USB_ENDPOINT_USAGE_IMPLICIT_FB = 0x20 # Implicit feedback Data endpoint
# XXX: several utility functions, not translated (yet ?)
class USBSSPIsocEndpointDescriptor(USBDescriptorHeader):
"""
USB_DT_SSP_ISOC_ENDPOINT_COMP: SuperSpeedPlus Isochronous Endpoint
Companion descriptor
"""
_bDescriptorType = USB_DT_SSP_ISOC_ENDPOINT_COMP
_fields_ = [
('wReseved', le16),
('dwBytesPerInterval', le32),
]
USB_DT_SSP_ISOC_EP_COMP_SIZE = 8
assert ctypes.sizeof(USBSSPIsocEndpointDescriptor) == USB_DT_SSP_ISOC_EP_COMP_SIZE
class USBSSEPCompDescriptor(USBDescriptorHeader):
"""
USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor
"""
_bDescriptorType = USB_DT_SS_ENDPOINT_COMP
_fields_ = [
('bMaxBurst', u8),
('bmAttributes', u8),
('wBytesPerInterval', le16),
]
def getMaxStreamCount(self):
"""
For a bulk endpoint: return MaxStreams, decoded from bmAttributes.
"""
max_streams = self.bmAttributes & 0x1f
return 1 << max_streams if max_streams else 0
def getIsochronousMultiplier(self):
"""
For isochronous endpoint: return Mult, decoded from bmAttributes.
"""
return 1 + (self.bmAttributes & 0x3)
def hasSuperSpeedPlusCompation(self):
"""
For isochronous endpoint: return whether a SuperSpeedPlus is supposed
to follow, decoded from bmAttributes.
"""
return bool(self.bmAttributes & 0x80)
USB_DT_SS_EP_COMP_SIZE = 6
assert ctypes.sizeof(USBSSEPCompDescriptor) == USB_DT_SS_EP_COMP_SIZE
# pylint: disable=invalid-name, missing-function-docstring
def USB_SS_MULT(value): # BBB: use USBSSEPCompDescriptor.get
return 1 + (value & 0x3)
def USB_SS_SSP_ISOC_COMP(value): # BBB: use USBSSEPCompDescriptor.get
return value & (1 << 7)
# pylint: enable=invalid-name, missing-function-docstring
class USBQualifierDescriptor(USBDescriptorHeader):
"""
USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor
"""
_bDescriptorType = USB_DT_DEVICE_QUALIFIER
_fields_ = [
('bcdUSB', le16),
('bDeviceClass', u8),
('bDeviceSubClass', u8),
('bDeviceProtocol', u8),
('bMaxPacketSize0', u8),
('bNumConfigurations', u8),
('bRESERVED', u8),
]
class USBOTGDescriptor(USBDescriptorHeader):
"""
USB_DT_OTG (from OTG 1.0a supplement)
"""
_bDescriptorType = USB_DT_OTG
_fields_ = [
('bmAttributes', u8),
]
class USBOTG20Descriptor(USBDescriptorHeader):
"""
USB_DT_OTG (from OTG 2.0 supplement)
"""
_bDescriptorType = USB_DT_OTG
_fields_ = [
('bmAttributes', u8),
('bcdOTG', le16),
]
USB_OTG_SRP = 1 << 0
USB_OTG_HNP = 1 << 1
USB_OTG_ADP = 1 << 2
OTG_STS_SELECTOR = 0xf000
class USBDebugDescriptor(USBDescriptorHeader):
"""
USB_DT_DEBUG: for special highspeed devices, replacing serial console
"""
_bDescriptorType = USB_DT_DEBUG
_fields_ = [
('bDebugInEndpoint', u8),
('bDebugOutEndpoint', u8),
]
class USBInterfaceAssocDescriptor(USBDescriptorHeader):
"""
USB_DT_INTERFACE_ASSOCIATION: groups interfaces
"""
_bDescriptorType = USB_DT_INTERFACE_ASSOCIATION
_fields_ = [
('bFirstInterface', u8),
('bInterfaceCount', u8),
('bFunctionClass', u8),
('bFunctionSubClass', u8),
('bFunctionProtocol', u8),
('iFunction', u8),
]
# To be continued...
# Bonus not in ch9.h:
# Feature selectors from Table 9-8 USB Power Delivery spec
USB_DEVICE_BATTERY_WAKE_MASK = 40
USB_DEVICE_OS_IS_PD_AWARE = 41
USB_DEVICE_POLICY_MODE = 42
USB_PORT_PR_SWAP = 43
USB_PORT_GOTO_MIN = 44
USB_PORT_RETURN_POWER = 45
USB_PORT_ACCEPT_PD_REQUEST = 46
USB_PORT_REJECT_PD_REQUEST = 47
USB_PORT_PORT_PD_RESET = 48
USB_PORT_C_PORT_PD_CHANGE = 49
USB_PORT_CABLE_PD_RESET = 50
USB_DEVICE_CHARGING_POLICY = 54