[PCIX]
[reactos.git] / reactos / 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 #include <stdio.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS ******************************************************************/
18
19 PWCHAR
20 NTAPI
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
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
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 NTAPI
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 va_start(va, Format);
130 ASSERT(IdBuffer->Count < MAX_ANSI_STRINGS);
131
132 /* Do the actual string formatting into the character buffer */
133 vsprintf(IdBuffer->CharBuffer, Format, va);
134
135 /* Initialize the ANSI_STRING that will hold this string buffer */
136 AnsiString = &IdBuffer->Strings[IdBuffer->Count];
137 RtlInitAnsiString(AnsiString, IdBuffer->CharBuffer);
138
139 /* Calculate the final size of the string, in Unicode */
140 Size = RtlAnsiStringToUnicodeSize(AnsiString);
141
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;
147
148 /* Move to the next string for next time */
149 IdBuffer->Count++;
150
151 /* Return the length */
152 return Length;
153 }
154
155 ULONG
156 NTAPI
157 PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer,
158 IN PCCH Format,
159 ...)
160 {
161 ULONG NextId, Size, Length, MaxLength;
162 PANSI_STRING AnsiString;
163 va_list va;
164 va_start(va, Format);
165 ASSERT(IdBuffer->Count);
166
167 /* Choose the next static ANSI_STRING to use */
168 NextId = IdBuffer->Count - 1;
169
170 /* Max length is from the end of the buffer up until the current pointer */
171 MaxLength = (PCHAR)(IdBuffer + 1) - IdBuffer->CharBuffer;
172
173 /* Do the actual append, and return the length this string took */
174 Length = vsprintf(IdBuffer->CharBuffer - 1, Format, va);
175 ASSERT(Length < MaxLength);
176
177 /* Select the static ANSI_STRING, and update its length information */
178 AnsiString = &IdBuffer->Strings[NextId];
179 AnsiString->Length += Length;
180 AnsiString->MaximumLength += Length;
181
182 /* Calculate the final size of the string, in Unicode */
183 Size = RtlAnsiStringToUnicodeSize(AnsiString);
184
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;
189
190 /* Return the size */
191 return Size;
192 }
193
194 NTSTATUS
195 NTAPI
196 PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension,
197 IN BUS_QUERY_ID_TYPE QueryType,
198 OUT PWCHAR *Buffer)
199 {
200 ULONG SubsysId;
201 CHAR VendorString[22];
202 PPCI_PDO_EXTENSION PdoExtension;
203 PPCI_FDO_EXTENSION ParentExtension;
204 PWCHAR StringBuffer;
205 ULONG i, Size;
206 NTSTATUS Status;
207 PANSI_STRING NextString;
208 UNICODE_STRING DestinationString;
209 PCI_ID_BUFFER IdBuffer;
210 PAGED_CODE();
211
212 /* Assume failure */
213 Status = STATUS_SUCCESS;
214 *Buffer = NULL;
215
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);
221
222 /* Initialize the PCI ID Buffer */
223 PciInitIdBuffer(&IdBuffer);
224
225 /* Build the subsystem ID as shown in PCI ID Strings */
226 SubsysId = DeviceExtension->SubsystemVendorId | (DeviceExtension->SubsystemId << 16);
227
228 /* Check what the caller is requesting */
229 switch (QueryType)
230 {
231 case BusQueryDeviceID:
232
233 /* A single ID, the vendor string + the revision ID */
234 PciIdPrintf(&IdBuffer,
235 "%s&SUBSYS_%08X&REV_%02X",
236 VendorString,
237 SubsysId,
238 DeviceExtension->RevisionId);
239 break;
240
241 case BusQueryHardwareIDs:
242
243 /* First the vendor string + the subsystem ID + the revision ID */
244 PciIdPrintf(&IdBuffer,
245 "%s&SUBSYS_%08X&REV_%02X",
246 VendorString,
247 SubsysId,
248 DeviceExtension->RevisionId);
249
250 /* Next, without the revision */
251 PciIdPrintf(&IdBuffer,
252 "%s&SUBSYS_%08X",
253 VendorString,
254 SubsysId);
255
256 /* Next, the vendor string + the base class + sub class + progif */
257 PciIdPrintf(&IdBuffer,
258 "%s&CC_%02X%02X%02X",
259 VendorString,
260 DeviceExtension->BaseClass,
261 DeviceExtension->SubClass,
262 DeviceExtension->ProgIf);
263
264 /* Next, without the progif */
265 PciIdPrintf(&IdBuffer,
266 "%s&CC_%02X%02X",
267 VendorString,
268 DeviceExtension->BaseClass,
269 DeviceExtension->SubClass);
270
271 /* And finally, a terminator */
272 PciIdPrintf(&IdBuffer, "\0");
273 break;
274
275 case BusQueryCompatibleIDs:
276
277 /* First, the vendor + revision ID only */
278 PciIdPrintf(&IdBuffer,
279 "%s&REV_%02X",
280 VendorString,
281 DeviceExtension->RevisionId);
282
283 /* Next, the vendor string alone */
284 PciIdPrintf(&IdBuffer, "%s", VendorString);
285
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);
293
294 /* Now without the progif */
295 PciIdPrintf(&IdBuffer,
296 "PCI\\VEN_%04X&CC_%02X%02X",
297 DeviceExtension->VendorId,
298 DeviceExtension->BaseClass,
299 DeviceExtension->SubClass);
300
301 /* And then just the vendor ID itself */
302 PciIdPrintf(&IdBuffer,
303 "PCI\\VEN_%04X",
304 DeviceExtension->VendorId);
305
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);
312
313 /* Next, without the progif */
314 PciIdPrintf(&IdBuffer,
315 "PCI\\CC_%02X%02X",
316 DeviceExtension->BaseClass,
317 DeviceExtension->SubClass);
318
319 /* And finally, a terminator */
320 PciIdPrintf(&IdBuffer, "\0");
321 break;
322
323 case BusQueryInstanceID:
324
325 /* Start with a terminator */
326 PciIdPrintf(&IdBuffer, "\0");
327
328 /* And then encode the device and function number */
329 PciIdPrintfAppend(&IdBuffer,
330 "%02X",
331 (DeviceExtension->Slot.u.bits.DeviceNumber << 3) |
332 DeviceExtension->Slot.u.bits.FunctionNumber);
333
334 /* Loop every parent until the root */
335 ParentExtension = DeviceExtension->ParentFdoExtension;
336 while (!PCI_IS_ROOT_FDO(ParentExtension))
337 {
338 /* And encode the parent's device and function number as well */
339 PdoExtension = ParentExtension->PhysicalDeviceObject->DeviceExtension;
340 PciIdPrintfAppend(&IdBuffer,
341 "%02X",
342 (PdoExtension->Slot.u.bits.DeviceNumber << 3) |
343 PdoExtension->Slot.u.bits.FunctionNumber);
344 }
345 break;
346
347 default:
348
349 /* Unknown query type */
350 DPRINT1("PciQueryId expected ID type = %d\n", QueryType);
351 return STATUS_NOT_SUPPORTED;
352 }
353
354 /* Something should've been generated if this has been reached */
355 ASSERT(IdBuffer.Count > 0);
356
357 /* Allocate the final string buffer to hold the ID */
358 StringBuffer = ExAllocatePoolWithTag(PagedPool, IdBuffer.TotalLength, 'BicP');
359 if (!StringBuffer) return STATUS_INSUFFICIENT_RESOURCES;
360
361 /* Build the UNICODE_STRING structure for it */
362 DPRINT1("PciQueryId(%d)\n", QueryType);
363 DestinationString.Buffer = StringBuffer;
364 DestinationString.MaximumLength = IdBuffer.TotalLength;
365
366 /* Loop every ID in the buffer */
367 for (i = 0; i < IdBuffer.Count; i++)
368 {
369 /* Select the ANSI_STRING for the ID */
370 NextString = &IdBuffer.Strings[i];
371 DPRINT1(" <- \"%s\"\n", NextString->Buffer);
372
373 /* Convert it to a UNICODE_STRING */
374 Status = RtlAnsiStringToUnicodeString(&DestinationString, NextString, FALSE);
375 ASSERT(NT_SUCCESS(Status));
376
377 /* Add it into the final destination buffer */
378 Size = IdBuffer.StringSize[i];
379 DestinationString.MaximumLength -= Size;
380 DestinationString.Buffer += (Size / sizeof(WCHAR));
381 }
382
383 /* Return the buffer to the caller and return status (should be success) */
384 *Buffer = StringBuffer;
385 return Status;
386 }
387
388 NTSTATUS
389 NTAPI
390 PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension,
391 IN DEVICE_TEXT_TYPE QueryType,
392 IN ULONG Locale,
393 OUT PWCHAR *Buffer)
394 {
395 PWCHAR MessageBuffer, LocationBuffer;
396 ULONG Length;
397 NTSTATUS Status;
398
399 UNREFERENCED_PARAMETER(Locale);
400
401 /* Check what the caller is requesting */
402 switch (QueryType)
403 {
404 case DeviceTextDescription:
405
406 /* Get the message from the resource section */
407 MessageBuffer = PciGetDeviceDescriptionMessage(PdoExtension->BaseClass,
408 PdoExtension->SubClass);
409
410 /* Return it to the caller, and select proper status code */
411 *Buffer = MessageBuffer;
412 Status = MessageBuffer ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
413 break;
414
415 case DeviceTextLocationInformation:
416
417 /* Get the message from the resource section */
418 MessageBuffer = PciGetDescriptionMessage(0x10000, &Length);
419 if (!MessageBuffer)
420 {
421 /* It should be there, but fail if it wasn't found for some reason */
422 Status = STATUS_NOT_SUPPORTED;
423 break;
424 }
425
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),
430 'BicP');
431 *Buffer = LocationBuffer;
432
433 /* Check if the allocation succeeded */
434 if (LocationBuffer)
435 {
436 /* Build the location string based on bus, function, and device */
437 swprintf(LocationBuffer,
438 MessageBuffer,
439 PdoExtension->ParentFdoExtension->BaseBus,
440 PdoExtension->Slot.u.bits.FunctionNumber,
441 PdoExtension->Slot.u.bits.DeviceNumber);
442 }
443
444 /* Free the original string from the resource section */
445 ExFreePoolWithTag(MessageBuffer, 0);
446
447 /* Select the correct status */
448 Status = LocationBuffer ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
449 break;
450
451 default:
452
453 /* Anything else is unsupported */
454 Status = STATUS_NOT_SUPPORTED;
455 break;
456 }
457
458 /* Return whether or not a device text string was indeed found */
459 return Status;
460 }
461
462 /* EOF */