1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <pci.h>
12 #include <stdio.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ******************************************************************/
18
19 PWCHAR
20 NTAPI
PciGetDescriptionMessage(IN ULONG Identifier,OUT PULONG Length)21 PciGetDescriptionMessage(IN ULONG Identifier,
22 OUT PULONG Length)
23 {
24 PMESSAGE_RESOURCE_ENTRY Entry;
25 ULONG TextLength;
26 PWCHAR Description, Buffer;
27 ANSI_STRING MessageString;
28 UNICODE_STRING UnicodeString;
29 NTSTATUS Status;
30
31 /* Find the message identifier in the message table */
32 MessageString.Buffer = NULL;
33 Status = RtlFindMessage(PciDriverObject->DriverStart,
34 11, // RT_MESSAGETABLE
35 LANG_NEUTRAL,
36 Identifier,
37 &Entry);
38 if (!NT_SUCCESS(Status)) return NULL;
39
40 /* Check if the resource data is Unicode or ANSI */
41 if (Entry->Flags & MESSAGE_RESOURCE_UNICODE)
42 {
43 /* Subtract one space for the end-of-message terminator */
44 TextLength = Entry->Length -
45 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) -
46 sizeof(WCHAR);
47
48 /* Grab the text */
49 Description = (PWCHAR)Entry->Text;
50
51 /* Validate valid message length, ending with a newline character */
52 ASSERT(TextLength > 1);
53 ASSERT(Description[TextLength / sizeof(WCHAR)] == L'\n');
54
55 /* Allocate the buffer to hold the message string */
56 Buffer = ExAllocatePoolWithTag(PagedPool, TextLength, 'BicP');
57 if (!Buffer) return NULL;
58
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;
62
63 /* Return the length to the caller, minus the terminating NULL */
64 if (Length) *Length = TextLength - 1;
65 }
66 else
67 {
68 /* Initialize the entry as a string */
69 RtlInitAnsiString(&MessageString, (PCHAR)Entry->Text);
70
71 /* Remove the newline character */
72 MessageString.Length -= sizeof(CHAR);
73
74 /* Convert it to Unicode */
75 RtlAnsiStringToUnicodeString(&UnicodeString, &MessageString, TRUE);
76 Buffer = UnicodeString.Buffer;
77
78 /* Return the length to the caller */
79 if (Length) *Length = UnicodeString.Length;
80 }
81
82 /* Return the message buffer to the caller */
83 return Buffer;
84 }
85
86 PWCHAR
87 NTAPI
PciGetDeviceDescriptionMessage(IN UCHAR BaseClass,IN UCHAR SubClass)88 PciGetDeviceDescriptionMessage(IN UCHAR BaseClass,
89 IN UCHAR SubClass)
90 {
91 PWCHAR Message;
92 ULONG Identifier;
93
94 /* The message identifier in the table is encoded based on the PCI class */
95 Identifier = (BaseClass << 8) | SubClass;
96
97 /* Go grab the description message for this device */
98 Message = PciGetDescriptionMessage(Identifier, NULL);
99 if (!Message)
100 {
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"));
104 }
105
106 /* Return the description message */
107 return Message;
108 }
109
110 VOID
111 NTAPI
PciInitIdBuffer(IN PPCI_ID_BUFFER IdBuffer)112 PciInitIdBuffer(IN PPCI_ID_BUFFER IdBuffer)
113 {
114 /* Initialize the sizes to zero and the pointer to the start of the buffer */
115 IdBuffer->TotalLength = 0;
116 IdBuffer->Count = 0;
117 IdBuffer->CharBuffer = IdBuffer->BufferData;
118 }
119
120 ULONG
121 __cdecl
PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer,IN PCCH Format,...)122 PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer,
123 IN PCCH Format,
124 ...)
125 {
126 ULONG Size, Length;
127 PANSI_STRING AnsiString;
128 va_list va;
129
130 ASSERT(IdBuffer->Count < MAX_ANSI_STRINGS);
131
132 /* Do the actual string formatting into the character buffer */
133 va_start(va, Format);
134 vsprintf(IdBuffer->CharBuffer, Format, va);
135 va_end(va);
136
137 /* Initialize the ANSI_STRING that will hold this string buffer */
138 AnsiString = &IdBuffer->Strings[IdBuffer->Count];
139 RtlInitAnsiString(AnsiString, IdBuffer->CharBuffer);
140
141 /* Calculate the final size of the string, in Unicode */
142 Size = RtlAnsiStringToUnicodeSize(AnsiString);
143
144 /* Update hte buffer with the size,and update the character pointer */
145 IdBuffer->StringSize[IdBuffer->Count] = Size;
146 IdBuffer->TotalLength += Size;
147 Length = AnsiString->Length + sizeof(ANSI_NULL);
148 IdBuffer->CharBuffer += Length;
149
150 /* Move to the next string for next time */
151 IdBuffer->Count++;
152
153 /* Return the length */
154 return Length;
155 }
156
157 ULONG
158 __cdecl
PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer,IN PCCH Format,...)159 PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer,
160 IN PCCH Format,
161 ...)
162 {
163 ULONG NextId, Size, Length, MaxLength;
164 PANSI_STRING AnsiString;
165 va_list va;
166
167 ASSERT(IdBuffer->Count);
168
169 /* Choose the next static ANSI_STRING to use */
170 NextId = IdBuffer->Count - 1;
171
172 /* Max length is from the end of the buffer up until the current pointer */
173 MaxLength = (PCHAR)(IdBuffer + 1) - IdBuffer->CharBuffer;
174
175 /* Do the actual append, and return the length this string took */
176 va_start(va, Format);
177 Length = vsprintf(IdBuffer->CharBuffer - 1, Format, va);
178 va_end(va);
179 ASSERT(Length < MaxLength);
180
181 /* Select the static ANSI_STRING, and update its length information */
182 AnsiString = &IdBuffer->Strings[NextId];
183 AnsiString->Length += Length;
184 AnsiString->MaximumLength += Length;
185
186 /* Calculate the final size of the string, in Unicode */
187 Size = RtlAnsiStringToUnicodeSize(AnsiString);
188
189 /* Update the buffer with the size, and update the character pointer */
190 IdBuffer->StringSize[NextId] = Size;
191 IdBuffer->TotalLength += Size;
192 IdBuffer->CharBuffer += Length;
193
194 /* Return the size */
195 return Size;
196 }
197
198 NTSTATUS
199 NTAPI
PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension,IN BUS_QUERY_ID_TYPE QueryType,OUT PWCHAR * Buffer)200 PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension,
201 IN BUS_QUERY_ID_TYPE QueryType,
202 OUT PWCHAR *Buffer)
203 {
204 ULONG SubsysId;
205 CHAR VendorString[22];
206 PPCI_PDO_EXTENSION PdoExtension;
207 PPCI_FDO_EXTENSION ParentExtension;
208 PWCHAR StringBuffer;
209 ULONG i, Size;
210 NTSTATUS Status;
211 PANSI_STRING NextString;
212 UNICODE_STRING DestinationString;
213 PCI_ID_BUFFER IdBuffer;
214 PAGED_CODE();
215
216 /* Assume failure */
217 Status = STATUS_SUCCESS;
218 *Buffer = NULL;
219
220 /* Start with the genric vendor string, which is the vendor ID + device ID */
221 sprintf(VendorString,
222 "PCI\\VEN_%04X&DEV_%04X",
223 DeviceExtension->VendorId,
224 DeviceExtension->DeviceId);
225
226 /* Initialize the PCI ID Buffer */
227 PciInitIdBuffer(&IdBuffer);
228
229 /* Build the subsystem ID as shown in PCI ID Strings */
230 SubsysId = DeviceExtension->SubsystemVendorId | (DeviceExtension->SubsystemId << 16);
231
232 /* Check what the caller is requesting */
233 switch (QueryType)
234 {
235 case BusQueryDeviceID:
236
237 /* A single ID, the vendor string + the revision ID */
238 PciIdPrintf(&IdBuffer,
239 "%s&SUBSYS_%08X&REV_%02X",
240 VendorString,
241 SubsysId,
242 DeviceExtension->RevisionId);
243 break;
244
245 case BusQueryHardwareIDs:
246
247 /* First the vendor string + the subsystem ID + the revision ID */
248 PciIdPrintf(&IdBuffer,
249 "%s&SUBSYS_%08X&REV_%02X",
250 VendorString,
251 SubsysId,
252 DeviceExtension->RevisionId);
253
254 /* Next, without the revision */
255 PciIdPrintf(&IdBuffer,
256 "%s&SUBSYS_%08X",
257 VendorString,
258 SubsysId);
259
260 /* Next, the vendor string + the base class + sub class + progif */
261 PciIdPrintf(&IdBuffer,
262 "%s&CC_%02X%02X%02X",
263 VendorString,
264 DeviceExtension->BaseClass,
265 DeviceExtension->SubClass,
266 DeviceExtension->ProgIf);
267
268 /* Next, without the progif */
269 PciIdPrintf(&IdBuffer,
270 "%s&CC_%02X%02X",
271 VendorString,
272 DeviceExtension->BaseClass,
273 DeviceExtension->SubClass);
274
275 /* And finally, a terminator */
276 PciIdPrintf(&IdBuffer, "\0");
277 break;
278
279 case BusQueryCompatibleIDs:
280
281 /* First, the vendor + revision ID only */
282 PciIdPrintf(&IdBuffer,
283 "%s&REV_%02X",
284 VendorString,
285 DeviceExtension->RevisionId);
286
287 /* Next, the vendor string alone */
288 PciIdPrintf(&IdBuffer, "%s", VendorString);
289
290 /* Next, the vendor ID + the base class + the sub class + progif */
291 PciIdPrintf(&IdBuffer,
292 "PCI\\VEN_%04X&CC_%02X%02X%02X",
293 DeviceExtension->VendorId,
294 DeviceExtension->BaseClass,
295 DeviceExtension->SubClass,
296 DeviceExtension->ProgIf);
297
298 /* Now without the progif */
299 PciIdPrintf(&IdBuffer,
300 "PCI\\VEN_%04X&CC_%02X%02X",
301 DeviceExtension->VendorId,
302 DeviceExtension->BaseClass,
303 DeviceExtension->SubClass);
304
305 /* And then just the vendor ID itself */
306 PciIdPrintf(&IdBuffer,
307 "PCI\\VEN_%04X",
308 DeviceExtension->VendorId);
309
310 /* Then the base class + subclass + progif, without any vendor */
311 PciIdPrintf(&IdBuffer,
312 "PCI\\CC_%02X%02X%02X",
313 DeviceExtension->BaseClass,
314 DeviceExtension->SubClass,
315 DeviceExtension->ProgIf);
316
317 /* Next, without the progif */
318 PciIdPrintf(&IdBuffer,
319 "PCI\\CC_%02X%02X",
320 DeviceExtension->BaseClass,
321 DeviceExtension->SubClass);
322
323 /* And finally, a terminator */
324 PciIdPrintf(&IdBuffer, "\0");
325 break;
326
327 case BusQueryInstanceID:
328
329 /* Start with a terminator */
330 PciIdPrintf(&IdBuffer, "\0");
331
332 /* And then encode the device and function number */
333 PciIdPrintfAppend(&IdBuffer,
334 "%02X",
335 (DeviceExtension->Slot.u.bits.DeviceNumber << 3) |
336 DeviceExtension->Slot.u.bits.FunctionNumber);
337
338 /* Loop every parent until the root */
339 ParentExtension = DeviceExtension->ParentFdoExtension;
340 while (!PCI_IS_ROOT_FDO(ParentExtension))
341 {
342 /* And encode the parent's device and function number as well */
343 PdoExtension = ParentExtension->PhysicalDeviceObject->DeviceExtension;
344 PciIdPrintfAppend(&IdBuffer,
345 "%02X",
346 (PdoExtension->Slot.u.bits.DeviceNumber << 3) |
347 PdoExtension->Slot.u.bits.FunctionNumber);
348 }
349 break;
350
351 default:
352
353 /* Unknown query type */
354 DPRINT1("PciQueryId expected ID type = %d\n", QueryType);
355 return STATUS_NOT_SUPPORTED;
356 }
357
358 /* Something should've been generated if this has been reached */
359 ASSERT(IdBuffer.Count > 0);
360
361 /* Allocate the final string buffer to hold the ID */
362 StringBuffer = ExAllocatePoolWithTag(PagedPool, IdBuffer.TotalLength, 'BicP');
363 if (!StringBuffer) return STATUS_INSUFFICIENT_RESOURCES;
364
365 /* Build the UNICODE_STRING structure for it */
366 DPRINT1("PciQueryId(%d)\n", QueryType);
367 DestinationString.Buffer = StringBuffer;
368 DestinationString.MaximumLength = IdBuffer.TotalLength;
369
370 /* Loop every ID in the buffer */
371 for (i = 0; i < IdBuffer.Count; i++)
372 {
373 /* Select the ANSI_STRING for the ID */
374 NextString = &IdBuffer.Strings[i];
375 DPRINT1(" <- \"%s\"\n", NextString->Buffer);
376
377 /* Convert it to a UNICODE_STRING */
378 Status = RtlAnsiStringToUnicodeString(&DestinationString, NextString, FALSE);
379 ASSERT(NT_SUCCESS(Status));
380
381 /* Add it into the final destination buffer */
382 Size = IdBuffer.StringSize[i];
383 DestinationString.MaximumLength -= Size;
384 DestinationString.Buffer += (Size / sizeof(WCHAR));
385 }
386
387 /* Return the buffer to the caller and return status (should be success) */
388 *Buffer = StringBuffer;
389 return Status;
390 }
391
392 NTSTATUS
393 NTAPI
PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension,IN DEVICE_TEXT_TYPE QueryType,IN ULONG Locale,OUT PWCHAR * Buffer)394 PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension,
395 IN DEVICE_TEXT_TYPE QueryType,
396 IN ULONG Locale,
397 OUT PWCHAR *Buffer)
398 {
399 PWCHAR MessageBuffer, LocationBuffer;
400 ULONG Length;
401 NTSTATUS Status;
402
403 UNREFERENCED_PARAMETER(Locale);
404
405 /* Check what the caller is requesting */
406 switch (QueryType)
407 {
408 case DeviceTextDescription:
409
410 /* Get the message from the resource section */
411 MessageBuffer = PciGetDeviceDescriptionMessage(PdoExtension->BaseClass,
412 PdoExtension->SubClass);
413
414 /* Return it to the caller, and select proper status code */
415 *Buffer = MessageBuffer;
416 Status = MessageBuffer ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
417 break;
418
419 case DeviceTextLocationInformation:
420
421 /* Get the message from the resource section */
422 MessageBuffer = PciGetDescriptionMessage(0x10000, &Length);
423 if (!MessageBuffer)
424 {
425 /* It should be there, but fail if it wasn't found for some reason */
426 Status = STATUS_NOT_SUPPORTED;
427 break;
428 }
429
430 /* Add space for a null-terminator, and allocate the buffer */
431 Length += 2 * sizeof(UNICODE_NULL);
432 LocationBuffer = ExAllocatePoolWithTag(PagedPool,
433 Length * sizeof(WCHAR),
434 'BicP');
435 *Buffer = LocationBuffer;
436
437 /* Check if the allocation succeeded */
438 if (LocationBuffer)
439 {
440 /* Build the location string based on bus, function, and device */
441 swprintf(LocationBuffer,
442 MessageBuffer,
443 PdoExtension->ParentFdoExtension->BaseBus,
444 PdoExtension->Slot.u.bits.FunctionNumber,
445 PdoExtension->Slot.u.bits.DeviceNumber);
446 }
447
448 /* Free the original string from the resource section */
449 ExFreePoolWithTag(MessageBuffer, 0);
450
451 /* Select the correct status */
452 Status = LocationBuffer ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
453 break;
454
455 default:
456
457 /* Anything else is unsupported */
458 Status = STATUS_NOT_SUPPORTED;
459 break;
460 }
461
462 /* Return whether or not a device text string was indeed found */
463 return Status;
464 }
465
466 /* EOF */
467