reactos/drivers/bus/pcix/pci/id.c

467 lines
15 KiB
C

/*
* PROJECT: ReactOS PCI Bus Driver
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: drivers/bus/pci/pci/id.c
* PURPOSE: PCI Device Identification
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <pci.h>
#include <stdio.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
PWCHAR
NTAPI
PciGetDescriptionMessage(IN ULONG Identifier,
OUT PULONG Length)
{
PMESSAGE_RESOURCE_ENTRY Entry;
ULONG TextLength;
PWCHAR Description, Buffer;
ANSI_STRING MessageString;
UNICODE_STRING UnicodeString;
NTSTATUS Status;
/* Find the message identifier in the message table */
MessageString.Buffer = NULL;
Status = RtlFindMessage(PciDriverObject->DriverStart,
11, // RT_MESSAGETABLE
LANG_NEUTRAL,
Identifier,
&Entry);
if (!NT_SUCCESS(Status)) return NULL;
/* Check if the resource data is Unicode or ANSI */
if (Entry->Flags & MESSAGE_RESOURCE_UNICODE)
{
/* Subtract one space for the end-of-message terminator */
TextLength = Entry->Length -
FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) -
sizeof(WCHAR);
/* Grab the text */
Description = (PWCHAR)Entry->Text;
/* Validate valid message length, ending with a newline character */
ASSERT(TextLength > 1);
ASSERT(Description[TextLength / sizeof(WCHAR)] == L'\n');
/* Allocate the buffer to hold the message string */
Buffer = ExAllocatePoolWithTag(PagedPool, TextLength, 'BicP');
if (!Buffer) return NULL;
/* Copy the message, minus the newline character, and terminate it */
RtlCopyMemory(Buffer, Entry->Text, TextLength - 1);
Buffer[TextLength / sizeof(WCHAR)] = UNICODE_NULL;
/* Return the length to the caller, minus the terminating NULL */
if (Length) *Length = TextLength - 1;
}
else
{
/* Initialize the entry as a string */
RtlInitAnsiString(&MessageString, (PCHAR)Entry->Text);
/* Remove the newline character */
MessageString.Length -= sizeof(CHAR);
/* Convert it to Unicode */
RtlAnsiStringToUnicodeString(&UnicodeString, &MessageString, TRUE);
Buffer = UnicodeString.Buffer;
/* Return the length to the caller */
if (Length) *Length = UnicodeString.Length;
}
/* Return the message buffer to the caller */
return Buffer;
}
PWCHAR
NTAPI
PciGetDeviceDescriptionMessage(IN UCHAR BaseClass,
IN UCHAR SubClass)
{
PWCHAR Message;
ULONG Identifier;
/* The message identifier in the table is encoded based on the PCI class */
Identifier = (BaseClass << 8) | SubClass;
/* Go grab the description message for this device */
Message = PciGetDescriptionMessage(Identifier, NULL);
if (!Message)
{
/* It wasn't found, allocate a buffer for a generic description */
Message = ExAllocatePoolWithTag(PagedPool, sizeof(L"PCI Device"), 'bicP');
if (Message) RtlCopyMemory(Message, L"PCI Device", sizeof(L"PCI Device"));
}
/* Return the description message */
return Message;
}
VOID
NTAPI
PciInitIdBuffer(IN PPCI_ID_BUFFER IdBuffer)
{
/* Initialize the sizes to zero and the pointer to the start of the buffer */
IdBuffer->TotalLength = 0;
IdBuffer->Count = 0;
IdBuffer->CharBuffer = IdBuffer->BufferData;
}
ULONG
__cdecl
PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer,
IN PCCH Format,
...)
{
ULONG Size, Length;
PANSI_STRING AnsiString;
va_list va;
ASSERT(IdBuffer->Count < MAX_ANSI_STRINGS);
/* Do the actual string formatting into the character buffer */
va_start(va, Format);
vsprintf(IdBuffer->CharBuffer, Format, va);
va_end(va);
/* Initialize the ANSI_STRING that will hold this string buffer */
AnsiString = &IdBuffer->Strings[IdBuffer->Count];
RtlInitAnsiString(AnsiString, IdBuffer->CharBuffer);
/* Calculate the final size of the string, in Unicode */
Size = RtlAnsiStringToUnicodeSize(AnsiString);
/* Update hte buffer with the size,and update the character pointer */
IdBuffer->StringSize[IdBuffer->Count] = Size;
IdBuffer->TotalLength += Size;
Length = AnsiString->Length + sizeof(ANSI_NULL);
IdBuffer->CharBuffer += Length;
/* Move to the next string for next time */
IdBuffer->Count++;
/* Return the length */
return Length;
}
ULONG
__cdecl
PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer,
IN PCCH Format,
...)
{
ULONG NextId, Size, Length, MaxLength;
PANSI_STRING AnsiString;
va_list va;
ASSERT(IdBuffer->Count);
/* Choose the next static ANSI_STRING to use */
NextId = IdBuffer->Count - 1;
/* Max length is from the end of the buffer up until the current pointer */
MaxLength = (PCHAR)(IdBuffer + 1) - IdBuffer->CharBuffer;
/* Do the actual append, and return the length this string took */
va_start(va, Format);
Length = vsprintf(IdBuffer->CharBuffer - 1, Format, va);
va_end(va);
ASSERT(Length < MaxLength);
/* Select the static ANSI_STRING, and update its length information */
AnsiString = &IdBuffer->Strings[NextId];
AnsiString->Length += Length;
AnsiString->MaximumLength += Length;
/* Calculate the final size of the string, in Unicode */
Size = RtlAnsiStringToUnicodeSize(AnsiString);
/* Update the buffer with the size, and update the character pointer */
IdBuffer->StringSize[NextId] = Size;
IdBuffer->TotalLength += Size;
IdBuffer->CharBuffer += Length;
/* Return the size */
return Size;
}
NTSTATUS
NTAPI
PciQueryId(IN PPCI_PDO_EXTENSION DeviceExtension,
IN BUS_QUERY_ID_TYPE QueryType,
OUT PWCHAR *Buffer)
{
ULONG SubsysId;
CHAR VendorString[22];
PPCI_PDO_EXTENSION PdoExtension;
PPCI_FDO_EXTENSION ParentExtension;
PWCHAR StringBuffer;
ULONG i, Size;
NTSTATUS Status;
PANSI_STRING NextString;
UNICODE_STRING DestinationString;
PCI_ID_BUFFER IdBuffer;
PAGED_CODE();
/* Assume failure */
Status = STATUS_SUCCESS;
*Buffer = NULL;
/* Start with the genric vendor string, which is the vendor ID + device ID */
sprintf(VendorString,
"PCI\\VEN_%04X&DEV_%04X",
DeviceExtension->VendorId,
DeviceExtension->DeviceId);
/* Initialize the PCI ID Buffer */
PciInitIdBuffer(&IdBuffer);
/* Build the subsystem ID as shown in PCI ID Strings */
SubsysId = DeviceExtension->SubsystemVendorId | (DeviceExtension->SubsystemId << 16);
/* Check what the caller is requesting */
switch (QueryType)
{
case BusQueryDeviceID:
/* A single ID, the vendor string + the revision ID */
PciIdPrintf(&IdBuffer,
"%s&SUBSYS_%08X&REV_%02X",
VendorString,
SubsysId,
DeviceExtension->RevisionId);
break;
case BusQueryHardwareIDs:
/* First the vendor string + the subsystem ID + the revision ID */
PciIdPrintf(&IdBuffer,
"%s&SUBSYS_%08X&REV_%02X",
VendorString,
SubsysId,
DeviceExtension->RevisionId);
/* Next, without the revision */
PciIdPrintf(&IdBuffer,
"%s&SUBSYS_%08X",
VendorString,
SubsysId);
/* Next, the vendor string + the base class + sub class + progif */
PciIdPrintf(&IdBuffer,
"%s&CC_%02X%02X%02X",
VendorString,
DeviceExtension->BaseClass,
DeviceExtension->SubClass,
DeviceExtension->ProgIf);
/* Next, without the progif */
PciIdPrintf(&IdBuffer,
"%s&CC_%02X%02X",
VendorString,
DeviceExtension->BaseClass,
DeviceExtension->SubClass);
/* And finally, a terminator */
PciIdPrintf(&IdBuffer, "\0");
break;
case BusQueryCompatibleIDs:
/* First, the vendor + revision ID only */
PciIdPrintf(&IdBuffer,
"%s&REV_%02X",
VendorString,
DeviceExtension->RevisionId);
/* Next, the vendor string alone */
PciIdPrintf(&IdBuffer, "%s", VendorString);
/* Next, the vendor ID + the base class + the sub class + progif */
PciIdPrintf(&IdBuffer,
"PCI\\VEN_%04X&CC_%02X%02X%02X",
DeviceExtension->VendorId,
DeviceExtension->BaseClass,
DeviceExtension->SubClass,
DeviceExtension->ProgIf);
/* Now without the progif */
PciIdPrintf(&IdBuffer,
"PCI\\VEN_%04X&CC_%02X%02X",
DeviceExtension->VendorId,
DeviceExtension->BaseClass,
DeviceExtension->SubClass);
/* And then just the vendor ID itself */
PciIdPrintf(&IdBuffer,
"PCI\\VEN_%04X",
DeviceExtension->VendorId);
/* Then the base class + subclass + progif, without any vendor */
PciIdPrintf(&IdBuffer,
"PCI\\CC_%02X%02X%02X",
DeviceExtension->BaseClass,
DeviceExtension->SubClass,
DeviceExtension->ProgIf);
/* Next, without the progif */
PciIdPrintf(&IdBuffer,
"PCI\\CC_%02X%02X",
DeviceExtension->BaseClass,
DeviceExtension->SubClass);
/* And finally, a terminator */
PciIdPrintf(&IdBuffer, "\0");
break;
case BusQueryInstanceID:
/* Start with a terminator */
PciIdPrintf(&IdBuffer, "\0");
/* And then encode the device and function number */
PciIdPrintfAppend(&IdBuffer,
"%02X",
(DeviceExtension->Slot.u.bits.DeviceNumber << 3) |
DeviceExtension->Slot.u.bits.FunctionNumber);
/* Loop every parent until the root */
ParentExtension = DeviceExtension->ParentFdoExtension;
while (!PCI_IS_ROOT_FDO(ParentExtension))
{
/* And encode the parent's device and function number as well */
PdoExtension = ParentExtension->PhysicalDeviceObject->DeviceExtension;
PciIdPrintfAppend(&IdBuffer,
"%02X",
(PdoExtension->Slot.u.bits.DeviceNumber << 3) |
PdoExtension->Slot.u.bits.FunctionNumber);
}
break;
default:
/* Unknown query type */
DPRINT1("PciQueryId expected ID type = %d\n", QueryType);
return STATUS_NOT_SUPPORTED;
}
/* Something should've been generated if this has been reached */
ASSERT(IdBuffer.Count > 0);
/* Allocate the final string buffer to hold the ID */
StringBuffer = ExAllocatePoolWithTag(PagedPool, IdBuffer.TotalLength, 'BicP');
if (!StringBuffer) return STATUS_INSUFFICIENT_RESOURCES;
/* Build the UNICODE_STRING structure for it */
DPRINT1("PciQueryId(%d)\n", QueryType);
DestinationString.Buffer = StringBuffer;
DestinationString.MaximumLength = IdBuffer.TotalLength;
/* Loop every ID in the buffer */
for (i = 0; i < IdBuffer.Count; i++)
{
/* Select the ANSI_STRING for the ID */
NextString = &IdBuffer.Strings[i];
DPRINT1(" <- \"%s\"\n", NextString->Buffer);
/* Convert it to a UNICODE_STRING */
Status = RtlAnsiStringToUnicodeString(&DestinationString, NextString, FALSE);
ASSERT(NT_SUCCESS(Status));
/* Add it into the final destination buffer */
Size = IdBuffer.StringSize[i];
DestinationString.MaximumLength -= Size;
DestinationString.Buffer += (Size / sizeof(WCHAR));
}
/* Return the buffer to the caller and return status (should be success) */
*Buffer = StringBuffer;
return Status;
}
NTSTATUS
NTAPI
PciQueryDeviceText(IN PPCI_PDO_EXTENSION PdoExtension,
IN DEVICE_TEXT_TYPE QueryType,
IN ULONG Locale,
OUT PWCHAR *Buffer)
{
PWCHAR MessageBuffer, LocationBuffer;
ULONG Length;
NTSTATUS Status;
UNREFERENCED_PARAMETER(Locale);
/* Check what the caller is requesting */
switch (QueryType)
{
case DeviceTextDescription:
/* Get the message from the resource section */
MessageBuffer = PciGetDeviceDescriptionMessage(PdoExtension->BaseClass,
PdoExtension->SubClass);
/* Return it to the caller, and select proper status code */
*Buffer = MessageBuffer;
Status = MessageBuffer ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED;
break;
case DeviceTextLocationInformation:
/* Get the message from the resource section */
MessageBuffer = PciGetDescriptionMessage(0x10000, &Length);
if (!MessageBuffer)
{
/* It should be there, but fail if it wasn't found for some reason */
Status = STATUS_NOT_SUPPORTED;
break;
}
/* Add space for a null-terminator, and allocate the buffer */
Length += 2 * sizeof(UNICODE_NULL);
LocationBuffer = ExAllocatePoolWithTag(PagedPool,
Length * sizeof(WCHAR),
'BicP');
*Buffer = LocationBuffer;
/* Check if the allocation succeeded */
if (LocationBuffer)
{
/* Build the location string based on bus, function, and device */
swprintf(LocationBuffer,
MessageBuffer,
PdoExtension->ParentFdoExtension->BaseBus,
PdoExtension->Slot.u.bits.FunctionNumber,
PdoExtension->Slot.u.bits.DeviceNumber);
}
/* Free the original string from the resource section */
ExFreePoolWithTag(MessageBuffer, 0);
/* Select the correct status */
Status = LocationBuffer ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
break;
default:
/* Anything else is unsupported */
Status = STATUS_NOT_SUPPORTED;
break;
}
/* Return whether or not a device text string was indeed found */
return Status;
}
/* EOF */