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 *******************************************************************/
16 /* GLOBALS ********************************************************************/
18 /* FUNCTIONS ******************************************************************/
22 PciGetDescriptionMessage(IN ULONG Identifier
,
25 PMESSAGE_RESOURCE_ENTRY Entry
;
27 PWCHAR Description
, Buffer
;
28 ANSI_STRING MessageString
;
29 UNICODE_STRING UnicodeString
;
32 /* Find the message identifier in the message table */
33 MessageString
.Buffer
= NULL
;
34 Status
= RtlFindMessage(PciDriverObject
->DriverStart
,
35 11, // RT_MESSAGETABLE
39 if (!NT_SUCCESS(Status
)) return NULL
;
41 /* Check if the resource data is Unicode or ANSI */
42 if (Entry
->Flags
& MESSAGE_RESOURCE_UNICODE
)
44 /* Subtract one space for the end-of-message terminator */
45 TextLength
= Entry
->Length
-
46 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY
, Text
) -
50 Description
= (PWCHAR
)Entry
->Text
;
52 /* Validate valid message length, ending with a newline character */
53 ASSERT(TextLength
> 1);
54 ASSERT(Description
[TextLength
/ sizeof(WCHAR
) == L
'\n']);
56 /* Allocate the buffer to hold the message string */
57 Buffer
= ExAllocatePoolWithTag(PagedPool
, TextLength
, 'BicP');
58 if (!Buffer
) return NULL
;
60 /* Copy the message, minus the newline character, and terminate it */
61 RtlCopyMemory(Buffer
, Entry
->Text
, TextLength
- 1);
62 Buffer
[TextLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
64 /* Return the length to the caller */
65 if (Length
) *Length
= UnicodeString
.Length
;
69 /* Initialize the entry as a string */
70 RtlInitAnsiString(&MessageString
, (PCHAR
)Entry
->Text
);
72 /* Remove the newline character */
73 MessageString
.Length
-= sizeof(CHAR
);
75 /* Convert it to Unicode */
76 RtlAnsiStringToUnicodeString(&UnicodeString
, &MessageString
, TRUE
);
77 Buffer
= UnicodeString
.Buffer
;
79 /* Return the length to the caller */
80 if (Length
) *Length
= UnicodeString
.Length
;
83 /* Return the message buffer to the caller */
89 PciGetDeviceDescriptionMessage(IN UCHAR BaseClass
,
95 /* The message identifier in the table is encoded based on the PCI class */
96 Identifier
= (BaseClass
<< 8) | SubClass
;
98 /* Go grab the description message for this device */
99 Message
= PciGetDescriptionMessage(Identifier
, NULL
);
102 /* It wasn't found, allocate a buffer for a generic description */
103 Message
= ExAllocatePoolWithTag(PagedPool
, sizeof(L
"PCI Device"), 'bicP');
104 if (Message
) RtlCopyMemory(Message
, L
"PCI Device", sizeof(L
"PCI Device"));
107 /* Return the description message */
113 PciInitIdBuffer(IN PPCI_ID_BUFFER IdBuffer
)
115 /* Initialize the sizes to zero and the pointer to the start of the buffer */
116 IdBuffer
->TotalLength
= 0;
118 IdBuffer
->CharBuffer
= IdBuffer
->BufferData
;
123 PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer
,
128 PANSI_STRING AnsiString
;
130 va_start(va
, Format
);
131 ASSERT(IdBuffer
->Count
< MAX_ANSI_STRINGS
);
133 /* Do the actual string formatting into the character buffer */
134 vsprintf(IdBuffer
->CharBuffer
, Format
, va
);
136 /* Initialize the ANSI_STRING that will hold this string buffer */
137 AnsiString
= &IdBuffer
->Strings
[IdBuffer
->Count
];
138 RtlInitAnsiString(AnsiString
, IdBuffer
->CharBuffer
);
140 /* Calculate the final size of the string, in Unicode */
141 Size
= RtlAnsiStringToUnicodeSize(AnsiString
);
143 /* Update hte buffer with the size,and update the character pointer */
144 IdBuffer
->StringSize
[IdBuffer
->Count
] = Size
;
145 IdBuffer
->TotalLength
+= Size
;
146 Length
= AnsiString
->Length
+ sizeof(ANSI_NULL
);
147 IdBuffer
->CharBuffer
+= Length
;
149 /* Move to the next string for next time */
152 /* Return the length */
158 PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer
,
162 ULONG NextId
, Size
, Length
, MaxLength
;
163 PANSI_STRING AnsiString
;
165 va_start(va
, Format
);
166 ASSERT(IdBuffer
->Count
);
168 /* Choose the next static ANSI_STRING to use */
169 NextId
= IdBuffer
->Count
- 1;
171 /* Max length is from the end of the buffer up until the current pointer */
172 MaxLength
= (PCHAR
)(IdBuffer
+ 1) - IdBuffer
->CharBuffer
;
174 /* Do the actual append, and return the length this string took */
175 Length
= vsprintf(IdBuffer
->CharBuffer
- 1, Format
, va
);
176 ASSERT(Length
< MaxLength
);
178 /* Select the static ANSI_STRING, and update its length information */
179 AnsiString
= &IdBuffer
->Strings
[NextId
];
180 AnsiString
->Length
+= Length
;
181 AnsiString
->MaximumLength
+= Length
;
183 /* Calculate the final size of the string, in Unicode */
184 Size
= RtlAnsiStringToUnicodeSize(AnsiString
);
186 /* Update the buffer with the size, and update the character pointer */
187 IdBuffer
->StringSize
[NextId
] = Size
;
188 IdBuffer
->TotalLength
+= Size
;
189 IdBuffer
->CharBuffer
+= Length
;
191 /* Return the size */
197 PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension
,
198 IN BUS_QUERY_ID_TYPE QueryType
,
202 CHAR VendorString
[22];
203 PPCI_PDO_EXTENSION PdoExtension
;
204 PPCI_FDO_EXTENSION ParentExtension
;
208 PANSI_STRING NextString
;
209 UNICODE_STRING DestinationString
;
210 PCI_ID_BUFFER IdBuffer
;
214 Status
= STATUS_SUCCESS
;
217 /* Start with the genric vendor string, which is the vendor ID + device ID */
218 sprintf(VendorString
,
219 "PCI\\VEN_%04X&DEV_%04X",
220 DeviceExtension
->VendorId
,
221 DeviceExtension
->DeviceId
);
223 /* Initialize the PCI ID Buffer */
224 PciInitIdBuffer(&IdBuffer
);
226 /* Build the subsystem ID as shown in PCI ID Strings */
227 SubsysId
= DeviceExtension
->SubsystemVendorId
| (DeviceExtension
->SubsystemId
<< 16);
229 /* Check what the caller is requesting */
232 case BusQueryDeviceID
:
234 /* A single ID, the vendor string + the revision ID */
235 PciIdPrintf(&IdBuffer
,
236 "%s&SUBSYS_%08X&REV_%02X",
239 DeviceExtension
->RevisionId
);
242 case BusQueryHardwareIDs
:
244 /* First the vendor string + the subsystem ID + the revision ID */
245 PciIdPrintf(&IdBuffer
,
246 "%s&SUBSYS_%08X&REV_%02X",
249 DeviceExtension
->RevisionId
);
251 /* Next, without the revision */
252 PciIdPrintf(&IdBuffer
,
257 /* Next, the vendor string + the base class + sub class + progif */
258 PciIdPrintf(&IdBuffer
,
259 "%s&CC_%02X%02X%02X",
261 DeviceExtension
->BaseClass
,
262 DeviceExtension
->SubClass
,
263 DeviceExtension
->ProgIf
);
265 /* Next, without the progif */
266 PciIdPrintf(&IdBuffer
,
269 DeviceExtension
->BaseClass
,
270 DeviceExtension
->SubClass
);
272 /* And finally, a terminator */
273 PciIdPrintf(&IdBuffer
, "\0");
276 case BusQueryCompatibleIDs
:
278 /* First, the vendor + revision ID only */
279 PciIdPrintf(&IdBuffer
,
282 DeviceExtension
->RevisionId
);
284 /* Next, the vendor string alone */
285 PciIdPrintf(&IdBuffer
, "%s", VendorString
);
287 /* Next, the vendor ID + the base class + the sub class + progif */
288 PciIdPrintf(&IdBuffer
,
289 "PCI\\VEN_%04X&CC_%02X%02X%02X",
290 DeviceExtension
->VendorId
,
291 DeviceExtension
->BaseClass
,
292 DeviceExtension
->SubClass
,
293 DeviceExtension
->ProgIf
);
295 /* Now without the progif */
296 PciIdPrintf(&IdBuffer
,
297 "PCI\\VEN_%04X&CC_%02X%02X",
298 DeviceExtension
->VendorId
,
299 DeviceExtension
->BaseClass
,
300 DeviceExtension
->SubClass
);
302 /* And then just the vendor ID itself */
303 PciIdPrintf(&IdBuffer
,
305 DeviceExtension
->VendorId
);
307 /* Then the base class + subclass + progif, without any vendor */
308 PciIdPrintf(&IdBuffer
,
309 "PCI\\CC_%02X%02X%02X",
310 DeviceExtension
->BaseClass
,
311 DeviceExtension
->SubClass
,
312 DeviceExtension
->ProgIf
);
314 /* Next, without the progif */
315 PciIdPrintf(&IdBuffer
,
317 DeviceExtension
->BaseClass
,
318 DeviceExtension
->SubClass
);
320 /* And finally, a terminator */
321 PciIdPrintf(&IdBuffer
, "\0");
324 case BusQueryInstanceID
:
326 /* Start with a terminator */
327 PciIdPrintf(&IdBuffer
, "\0");
329 /* And then encode the device and function number */
330 PciIdPrintfAppend(&IdBuffer
,
332 (DeviceExtension
->Slot
.u
.bits
.DeviceNumber
<< 3) |
333 DeviceExtension
->Slot
.u
.bits
.FunctionNumber
);
335 /* Loop every parent until the root */
336 ParentExtension
= DeviceExtension
->ParentFdoExtension
;
337 while (!PCI_IS_ROOT_FDO(ParentExtension
))
339 /* And encode the parent's device and function number as well */
340 PdoExtension
= ParentExtension
->PhysicalDeviceObject
->DeviceExtension
;
341 PciIdPrintfAppend(&IdBuffer
,
343 (PdoExtension
->Slot
.u
.bits
.DeviceNumber
<< 3) |
344 PdoExtension
->Slot
.u
.bits
.FunctionNumber
);
350 /* Unknown query type */
351 DPRINT1("PciQueryId expected ID type = %d\n", QueryType
);
352 return STATUS_NOT_SUPPORTED
;
355 /* Something should've been generated if this has been reached */
356 ASSERT(IdBuffer
.Count
> 0);
358 /* Allocate the final string buffer to hold the ID */
359 StringBuffer
= ExAllocatePoolWithTag(PagedPool
, IdBuffer
.TotalLength
, 'BicP');
360 if (!StringBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
362 /* Build the UNICODE_STRING structure for it */
363 DPRINT1("PciQueryId(%d)\n", QueryType
);
364 DestinationString
.Buffer
= StringBuffer
;
365 DestinationString
.MaximumLength
= IdBuffer
.TotalLength
;
367 /* Loop every ID in the buffer */
368 for (i
= 0; i
< IdBuffer
.Count
; i
++)
370 /* Select the ANSI_STRING for the ID */
371 NextString
= &IdBuffer
.Strings
[i
];
372 DPRINT1(" <- \"%s\"\n", NextString
->Buffer
);
374 /* Convert it to a UNICODE_STRING */
375 Status
= RtlAnsiStringToUnicodeString(&DestinationString
, NextString
, FALSE
);
376 ASSERT(NT_SUCCESS(Status
));
378 /* Add it into the final destination buffer */
379 Size
= IdBuffer
.StringSize
[i
];
380 DestinationString
.MaximumLength
-= Size
;
381 DestinationString
.Buffer
+= (Size
/ sizeof(WCHAR
));
384 /* Return the buffer to the caller and return status (should be success) */
385 *Buffer
= StringBuffer
;
391 PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension
,
392 IN DEVICE_TEXT_TYPE QueryType
,
396 PWCHAR MessageBuffer
, LocationBuffer
;
400 /* Check what the caller is requesting */
403 case DeviceTextDescription
:
405 /* Get the message from the resource section */
406 MessageBuffer
= PciGetDeviceDescriptionMessage(PdoExtension
->BaseClass
,
407 PdoExtension
->SubClass
);
409 /* Return it to the caller, and select proper status code */
410 *Buffer
= MessageBuffer
;
411 Status
= MessageBuffer
? STATUS_SUCCESS
: STATUS_NOT_SUPPORTED
;
414 case DeviceTextLocationInformation
:
416 /* Get the message from the resource section */
417 MessageBuffer
= PciGetDescriptionMessage(0x10000, &Length
);
420 /* It should be there, but fail if it wasn't found for some reason */
421 Status
= STATUS_NOT_SUPPORTED
;
425 /* Add space for a null-terminator, and allocate the buffer */
426 Length
+= 2 * sizeof(UNICODE_NULL
);
427 LocationBuffer
= ExAllocatePoolWithTag(PagedPool
,
428 Length
* sizeof(WCHAR
),
430 *Buffer
= LocationBuffer
;
432 /* Check if the allocation succeeded */
435 /* Build the location string based on bus, function, and device */
436 swprintf(LocationBuffer
,
438 PdoExtension
->ParentFdoExtension
->BaseBus
,
439 PdoExtension
->Slot
.u
.bits
.FunctionNumber
,
440 PdoExtension
->Slot
.u
.bits
.DeviceNumber
);
443 /* Free the original string from the resource section */
444 ExFreePoolWithTag(MessageBuffer
, 0);
446 /* Select the correct status */
447 Status
= LocationBuffer
? STATUS_SUCCESS
: STATUS_INSUFFICIENT_RESOURCES
;
452 /* Anything else is unsupported */
453 Status
= STATUS_NOT_SUPPORTED
;
457 /* Return whether or not a device text string was indeed found */