xref: /reactos/drivers/bus/pcix/pci/id.c (revision 34593d93)
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