2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/bus/pci/pci/id.c
5 * PURPOSE: PCI Device Identification
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
17 /* FUNCTIONS ******************************************************************/
21 PciGetDescriptionMessage(IN ULONG Identifier
,
24 PMESSAGE_RESOURCE_ENTRY Entry
;
26 PWCHAR Description
, Buffer
;
27 ANSI_STRING MessageString
;
28 UNICODE_STRING UnicodeString
;
31 /* Find the message identifier in the message table */
32 MessageString
.Buffer
= NULL
;
33 Status
= RtlFindMessage(PciDriverObject
->DriverStart
,
34 11, // RT_MESSAGETABLE
38 if (!NT_SUCCESS(Status
)) return NULL
;
40 /* Check if the resource data is Unicode or ANSI */
41 if (Entry
->Flags
& MESSAGE_RESOURCE_UNICODE
)
43 /* Subtract one space for the end-of-message terminator */
44 TextLength
= Entry
->Length
-
45 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY
, Text
) -
49 Description
= (PWCHAR
)Entry
->Text
;
51 /* Validate valid message length, ending with a newline character */
52 ASSERT(TextLength
> 1);
53 ASSERT(Description
[TextLength
/ sizeof(WCHAR
)] == L
'\n');
55 /* Allocate the buffer to hold the message string */
56 Buffer
= ExAllocatePoolWithTag(PagedPool
, TextLength
, 'BicP');
57 if (!Buffer
) return NULL
;
59 /* Copy the message, minus the newline character, and terminate it */
60 RtlCopyMemory(Buffer
, Entry
->Text
, TextLength
- 1);
61 Buffer
[TextLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
63 /* Return the length to the caller, minus the terminating NULL */
64 if (Length
) *Length
= TextLength
- 1;
68 /* Initialize the entry as a string */
69 RtlInitAnsiString(&MessageString
, (PCHAR
)Entry
->Text
);
71 /* Remove the newline character */
72 MessageString
.Length
-= sizeof(CHAR
);
74 /* Convert it to Unicode */
75 RtlAnsiStringToUnicodeString(&UnicodeString
, &MessageString
, TRUE
);
76 Buffer
= UnicodeString
.Buffer
;
78 /* Return the length to the caller */
79 if (Length
) *Length
= UnicodeString
.Length
;
82 /* Return the message buffer to the caller */
88 PciGetDeviceDescriptionMessage(IN UCHAR BaseClass
,
94 /* The message identifier in the table is encoded based on the PCI class */
95 Identifier
= (BaseClass
<< 8) | SubClass
;
97 /* Go grab the description message for this device */
98 Message
= PciGetDescriptionMessage(Identifier
, NULL
);
101 /* It wasn't found, allocate a buffer for a generic description */
102 Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(L
"PCI Device"), 'bicP');
103 if (Message
) RtlCopyMemory(Message
, L
"PCI Device", sizeof(L
"PCI Device"));
106 /* Return the description message */
112 PciInitIdBuffer(IN PPCI_ID_BUFFER IdBuffer
)
114 /* Initialize the sizes to zero and the pointer to the start of the buffer */
115 IdBuffer
->TotalLength
= 0;
117 IdBuffer
->CharBuffer
= IdBuffer
->BufferData
;
122 PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer
,
127 PANSI_STRING AnsiString
;
129 va_start(va
, Format
);
130 ASSERT(IdBuffer
->Count
< MAX_ANSI_STRINGS
);
132 /* Do the actual string formatting into the character buffer */
133 vsprintf(IdBuffer
->CharBuffer
, Format
, va
);
135 /* Initialize the ANSI_STRING that will hold this string buffer */
136 AnsiString
= &IdBuffer
->Strings
[IdBuffer
->Count
];
137 RtlInitAnsiString(AnsiString
, IdBuffer
->CharBuffer
);
139 /* Calculate the final size of the string, in Unicode */
140 Size
= RtlAnsiStringToUnicodeSize(AnsiString
);
142 /* Update hte buffer with the size,and update the character pointer */
143 IdBuffer
->StringSize
[IdBuffer
->Count
] = Size
;
144 IdBuffer
->TotalLength
+= Size
;
145 Length
= AnsiString
->Length
+ sizeof(ANSI_NULL
);
146 IdBuffer
->CharBuffer
+= Length
;
148 /* Move to the next string for next time */
151 /* Return the length */
157 PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer
,
161 ULONG NextId
, Size
, Length
, MaxLength
;
162 PANSI_STRING AnsiString
;
164 va_start(va
, Format
);
165 ASSERT(IdBuffer
->Count
);
167 /* Choose the next static ANSI_STRING to use */
168 NextId
= IdBuffer
->Count
- 1;
170 /* Max length is from the end of the buffer up until the current pointer */
171 MaxLength
= (PCHAR
)(IdBuffer
+ 1) - IdBuffer
->CharBuffer
;
173 /* Do the actual append, and return the length this string took */
174 Length
= vsprintf(IdBuffer
->CharBuffer
- 1, Format
, va
);
175 ASSERT(Length
< MaxLength
);
177 /* Select the static ANSI_STRING, and update its length information */
178 AnsiString
= &IdBuffer
->Strings
[NextId
];
179 AnsiString
->Length
+= Length
;
180 AnsiString
->MaximumLength
+= Length
;
182 /* Calculate the final size of the string, in Unicode */
183 Size
= RtlAnsiStringToUnicodeSize(AnsiString
);
185 /* Update the buffer with the size, and update the character pointer */
186 IdBuffer
->StringSize
[NextId
] = Size
;
187 IdBuffer
->TotalLength
+= Size
;
188 IdBuffer
->CharBuffer
+= Length
;
190 /* Return the size */
196 PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension
,
197 IN BUS_QUERY_ID_TYPE QueryType
,
201 CHAR VendorString
[22];
202 PPCI_PDO_EXTENSION PdoExtension
;
203 PPCI_FDO_EXTENSION ParentExtension
;
207 PANSI_STRING NextString
;
208 UNICODE_STRING DestinationString
;
209 PCI_ID_BUFFER IdBuffer
;
213 Status
= STATUS_SUCCESS
;
216 /* Start with the genric vendor string, which is the vendor ID + device ID */
217 sprintf(VendorString
,
218 "PCI\\VEN_%04X&DEV_%04X",
219 DeviceExtension
->VendorId
,
220 DeviceExtension
->DeviceId
);
222 /* Initialize the PCI ID Buffer */
223 PciInitIdBuffer(&IdBuffer
);
225 /* Build the subsystem ID as shown in PCI ID Strings */
226 SubsysId
= DeviceExtension
->SubsystemVendorId
| (DeviceExtension
->SubsystemId
<< 16);
228 /* Check what the caller is requesting */
231 case BusQueryDeviceID
:
233 /* A single ID, the vendor string + the revision ID */
234 PciIdPrintf(&IdBuffer
,
235 "%s&SUBSYS_%08X&REV_%02X",
238 DeviceExtension
->RevisionId
);
241 case BusQueryHardwareIDs
:
243 /* First the vendor string + the subsystem ID + the revision ID */
244 PciIdPrintf(&IdBuffer
,
245 "%s&SUBSYS_%08X&REV_%02X",
248 DeviceExtension
->RevisionId
);
250 /* Next, without the revision */
251 PciIdPrintf(&IdBuffer
,
256 /* Next, the vendor string + the base class + sub class + progif */
257 PciIdPrintf(&IdBuffer
,
258 "%s&CC_%02X%02X%02X",
260 DeviceExtension
->BaseClass
,
261 DeviceExtension
->SubClass
,
262 DeviceExtension
->ProgIf
);
264 /* Next, without the progif */
265 PciIdPrintf(&IdBuffer
,
268 DeviceExtension
->BaseClass
,
269 DeviceExtension
->SubClass
);
271 /* And finally, a terminator */
272 PciIdPrintf(&IdBuffer
, "\0");
275 case BusQueryCompatibleIDs
:
277 /* First, the vendor + revision ID only */
278 PciIdPrintf(&IdBuffer
,
281 DeviceExtension
->RevisionId
);
283 /* Next, the vendor string alone */
284 PciIdPrintf(&IdBuffer
, "%s", VendorString
);
286 /* Next, the vendor ID + the base class + the sub class + progif */
287 PciIdPrintf(&IdBuffer
,
288 "PCI\\VEN_%04X&CC_%02X%02X%02X",
289 DeviceExtension
->VendorId
,
290 DeviceExtension
->BaseClass
,
291 DeviceExtension
->SubClass
,
292 DeviceExtension
->ProgIf
);
294 /* Now without the progif */
295 PciIdPrintf(&IdBuffer
,
296 "PCI\\VEN_%04X&CC_%02X%02X",
297 DeviceExtension
->VendorId
,
298 DeviceExtension
->BaseClass
,
299 DeviceExtension
->SubClass
);
301 /* And then just the vendor ID itself */
302 PciIdPrintf(&IdBuffer
,
304 DeviceExtension
->VendorId
);
306 /* Then the base class + subclass + progif, without any vendor */
307 PciIdPrintf(&IdBuffer
,
308 "PCI\\CC_%02X%02X%02X",
309 DeviceExtension
->BaseClass
,
310 DeviceExtension
->SubClass
,
311 DeviceExtension
->ProgIf
);
313 /* Next, without the progif */
314 PciIdPrintf(&IdBuffer
,
316 DeviceExtension
->BaseClass
,
317 DeviceExtension
->SubClass
);
319 /* And finally, a terminator */
320 PciIdPrintf(&IdBuffer
, "\0");
323 case BusQueryInstanceID
:
325 /* Start with a terminator */
326 PciIdPrintf(&IdBuffer
, "\0");
328 /* And then encode the device and function number */
329 PciIdPrintfAppend(&IdBuffer
,
331 (DeviceExtension
->Slot
.u
.bits
.DeviceNumber
<< 3) |
332 DeviceExtension
->Slot
.u
.bits
.FunctionNumber
);
334 /* Loop every parent until the root */
335 ParentExtension
= DeviceExtension
->ParentFdoExtension
;
336 while (!PCI_IS_ROOT_FDO(ParentExtension
))
338 /* And encode the parent's device and function number as well */
339 PdoExtension
= ParentExtension
->PhysicalDeviceObject
->DeviceExtension
;
340 PciIdPrintfAppend(&IdBuffer
,
342 (PdoExtension
->Slot
.u
.bits
.DeviceNumber
<< 3) |
343 PdoExtension
->Slot
.u
.bits
.FunctionNumber
);
349 /* Unknown query type */
350 DPRINT1("PciQueryId expected ID type = %d\n", QueryType
);
351 return STATUS_NOT_SUPPORTED
;
354 /* Something should've been generated if this has been reached */
355 ASSERT(IdBuffer
.Count
> 0);
357 /* Allocate the final string buffer to hold the ID */
358 StringBuffer
= ExAllocatePoolWithTag(PagedPool
, IdBuffer
.TotalLength
, 'BicP');
359 if (!StringBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
361 /* Build the UNICODE_STRING structure for it */
362 DPRINT1("PciQueryId(%d)\n", QueryType
);
363 DestinationString
.Buffer
= StringBuffer
;
364 DestinationString
.MaximumLength
= IdBuffer
.TotalLength
;
366 /* Loop every ID in the buffer */
367 for (i
= 0; i
< IdBuffer
.Count
; i
++)
369 /* Select the ANSI_STRING for the ID */
370 NextString
= &IdBuffer
.Strings
[i
];
371 DPRINT1(" <- \"%s\"\n", NextString
->Buffer
);
373 /* Convert it to a UNICODE_STRING */
374 Status
= RtlAnsiStringToUnicodeString(&DestinationString
, NextString
, FALSE
);
375 ASSERT(NT_SUCCESS(Status
));
377 /* Add it into the final destination buffer */
378 Size
= IdBuffer
.StringSize
[i
];
379 DestinationString
.MaximumLength
-= Size
;
380 DestinationString
.Buffer
+= (Size
/ sizeof(WCHAR
));
383 /* Return the buffer to the caller and return status (should be success) */
384 *Buffer
= StringBuffer
;
390 PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension
,
391 IN DEVICE_TEXT_TYPE QueryType
,
395 PWCHAR MessageBuffer
, LocationBuffer
;
399 UNREFERENCED_PARAMETER(Locale
);
401 /* Check what the caller is requesting */
404 case DeviceTextDescription
:
406 /* Get the message from the resource section */
407 MessageBuffer
= PciGetDeviceDescriptionMessage(PdoExtension
->BaseClass
,
408 PdoExtension
->SubClass
);
410 /* Return it to the caller, and select proper status code */
411 *Buffer
= MessageBuffer
;
412 Status
= MessageBuffer
? STATUS_SUCCESS
: STATUS_NOT_SUPPORTED
;
415 case DeviceTextLocationInformation
:
417 /* Get the message from the resource section */
418 MessageBuffer
= PciGetDescriptionMessage(0x10000, &Length
);
421 /* It should be there, but fail if it wasn't found for some reason */
422 Status
= STATUS_NOT_SUPPORTED
;
426 /* Add space for a null-terminator, and allocate the buffer */
427 Length
+= 2 * sizeof(UNICODE_NULL
);
428 LocationBuffer
= ExAllocatePoolWithTag(PagedPool
,
429 Length
* sizeof(WCHAR
),
431 *Buffer
= LocationBuffer
;
433 /* Check if the allocation succeeded */
436 /* Build the location string based on bus, function, and device */
437 swprintf(LocationBuffer
,
439 PdoExtension
->ParentFdoExtension
->BaseBus
,
440 PdoExtension
->Slot
.u
.bits
.FunctionNumber
,
441 PdoExtension
->Slot
.u
.bits
.DeviceNumber
);
444 /* Free the original string from the resource section */
445 ExFreePoolWithTag(MessageBuffer
, 0);
447 /* Select the correct status */
448 Status
= LocationBuffer
? STATUS_SUCCESS
: STATUS_INSUFFICIENT_RESOURCES
;
453 /* Anything else is unsupported */
454 Status
= STATUS_NOT_SUPPORTED
;
458 /* Return whether or not a device text string was indeed found */