Sync with trunk r58740.
[reactos.git] / drivers / bus / pcix / pci / id.c
index c1d711b..205265d 100644 (file)
@@ -11,6 +11,7 @@
 #include <pci.h>
 #define NDEBUG
 #include <debug.h>
+#include "stdio.h"
 
 /* GLOBALS ********************************************************************/
 
@@ -50,7 +51,7 @@ PciGetDescriptionMessage(IN ULONG Identifier,
 
         /* Validate valid message length, ending with a newline character */
         ASSERT(TextLength > 1);
-        ASSERT(Description[TextLength / sizeof(WCHAR) == L'\n']);
+        ASSERT(Description[TextLength / sizeof(WCHAR)] == L'\n');
 
         /* Allocate the buffer to hold the message string */
         Buffer = ExAllocatePoolWithTag(PagedPool, TextLength, 'BicP');
@@ -60,8 +61,8 @@ PciGetDescriptionMessage(IN ULONG Identifier,
         RtlCopyMemory(Buffer, Entry->Text, TextLength - 1);
         Buffer[TextLength / sizeof(WCHAR)] = UNICODE_NULL;
 
-        /* Return the length to the caller */
-        if (Length) *Length = UnicodeString.Length;
+        /* Return the length to the caller, minus the terminating NULL */
+        if (Length) *Length = TextLength - 1;
     }
     else
     {
@@ -107,4 +108,354 @@ PciGetDeviceDescriptionMessage(IN UCHAR BaseClass,
     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
+NTAPI
+PciIdPrintf(IN PPCI_ID_BUFFER IdBuffer,
+            IN PCCH Format,
+            ...)
+{
+    ULONG Size, Length;
+    PANSI_STRING AnsiString;
+    va_list va;
+    va_start(va, Format);
+    ASSERT(IdBuffer->Count < MAX_ANSI_STRINGS);
+    /* Do the actual string formatting into the character buffer */
+    vsprintf(IdBuffer->CharBuffer, Format, 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
+NTAPI
+PciIdPrintfAppend(IN PPCI_ID_BUFFER IdBuffer,
+                  IN PCCH Format,
+                  ...)
+{
+    ULONG NextId, Size, Length, MaxLength;
+    PANSI_STRING AnsiString;
+    va_list va;
+    va_start(va, Format);
+    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 */
+    Length = vsprintf(IdBuffer->CharBuffer - 1, Format, 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;
+    
+    /* 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 */