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 __cdecl 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 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 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 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