1# Copyright (C) 2021-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import ctypes
7
8import inspectorlib.cdata as cdata
9import inspectorlib.unpack as unpack
10
11# 6.4.2 Small Resource Data Type
12
13class SmallResourceDataTag(cdata.Struct):
14    _pack_ = 1
15    _fields_ = [
16        ('length', ctypes.c_uint8, 3),
17        ('name', ctypes.c_uint8, 4),
18        ('type', ctypes.c_uint8, 1),
19    ]
20
21SMALL_RESOURCE_ITEM_IRQ_FORMAT                    = 0x04
22SMALL_RESOURCE_ITEM_DMA_FORMAT                    = 0x05
23SMALL_RESOURCE_ITEM_START_DEPENDENT_FUNCTIONS     = 0x06
24SMALL_RESOURCE_ITEM_END_DEPENDENT_FUNCTIONS       = 0x07
25SMALL_RESOURCE_ITEM_IO_PORT                       = 0x08
26SMALL_RESOURCE_ITEM_FIXED_LOCATION_IO_PORT        = 0x09
27SMALL_RESOURCE_ITEM_FIXED_DMA                     = 0x0A
28SMALL_RESOURCE_ITEM_VENDOR_DEFINED                = 0x0E
29SMALL_RESOURCE_ITEM_END_TAG                       = 0x0F
30
31# 6.4.2.1 IRQ Descriptor
32
33def SmallResourceItemIRQ_factory(_len=2):
34    class SmallResourceItemIRQ(cdata.Struct):
35        _pack_ = 1
36        _fields_ = SmallResourceDataTag._fields_ + [
37            ('_INT', ctypes.c_uint16),
38        ] + ([
39            ('_HE', ctypes.c_uint8, 1),
40            ('ingored', ctypes.c_uint8, 2),
41            ('_LL', ctypes.c_uint8, 1),
42            ('_SHR', ctypes.c_uint8, 1),
43            ('_WKC', ctypes.c_uint8, 1),
44            ('reserved', ctypes.c_uint8, 2),
45        ] if (_len > 2) else [])
46
47        @property
48        def irqs(self):
49            return [i for i in range(0, 16) if ((self._INT & (1 << i)) != 0)]
50    return SmallResourceItemIRQ
51
52# 6.4.2.2 DMA Descriptor
53
54class SmallResourceItemDMA(cdata.Struct):
55    _pack_ = 1
56    _fields_ = SmallResourceDataTag._fields_ + [
57        ('_DMA', ctypes.c_uint8),
58        ('_SIZ', ctypes.c_uint8, 2),
59        ('_BM', ctypes.c_uint8, 1),
60        ('ignored', ctypes.c_uint8, 2),
61        ('_TYP', ctypes.c_uint8, 2),
62        ('reserved', ctypes.c_uint8, 1),
63    ]
64
65# 6.4.2.3 Start Dependent Functions Descriptor
66
67def SmallResourceItemStartDependentFunctions_factory(_len):
68    class SmallResourceItemStartDependentFunctions(cdata.Struct):
69        _pack_ = 1
70        _fields_ = SmallResourceDataTag._fields_ + ([
71            ('compatibility', ctypes.c_uint8, 2),
72            ('performance', ctypes.c_uint8, 2),
73            ('reserved', ctypes.c_uint8, 4),
74        ] if (_len > 0) else [])
75    return SmallResourceItemStartDependentFunctions
76
77# 6.4.2.4 End Dependent Functions Descriptor
78
79class SmallResourceItemEndDependentFunctions(cdata.Struct):
80    _pack_ = 1
81    _fields_ = SmallResourceDataTag._fields_
82
83# 6.4.2.5 I/O Port Descriptor
84
85io_port_decoding = {
86    0b0: 'Decodes bits[9:0]',
87    0b1: 'Decodes bits[15:0]',
88}
89
90class SmallResourceItemIOPort(cdata.Struct):
91    _pack_ = 1
92    _fields_ = SmallResourceDataTag._fields_ + [
93        ('_DEC', ctypes.c_uint8, 1),
94        ('reserved', ctypes.c_uint8, 7),
95        ('_MIN', ctypes.c_uint16),
96        ('_MAX', ctypes.c_uint16),
97        ('_ALN', ctypes.c_uint8),
98        ('_LEN', ctypes.c_uint8),
99    ]
100    _formats = {
101        '_DEC': unpack.format_table("{}", io_port_decoding)
102    }
103
104# 6.4.2.6 Fixed Location I/O Port Descriptor
105
106class SmallResourceItemFixedLocationIOPort(cdata.Struct):
107    _pack_ = 1
108    _fields_ = SmallResourceDataTag._fields_ + [
109        ('_BAS', ctypes.c_uint16),
110        ('_LEN', ctypes.c_uint8),
111    ]
112
113# 6.4.2.7 Fixed DMA Descriptor
114
115class SmallResourceItemFixedDMA(cdata.Struct):
116    _pack_ = 1
117    _fields_ = SmallResourceDataTag._fields_ + [
118        ('_DMA', ctypes.c_uint16),
119        ('_TYP', ctypes.c_uint16),
120        ('_SIZ', ctypes.c_uint8),
121    ]
122
123# 6.4.2.8 Vendor-Defined Descriptor, Type 0
124
125def SmallResourceItemVendorDefined_factory(_len):
126    class SmallResourceItemVendorDefined(cdata.Struct):
127        _pack_ = 1
128        _fields_ = SmallResourceDataTag._fields_ + [
129            ('data', ctypes.c_uint8 * _len),
130        ]
131    return SmallResourceItemVendorDefined
132
133# 6.4.2.9 End Tag
134
135class SmallResourceItemEndTag(cdata.Struct):
136    _pack_ = 1
137    _fields_ = SmallResourceDataTag._fields_ + [
138        ('checksum', ctypes.c_uint8)
139    ]
140
141# 6.4.3 Large Resource Data Type
142
143class LargeResourceDataTag(cdata.Struct):
144    _pack_ = 1
145    _fields_ = [
146        ('name', ctypes.c_uint8, 7),
147        ('type', ctypes.c_uint8, 1),
148        ('length', ctypes.c_uint16),
149    ]
150
151LARGE_RESOURCE_ITEM_24BIT_MEMORY_RANGE            = 0x01
152LARGE_RESOURCE_ITEM_GENERIC_REGISTER              = 0x02
153LARGE_RESOURCE_ITEM_VENDOR_DEFINED                = 0x04
154LARGE_RESOURCE_ITEM_32BIT_MEMORY_RANGE            = 0x05
155LARGE_RESOURCE_ITEM_32BIT_FIXED_MEMORY_RANGE      = 0x06
156LARGE_RESOURCE_ITEM_ADDRESS_SPACE_RESOURCE        = 0x07
157LARGE_RESOURCE_ITEM_WORD_ADDRESS_SPACE            = 0x08
158LARGE_RESOURCE_ITEM_EXTENDED_INTERRUPT            = 0x09
159LARGE_RESOURCE_ITEM_QWORD_ADDRESS_SPACE           = 0x0A
160LARGE_RESOURCE_ITEM_EXTENDED_ADDRESS_SPACE        = 0x0B
161LARGE_RESOURCE_ITEM_GPIO_CONNECTION               = 0x0C
162LARGE_RESOURCE_ITEM_PIN_FUNCTION                  = 0x0D
163LARGE_RESOURCE_ITEM_GENERIC_SERIAL_BUS_CONNECTION = 0x0E
164LARGE_RESOURCE_ITEM_PIN_CONFIGURATION             = 0x0F
165LARGE_RESOURCE_ITEM_PIN_GROUP                     = 0x10
166LARGE_RESOURCE_ITEM_PIN_GROUP_FUNCTION            = 0x11
167LARGE_RESOURCE_ITEM_PIN_GROUP_CONFIGURATION       = 0x12
168
169# 6.4.3.1 24-Bit Memory Range Descriptor
170
171class LargeResourceItem24BitMemoryRange(cdata.Struct):
172    _pack_ = 1
173    _fields_ = LargeResourceDataTag._fields_ + [
174        ('_RW', ctypes.c_uint8, 1),
175        ('ignored', ctypes.c_uint8, 7),
176        ('_MIN', ctypes.c_uint16),
177        ('_MAX', ctypes.c_uint16),
178        ('_ALN', ctypes.c_uint16),
179        ('_LEN', ctypes.c_uint16),
180    ]
181
182# 6.4.3.2 Vendor-Defined Descriptor, Type 1
183
184def LargeResourceItemVendorDefined_factory(_len):
185    class LargeResourceItemVendorDefined(cdata.Struct):
186        _pack_ = 1
187        _fields_ = SmallResourceDataTag._fields_ + [
188            ('subtype', ctypes.c_uint8),
189            ('UUID', ctypes.c_uint8 * 16),
190            ('data', ctypes.c_uint8 * (_len - 17)),
191        ]
192    return LargeResourceItemVendorDefined
193
194# 6.4.3.3 32-Bit Memory Range Descriptor
195
196class LargeResourceItem32BitMemoryRange(cdata.Struct):
197    _pack_ = 1
198    _fields_ = LargeResourceDataTag._fields_ + [
199        ('_RW', ctypes.c_uint8, 1),
200        ('ignored', ctypes.c_uint8, 7),
201        ('_MIN', ctypes.c_uint32),
202        ('_MAX', ctypes.c_uint32),
203        ('_ALN', ctypes.c_uint32),
204        ('_LEN', ctypes.c_uint32),
205    ]
206
207# 6.4.3.4 32-Bit Fixed Memory Range Descriptor
208
209class LargeResourceItem32BitFixedMemoryRange(cdata.Struct):
210    _pack_ = 1
211    _fields_ = LargeResourceDataTag._fields_ + [
212        ('_RW', ctypes.c_uint8, 1),
213        ('ignored', ctypes.c_uint8, 7),
214        ('_BAS', ctypes.c_uint32),
215        ('_LEN', ctypes.c_uint32),
216    ]
217
218# 6.4.3.5 Address Space Resource Descriptors
219
220resource_type = {
221    0x00: 'Memory range',
222    0x01: 'I/O range',
223    0x02: 'Bus number',
224}
225
226decode_type = {
227    0b0: 'This bridge positively decodes this address',
228    0b1: 'This bridge subtractively decodes this address',
229}
230
231min_address_fixed = {
232    0b0: 'The specified minimum address is not fixed',
233    0b1: 'The specified minimum address is fixed',
234}
235
236max_address_fixed = {
237    0b0: 'The specified maximum address is not fixed',
238    0b1: 'The specified maximum address is fixed',
239}
240
241# 6.4.3.5.1 QWord Address Space Descriptor
242
243def LargeResourceItemQWordAddressSpace_factory(_len=43):
244    class LargeResourceItemQWordAddressSpace(cdata.Struct):
245        _pack_ = 1
246        _fields_ = LargeResourceDataTag._fields_ + [
247            ('_TYP', ctypes.c_uint8),
248            ('ignored', ctypes.c_uint8, 1),
249            ('_DEC', ctypes.c_uint8, 1),
250            ('_MIF', ctypes.c_uint8, 1),
251            ('_MAF', ctypes.c_uint8, 1),
252            ('reserved1', ctypes.c_uint8, 4),
253            ('flags', ctypes.c_uint8),
254            ('_GRA', ctypes.c_uint64),
255            ('_MIN', ctypes.c_uint64),
256            ('_MAX', ctypes.c_uint64),
257            ('_TRA', ctypes.c_uint64),
258            ('_LEN', ctypes.c_uint64),
259        ] + ([
260            ('reserved2', ctypes.c_uint8)
261        ] if (_len > 43) else []) + ([
262            ('resource_source_opt', ctypes.c_char * (_len - 44))
263        ] if (_len > 44) else [])
264        _formats = {
265            '_TYP': unpack.format_table("{}", resource_type),
266            '_DEC': unpack.format_table("{}", decode_type),
267            '_MIF': unpack.format_table("{}", min_address_fixed),
268            '_MAF': unpack.format_table("{}", max_address_fixed),
269        }
270
271        @property
272        def resource_source(self):
273            return getattr(self, "resource_source_opt", None)
274
275    return LargeResourceItemQWordAddressSpace
276
277# 6.4.3.5.2 DWord Address Space Descriptor
278
279def LargeResourceItemDWordAddressSpace_factory(_len=23):
280    class LargeResourceItemDWordAddressSpace(cdata.Struct):
281        _pack_ = 1
282        _fields_ = LargeResourceDataTag._fields_ + [
283            ('_TYP', ctypes.c_uint8),
284            ('ignored', ctypes.c_uint8, 1),
285            ('_DEC', ctypes.c_uint8, 1),
286            ('_MIF', ctypes.c_uint8, 1),
287            ('_MAF', ctypes.c_uint8, 1),
288            ('reserved1', ctypes.c_uint8, 4),
289            ('flags', ctypes.c_uint8),
290            ('_GRA', ctypes.c_uint32),
291            ('_MIN', ctypes.c_uint32),
292            ('_MAX', ctypes.c_uint32),
293            ('_TRA', ctypes.c_uint32),
294            ('_LEN', ctypes.c_uint32),
295        ] + ([
296            ('reserved2', ctypes.c_uint8)
297        ] if (_len > 23) else []) + ([
298            ('resource_source_opt', ctypes.c_char * (_len - 24))
299        ] if (_len > 24) else [])
300        _formats = {
301            '_TYP': unpack.format_table("{}", resource_type),
302            '_DEC': unpack.format_table("{}", decode_type),
303            '_MIF': unpack.format_table("{}", min_address_fixed),
304            '_MAF': unpack.format_table("{}", max_address_fixed),
305        }
306
307        @property
308        def resource_source(self):
309            return getattr(self, "resource_source_opt", None)
310
311    return LargeResourceItemDWordAddressSpace
312
313# 6.4.3.5.3 Word Address Space Descriptor
314
315def LargeResourceItemWordAddressSpace_factory(_len=13):
316    class LargeResourceItemWordAddressSpace(cdata.Struct):
317        _pack_ = 1
318        _fields_ = LargeResourceDataTag._fields_ + [
319            ('_TYP', ctypes.c_uint8),
320            ('ignored', ctypes.c_uint8, 1),
321            ('_DEC', ctypes.c_uint8, 1),
322            ('_MIF', ctypes.c_uint8, 1),
323            ('_MAF', ctypes.c_uint8, 1),
324            ('reserved1', ctypes.c_uint8, 4),
325            ('flags', ctypes.c_uint8),
326            ('_GRA', ctypes.c_uint16),
327            ('_MIN', ctypes.c_uint16),
328            ('_MAX', ctypes.c_uint16),
329            ('_TRA', ctypes.c_uint16),
330            ('_LEN', ctypes.c_uint16),
331        ] + ([
332            ('reserved2', ctypes.c_uint8)
333        ] if (_len > 13) else []) + ([
334            ('resource_source_opt', ctypes.c_char * (_len - 14))
335        ] if (_len > 14) else [])
336        _formats = {
337            '_TYP': unpack.format_table("{}", resource_type),
338            '_DEC': unpack.format_table("{}", decode_type),
339            '_MIF': unpack.format_table("{}", min_address_fixed),
340            '_MAF': unpack.format_table("{}", max_address_fixed),
341        }
342
343        @property
344        def resource_source(self):
345            return getattr(self, "resource_source_opt", None)
346
347    return LargeResourceItemWordAddressSpace
348
349# 6.4.3.5.4 Extended Address Space Descriptor
350
351class LargeResourceItemExtendedAddressSpace(cdata.Struct):
352    _pack_ = 1
353    _fields_ = LargeResourceDataTag._fields_ + [
354        ('_TYP', ctypes.c_uint8),
355        ('ignored', ctypes.c_uint8, 1),
356        ('_DEC', ctypes.c_uint8, 1),
357        ('_MIF', ctypes.c_uint8, 1),
358        ('_MAF', ctypes.c_uint8, 1),
359        ('reserved1', ctypes.c_uint8, 4),
360        ('flags', ctypes.c_uint8),
361        ('revision', ctypes.c_uint8),
362        ('reserved2', ctypes.c_uint8),
363        ('_GRA', ctypes.c_uint64),
364        ('_MIN', ctypes.c_uint64),
365        ('_MAX', ctypes.c_uint64),
366        ('_TRA', ctypes.c_uint64),
367        ('_LEN', ctypes.c_uint64),
368        ('_ATT', ctypes.c_uint64),
369    ]
370    _formats = {
371        '_TYP': unpack.format_table("{}", resource_type),
372        '_DEC': unpack.format_table("{}", decode_type),
373        '_MIF': unpack.format_table("{}", min_address_fixed),
374        '_MAF': unpack.format_table("{}", max_address_fixed),
375    }
376
377# 6.4.3.6 Extended Interrupt Descriptor
378
379def LargeResourceItemExtendedInterrupt_factory(_addr):
380    class LargeResourceItemExtendedInterruptLayout(cdata.Struct):
381        _pack_ = 1
382        _fields_ = LargeResourceDataTag._fields_ + [
383            ('flags', ctypes.c_uint8),
384            ('_LEN', ctypes.c_uint8),
385        ]
386
387    def aux(layout):
388        class LargeResourceItemExtendedInterrupt(cdata.Struct):
389            _pack_ = 1
390            _fields_ = LargeResourceDataTag._fields_ + [
391                ('_CP', ctypes.c_uint8, 1),
392                ('_HE', ctypes.c_uint8, 1),
393                ('_LL', ctypes.c_uint8, 1),
394                ('_SHR', ctypes.c_uint8, 1),
395                ('_WKC', ctypes.c_uint8, 1),
396                ('reserved1', ctypes.c_uint8, 3),
397                ('_LEN', ctypes.c_uint8),
398                ('_INT', ctypes.c_uint32 * layout._LEN),
399            ] + ([
400                ('reserved2', ctypes.c_uint8),
401            ] if (layout.length > 2 + layout._LEN * 4) else []) + ([
402                ('resource_source_opt', ctypes.c_char * (layout.length - layout._LEN * 4 - 3))
403            ] if (layout.length > 2 + layout._LEN * 4 + 1) else [])
404
405            @property
406            def resource_source(self):
407                return getattr(self, "resource_source_opt", None)
408
409        return LargeResourceItemExtendedInterrupt
410
411    return aux(LargeResourceItemExtendedInterruptLayout.from_address(_addr))
412
413# 6.4.3.7 Generic Register Descriptor
414
415class LargeResourceItemGenericRegister(cdata.Struct):
416    _pack_ = 1
417    _fields_ = LargeResourceDataTag._fields_ + [
418        ('_ASI', ctypes.c_uint8),
419        ('_RBW', ctypes.c_uint8),
420        ('_RBO', ctypes.c_uint8),
421        ('_ASZ', ctypes.c_uint8),
422        ('_ADR', ctypes.c_uint64),
423    ]
424
425# 6.4.3.8.1 GPIO Connection Descriptor
426
427def LargeResourceItemGPIOConnection_factory(_addr):
428    class LargeResourceItemGPIOConnectionLayout(cdata.Struct):
429        _pack_ = 1
430        _fields_ = LargeResourceDataTag._fields_ + [
431            ('revision_id', ctypes.c_uint8),
432            ('connection_type', ctypes.c_uint8),
433            # Byte 5 to 13 (both inclusive) are not involved in detecting the layout of the descriptor
434            ('data1', ctypes.c_uint8 * 9),
435            ('pin_table_offset', ctypes.c_uint16),
436            ('data2', ctypes.c_uint8),
437            ('resource_source_name_offset', ctypes.c_uint16),
438            ('vendor_data_offset', ctypes.c_uint16),
439            ('vendor_data_length', ctypes.c_uint16),
440        ]
441
442    def aux(layout):
443        if layout.connection_type == 0:  # Interrupt connection
444            interrupt_and_io_flags_fields = [
445                ('_MOD', ctypes.c_uint16, 1),
446                ('_POL', ctypes.c_uint16, 2),
447                ('_SHR', ctypes.c_uint16, 1),
448                ('_WKC', ctypes.c_uint16, 1),
449                ('reserved2', ctypes.c_uint16, 11),
450            ]
451        elif layout.connection_type == 1:  # I/O connection
452            interrupt_and_io_flags_fields = [
453                ('_IOR', ctypes.c_uint16, 1),
454                ('reserved2_1', ctypes.c_uint16, 2),
455                ('_SHR', ctypes.c_uint16, 1),
456                ('reserved2_2', ctypes.c_uint16, 12),
457            ]
458        else:
459            interrupt_and_io_flags_fields = [('interrupt_and_io_flags', ctypes.c_uint16)]
460
461        pre_pin_table_length = layout.pin_table_offset - 23
462        pin_count = (layout.resource_source_name_offset - layout.pin_table_offset) // 2
463        resource_source_name_length = layout.vendor_data_offset - layout.resource_source_name_offset
464
465        class LargeResourceItemGPIOConnection(cdata.Struct):
466            _pack_ = 1
467            _fields_ = LargeResourceDataTag._fields_ + [
468                ('revision_id', ctypes.c_uint8),
469                ('connection_type', ctypes.c_uint8),
470                ('consumer_producer', ctypes.c_uint16, 1),
471                ('reserved1', ctypes.c_uint16, 15),
472            ] + interrupt_and_io_flags_fields + [
473                ('_PPI', ctypes.c_uint8),
474                ('_DRS', ctypes.c_uint16),
475                ('_DBT', ctypes.c_uint16),
476                ('pin_table_offset', ctypes.c_uint16),
477                ('resource_source_index', ctypes.c_uint8),
478                ('resource_source_name_offset', ctypes.c_uint16),
479                ('vendor_data_offset', ctypes.c_uint16),
480                ('vendor_data_length', ctypes.c_uint16),
481            ] + ([
482                ('reserved3', ctypes.c_uint8 * pre_pin_table_length),
483            ] if pre_pin_table_length > 0 else []) + [
484                ('pin_numbers', ctypes.c_uint16 * pin_count),
485                ('resource_source', ctypes.c_char * resource_source_name_length)
486            ] + ([
487                ('_VEN', ctypes.c_uint8 * layout.vendor_data_length)
488            ] if layout.vendor_data_length > 0 else [])
489
490        return LargeResourceItemGPIOConnection
491
492    return aux(LargeResourceItemGPIOConnectionLayout.from_address(_addr))
493
494# 6.4.3.8.2 GenericSerialBus Connection Descriptors
495
496def LargeResourceItemGenericSerialBusConnection_factory(_addr):
497    class LargeResourceItemGenericSerialBusConnectionLayout(cdata.Struct):
498        _pack_ = 1
499        _fields_ = LargeResourceDataTag._fields_ + [
500            # Byte 3 to 9 (both inclusive) are not involved in detecting the layout of the descriptor
501            ('data', ctypes.c_uint8 * 7),
502            ('type_data_length', ctypes.c_uint16),
503        ]
504
505    def aux(layout):
506        class LargeResourceItemGenericSerialBusConnection(cdata.Struct):
507            _pack_ = 1
508            _fields_ = LargeResourceDataTag._fields_ + [
509                ('revision_id', ctypes.c_uint8),
510                ('resource_source_index', ctypes.c_uint8),
511                ('serial_bus_type', ctypes.c_uint8),
512                ('_SLV', ctypes.c_uint8, 1),
513                ('consumer_producer', ctypes.c_uint8, 1),
514                ('_SHR', ctypes.c_uint8, 1),
515                ('reserved', ctypes.c_uint8, 5),
516                ('type_specific_flags', ctypes.c_uint16),
517                ('type_specific_revision_id', ctypes.c_uint8),
518                ('type_data_length', ctypes.c_uint16),
519                ('type_specific_data', ctypes.c_uint8 * layout.type_data_length),
520                ('resource_source', ctypes.c_char * (layout.length - 9 - layout.type_data_length)),
521            ]
522
523        return LargeResourceItemGenericSerialBusConnection
524
525    return aux(LargeResourceItemGenericSerialBusConnectionLayout.from_address(_addr))
526
527# 6.4.3.9 Pin Function Descriptor
528
529def LargeResourceItemPinFunction_factory(_len):
530    class LargeResourceItemPinFunction(cdata.Struct):
531        _pack_ = 1
532        _fields_ = LargeResourceDataTag._fields_ + [
533            ('_REV', ctypes.c_uint8),
534            ('_SHR', ctypes.c_uint8, 1),
535            ('reserved1', ctypes.c_uint16, 15),
536            ('_PPC', ctypes.c_uint8),
537            ('_FUN', ctypes.c_uint16),
538            ('_PTO', ctypes.c_uint16),
539            ('reserved2', ctypes.c_uint8),
540            ('_RNI', ctypes.c_uint16),
541            ('_VDO', ctypes.c_uint16),
542            ('_VDL', ctypes.c_uint16),
543            ('data', ctypes.c_uint8 * (_len - 18)),
544        ]
545    return LargeResourceItemPinFunction
546
547# 6.4.3.10 Pin Configuration Descriptor
548
549def LargeResourceItemPinConfiguration_factory(_len):
550    class LargeResourceItemPinConfiguration(cdata.Struct):
551        _pack_ = 1
552        _fields_ = LargeResourceDataTag._fields_ + [
553            ('_REV', ctypes.c_uint8),
554            ('_SHR', ctypes.c_uint8, 1),
555            ('_CP', ctypes.c_uint8, 1),
556            ('reserved1', ctypes.c_uint16, 14),
557            ('_TYP', ctypes.c_uint8),
558            ('_VAL', ctypes.c_uint32),
559            ('_PTO', ctypes.c_uint16),
560            ('reserved2', ctypes.c_uint8),
561            ('_RNO', ctypes.c_uint16),
562            ('_VDO', ctypes.c_uint16),
563            ('_VDL', ctypes.c_uint16),
564            ('data', ctypes.c_uint8 * (_len - 20)),
565        ]
566    return LargeResourceItemPinConfiguration
567
568# 6.4.3.11 Pin Group Descriptor
569
570def LargeResourceItemPinGroup_factory(_len):
571    class LargeResourceItemPinGroup(cdata.Struct):
572        _pack_ = 1
573        _fields_ = LargeResourceDataTag._fields_ + [
574            ('_REV', ctypes.c_uint8),
575            ('_CP', ctypes.c_uint8, 1),
576            ('reserved1', ctypes.c_uint16, 15),
577            ('_PTO', ctypes.c_uint16),
578            ('_RLO', ctypes.c_uint16),
579            ('_VDO', ctypes.c_uint16),
580            ('_VDL', ctypes.c_uint16),
581            ('data', ctypes.c_uint8 * (_len - 14)),
582        ]
583    return LargeResourceItemPinGroup
584
585# 6.4.3.12 Pin Group Function Descriptor
586
587def LargeResourceItemPinGroupFunction_factory(_len):
588    class LargeResourceItemPinGroupFunction(cdata.Struct):
589        _pack_ = 1
590        _fields_ = LargeResourceDataTag._fields_ + [
591            ('_REV', ctypes.c_uint8),
592            ('_SHR', ctypes.c_uint8, 1),
593            ('_CP', ctypes.c_uint8, 1),
594            ('reserved1', ctypes.c_uint16, 14),
595            ('_FUN', ctypes.c_uint16),
596            ('reserved2', ctypes.c_uint8),
597            ('_RNI', ctypes.c_uint16),
598            ('_RLO', ctypes.c_uint16),
599            ('_VDO', ctypes.c_uint16),
600            ('_VDL', ctypes.c_uint16),
601            ('data', ctypes.c_uint8 * (_len - 17)),
602        ]
603    return LargeResourceItemPinGroupFunction
604
605# 6.4.3.13 Pin Group Configuration Descriptor
606
607def LargeResourceItemPinGroupConfiguration_factory(_len):
608    class LargeResourceItemPinGroupConfiguration(cdata.Struct):
609        _pack_ = 1
610        _fields_ = LargeResourceDataTag._fields_ + [
611            ('_REV', ctypes.c_uint8),
612            ('_SHR', ctypes.c_uint8, 1),
613            ('_CP', ctypes.c_uint8, 1),
614            ('reserved1', ctypes.c_uint16, 14),
615            ('_TYP', ctypes.c_uint8),
616            ('_VAL', ctypes.c_uint32),
617            ('reserved2', ctypes.c_uint8),
618            ('_RNO', ctypes.c_uint16),
619            ('_RLO', ctypes.c_uint16),
620            ('_VDO', ctypes.c_uint16),
621            ('_VDL', ctypes.c_uint16),
622            ('data', ctypes.c_uint8 * (_len - 20)),
623        ]
624    return LargeResourceItemPinGroupConfiguration
625
626# The parser
627
628def rdt_item_list(addr, length):
629    end = addr + length
630    field_list = list()
631    item_num = 0
632    while addr < end:
633        item_num += 1
634        tag = SmallResourceDataTag.from_address(addr)
635        if tag.type == 0:  # Small type
636            if tag.name == SMALL_RESOURCE_ITEM_IRQ_FORMAT:
637                cls = SmallResourceItemIRQ_factory(tag.length)
638            elif tag.name == SMALL_RESOURCE_ITEM_DMA_FORMAT:
639                cls = SmallResourceItemDMA
640            elif tag.name == SMALL_RESOURCE_ITEM_START_DEPENDENT_FUNCTIONS:
641                cls = SmallResourceItemStartDependentFunctions_factory(tag.length)
642            elif tag.name == SMALL_RESOURCE_ITEM_END_DEPENDENT_FUNCTIONS:
643                cls = SmallResourceItemEndDependentFunctions
644            elif tag.name == SMALL_RESOURCE_ITEM_IO_PORT:
645                cls = SmallResourceItemIOPort
646            elif tag.name == SMALL_RESOURCE_ITEM_FIXED_LOCATION_IO_PORT:
647                cls = SmallResourceItemFixedLocationIOPort
648            elif tag.name == SMALL_RESOURCE_ITEM_FIXED_DMA:
649                cls = SmallResourceItemFixedDMA
650            elif tag.name == SMALL_RESOURCE_ITEM_VENDOR_DEFINED:
651                cls = SmallResourceItemVendorDefined_factory(tag.length)
652            elif tag.name == SMALL_RESOURCE_ITEM_END_TAG:
653                cls = SmallResourceItemEndTag
654            else:
655                raise NotImplementedError(f"Unknown small resource item name: {tag.name}, offset {addr}")
656            size = ctypes.sizeof(cls)
657            assert size == tag.length + 1, f"{cls}: {size} != {tag.length} + 1"
658            addr += size
659        else:              # Large type
660            tag = LargeResourceDataTag.from_address(addr)
661            if tag.name == LARGE_RESOURCE_ITEM_24BIT_MEMORY_RANGE:
662                cls = LargeResourceItem24BitMemoryRange
663            elif tag.name == LARGE_RESOURCE_ITEM_GENERIC_REGISTER:
664                cls = LargeResourceItemGenericRegister
665            elif tag.name == LARGE_RESOURCE_ITEM_VENDOR_DEFINED:
666                cls = LargeResourceItemVendorDefined_factory(tag.length)
667            elif tag.name == LARGE_RESOURCE_ITEM_32BIT_MEMORY_RANGE:
668                cls = LargeResourceItem32BitMemoryRange
669            elif tag.name == LARGE_RESOURCE_ITEM_32BIT_FIXED_MEMORY_RANGE:
670                cls = LargeResourceItem32BitFixedMemoryRange
671            elif tag.name == LARGE_RESOURCE_ITEM_ADDRESS_SPACE_RESOURCE:
672                cls = LargeResourceItemDWordAddressSpace_factory(tag.length)
673            elif tag.name == LARGE_RESOURCE_ITEM_WORD_ADDRESS_SPACE:
674                cls = LargeResourceItemWordAddressSpace_factory(tag.length)
675            elif tag.name == LARGE_RESOURCE_ITEM_EXTENDED_INTERRUPT:
676                cls = LargeResourceItemExtendedInterrupt_factory(addr)
677            elif tag.name == LARGE_RESOURCE_ITEM_QWORD_ADDRESS_SPACE:
678                cls = LargeResourceItemQWordAddressSpace_factory(tag.length)
679            elif tag.name == LARGE_RESOURCE_ITEM_EXTENDED_ADDRESS_SPACE:
680                cls = LargeResourceItemExtendedAddressSpace
681            elif tag.name == LARGE_RESOURCE_ITEM_GPIO_CONNECTION:
682                cls = LargeResourceItemGPIOConnection_factory(addr)
683            elif tag.name == LARGE_RESOURCE_ITEM_PIN_FUNCTION:
684                cls = LargeResourceItemPinFunction_factory(tag.length)
685            elif tag.name == LARGE_RESOURCE_ITEM_GENERIC_SERIAL_BUS_CONNECTION:
686                cls = LargeResourceItemGenericSerialBusConnection_factory(addr)
687            elif tag.name == LARGE_RESOURCE_ITEM_PIN_CONFIGURATION:
688                cls = LargeResourceItemPinConfiguration_factory(tag.length)
689            elif tag.name == LARGE_RESOURCE_ITEM_PIN_GROUP:
690                cls = LargeResourceItemPinGroup_factory(tag.length)
691            elif tag.name == LARGE_RESOURCE_ITEM_PIN_GROUP_FUNCTION:
692                cls = LargeResourceItemPinGroupFunction_factory(tag.length)
693            elif tag.name == LARGE_RESOURCE_ITEM_PIN_GROUP_CONFIGURATION:
694                cls = LargeResourceItemPinGroupConfiguration_factory(tag.length)
695            else:
696                raise NotImplementedError(f"Unknown Large resource item name: {tag.name}, offset {addr}")
697            size = ctypes.sizeof(cls)
698            assert size == tag.length + 3, f"{cls}: {size} != {tag.length} + 3"
699            addr += size
700        field_list.append((f'item{item_num}', cls))
701    return field_list
702
703def rdt_factory(field_list):
704
705    class items(cdata.Struct):
706        _pack_ = 1
707        _fields_ = field_list
708
709        def __iter__(self):
710            for f in self._fields_:
711                yield getattr(self, f[0])
712
713        def __getitem__(self, index):
714            return getattr(self, self._fields_[index][0])
715
716    class ResourceData(cdata.Struct):
717        _pack_ = 1
718        _fields_ = [
719            ('items', items)
720        ]
721    return ResourceData
722
723def parse_resource_data(data):
724    """Parse ACPI resource data types returned by _CRS, _PRS and _SRS control methods."""
725    buf = ctypes.create_string_buffer(bytes(data), len(data))
726    addr = ctypes.addressof(buf)
727    item_list = rdt_item_list(addr, len(data))
728    return rdt_factory(item_list).from_buffer_copy(data)
729