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