[FREELDR] Fix 64 bit issues
[reactos.git] / boot / freeldr / freeldr / arch / i386 / machpc.c
index 07083f0..527b944 100644 (file)
  */
 
 #include <freeldr.h>
+#include <cportlib/cportlib.h>
+
+#include <debug.h>
+
+DBG_DEFAULT_CHANNEL(HWDETECT);
+
+
+/* Maximum number of COM and LPT ports */
+#define MAX_COM_PORTS   4
+#define MAX_LPT_PORTS   3
+
+/* No Mouse */
+#define MOUSE_TYPE_NONE            0
+/* Microsoft Mouse with 2 buttons */
+#define MOUSE_TYPE_MICROSOFT       1
+/* Logitech Mouse with 3 buttons */
+#define MOUSE_TYPE_LOGITECH        2
+/* Microsoft Wheel Mouse (aka Z Mouse) */
+#define MOUSE_TYPE_WHEELZ          3
+/* Mouse Systems Mouse */
+#define MOUSE_TYPE_MOUSESYSTEMS    4
+
+
+/* PS2 stuff */
+
+/* Controller registers. */
+#define CONTROLLER_REGISTER_STATUS                      0x64
+#define CONTROLLER_REGISTER_CONTROL                     0x64
+#define CONTROLLER_REGISTER_DATA                        0x60
+
+/* Controller commands. */
+#define CONTROLLER_COMMAND_READ_MODE                    0x20
+#define CONTROLLER_COMMAND_WRITE_MODE                   0x60
+#define CONTROLLER_COMMAND_GET_VERSION                  0xA1
+#define CONTROLLER_COMMAND_MOUSE_DISABLE                0xA7
+#define CONTROLLER_COMMAND_MOUSE_ENABLE                 0xA8
+#define CONTROLLER_COMMAND_TEST_MOUSE                   0xA9
+#define CONTROLLER_COMMAND_SELF_TEST                    0xAA
+#define CONTROLLER_COMMAND_KEYBOARD_TEST                0xAB
+#define CONTROLLER_COMMAND_KEYBOARD_DISABLE             0xAD
+#define CONTROLLER_COMMAND_KEYBOARD_ENABLE              0xAE
+#define CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER    0xD3
+#define CONTROLLER_COMMAND_WRITE_MOUSE                  0xD4
+
+/* Controller status */
+#define CONTROLLER_STATUS_OUTPUT_BUFFER_FULL            0x01
+#define CONTROLLER_STATUS_INPUT_BUFFER_FULL             0x02
+#define CONTROLLER_STATUS_SELF_TEST                     0x04
+#define CONTROLLER_STATUS_COMMAND                       0x08
+#define CONTROLLER_STATUS_UNLOCKED                      0x10
+#define CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL      0x20
+#define CONTROLLER_STATUS_GENERAL_TIMEOUT               0x40
+#define CONTROLLER_STATUS_PARITY_ERROR                  0x80
+#define AUX_STATUS_OUTPUT_BUFFER_FULL                   (CONTROLLER_STATUS_OUTPUT_BUFFER_FULL | \
+                                                         CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL)
+
+/* Timeout in ms for sending to keyboard controller. */
+#define CONTROLLER_TIMEOUT                              250
+
+
+// NOTE: Similar to machxbox.c!XboxGetHarddiskConfigurationData(),
+// but with extended geometry support.
+static
+PCM_PARTIAL_RESOURCE_LIST
+PcGetHarddiskConfigurationData(UCHAR DriveNumber, ULONG* pSize)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
+    EXTENDED_GEOMETRY ExtGeometry;
+    GEOMETRY Geometry;
+    ULONG Size;
+
+    //
+    // Initialize returned size
+    //
+    *pSize = 0;
+
+    /* Set 'Configuration Data' value */
+    Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
+           sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
+    PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+    if (PartialResourceList == NULL)
+    {
+        ERR("Failed to allocate resource descriptor\n");
+        return NULL;
+    }
+
+    memset(PartialResourceList, 0, Size);
+    PartialResourceList->Version = 1;
+    PartialResourceList->Revision = 1;
+    PartialResourceList->Count = 1;
+    PartialResourceList->PartialDescriptors[0].Type =
+        CmResourceTypeDeviceSpecific;
+//  PartialResourceList->PartialDescriptors[0].ShareDisposition =
+//  PartialResourceList->PartialDescriptors[0].Flags =
+    PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+        sizeof(CM_DISK_GEOMETRY_DEVICE_DATA);
+
+    /* Get pointer to geometry data */
+    DiskGeometry = (PVOID)(((ULONG_PTR)PartialResourceList) + sizeof(CM_PARTIAL_RESOURCE_LIST));
+
+    /* Get the disk geometry */
+    ExtGeometry.Size = sizeof(EXTENDED_GEOMETRY);
+    if (DiskGetExtendedDriveParameters(DriveNumber, &ExtGeometry, ExtGeometry.Size))
+    {
+        DiskGeometry->BytesPerSector = ExtGeometry.BytesPerSector;
+        DiskGeometry->NumberOfCylinders = ExtGeometry.Cylinders;
+        DiskGeometry->SectorsPerTrack = ExtGeometry.SectorsPerTrack;
+        DiskGeometry->NumberOfHeads = ExtGeometry.Heads;
+    }
+    else if (MachDiskGetDriveGeometry(DriveNumber, &Geometry))
+    {
+        DiskGeometry->BytesPerSector = Geometry.BytesPerSector;
+        DiskGeometry->NumberOfCylinders = Geometry.Cylinders;
+        DiskGeometry->SectorsPerTrack = Geometry.Sectors;
+        DiskGeometry->NumberOfHeads = Geometry.Heads;
+    }
+    else
+    {
+        TRACE("Reading disk geometry failed\n");
+        FrLdrHeapFree(PartialResourceList, TAG_HW_RESOURCE_LIST);
+        return NULL;
+    }
+    TRACE("Disk %x: %u Cylinders  %u Heads  %u Sectors  %u Bytes\n",
+          DriveNumber,
+          DiskGeometry->NumberOfCylinders,
+          DiskGeometry->NumberOfHeads,
+          DiskGeometry->SectorsPerTrack,
+          DiskGeometry->BytesPerSector);
+
+    //
+    // Return configuration data
+    //
+    *pSize = Size;
+    return PartialResourceList;
+}
+
+static
+VOID
+DetectPnpBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_PNP_BIOS_DEVICE_NODE DeviceNode;
+    PCM_PNP_BIOS_INSTALLATION_CHECK InstData;
+    PCONFIGURATION_COMPONENT_DATA BusKey;
+    ULONG x;
+    ULONG NodeSize = 0;
+    ULONG NodeCount = 0;
+    UCHAR NodeNumber;
+    ULONG FoundNodeCount;
+    int i;
+    ULONG PnpBufferSize;
+    ULONG PnpBufferSizeLimit;
+    ULONG Size;
+    char *Ptr;
+
+    InstData = (PCM_PNP_BIOS_INSTALLATION_CHECK)PnpBiosSupported();
+    if (InstData == NULL || strncmp((CHAR*)InstData->Signature, "$PnP", 4))
+    {
+        TRACE("PnP-BIOS not supported\n");
+        return;
+    }
+
+    TRACE("PnP-BIOS supported\n");
+    TRACE("Signature '%c%c%c%c'\n",
+          InstData->Signature[0], InstData->Signature[1],
+          InstData->Signature[2], InstData->Signature[3]);
+
+    x = PnpBiosGetDeviceNodeCount(&NodeSize, &NodeCount);
+    if (x == 0x82)
+    {
+        TRACE("PnP-BIOS function 'Get Number of System Device Nodes' not supported\n");
+        return;
+    }
+
+    NodeCount &= 0xFF; // needed since some fscked up BIOSes return
+    // wrong info (e.g. Mac Virtual PC)
+    // e.g. look: http://my.execpc.com/~geezer/osd/pnp/pnp16.c
+    if (x != 0 || NodeSize == 0 || NodeCount == 0)
+    {
+        ERR("PnP-BIOS failed to enumerate device nodes\n");
+        return;
+    }
+    TRACE("MaxNodeSize %u  NodeCount %u\n", NodeSize, NodeCount);
+    TRACE("Estimated buffer size %u\n", NodeSize * NodeCount);
+
+    /* Set 'Configuration Data' value */
+    PnpBufferSizeLimit = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK)
+                         + (NodeSize * NodeCount);
+    Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + PnpBufferSizeLimit;
+    PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+    if (PartialResourceList == NULL)
+    {
+        ERR("Failed to allocate resource descriptor\n");
+        return;
+    }
+    memset(PartialResourceList, 0, Size);
+
+    /* Initialize resource descriptor */
+    PartialResourceList->Version = 1;
+    PartialResourceList->Revision = 1;
+    PartialResourceList->Count = 1;
+    PartialResourceList->PartialDescriptors[0].Type =
+        CmResourceTypeDeviceSpecific;
+    PartialResourceList->PartialDescriptors[0].ShareDisposition =
+        CmResourceShareUndetermined;
+
+    /* The buffer starts after PartialResourceList->PartialDescriptors[0] */
+    Ptr = (char *)(PartialResourceList + 1);
+
+    /* Set installation check data */
+    memcpy (Ptr, InstData, sizeof(CM_PNP_BIOS_INSTALLATION_CHECK));
+    Ptr += sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
+    PnpBufferSize = sizeof(CM_PNP_BIOS_INSTALLATION_CHECK);
+
+    /* Copy device nodes */
+    FoundNodeCount = 0;
+    for (i = 0; i < 0xFF; i++)
+    {
+        NodeNumber = (UCHAR)i;
+
+        x = PnpBiosGetDeviceNode(&NodeNumber, DiskReadBuffer);
+        if (x == 0)
+        {
+            DeviceNode = (PCM_PNP_BIOS_DEVICE_NODE)DiskReadBuffer;
+
+            TRACE("Node: %u  Size %u (0x%x)\n",
+                  DeviceNode->Node,
+                  DeviceNode->Size,
+                  DeviceNode->Size);
+
+            if (PnpBufferSize + DeviceNode->Size > PnpBufferSizeLimit)
+            {
+                ERR("Buffer too small! Ignoring remaining device nodes.\n");
+                break;
+            }
+
+            memcpy(Ptr, DeviceNode, DeviceNode->Size);
+
+            Ptr += DeviceNode->Size;
+            PnpBufferSize += DeviceNode->Size;
+
+            FoundNodeCount++;
+            if (FoundNodeCount >= NodeCount)
+                break;
+        }
+    }
+
+    /* Set real data size */
+    PartialResourceList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+        PnpBufferSize;
+    Size = sizeof(CM_PARTIAL_RESOURCE_LIST) + PnpBufferSize;
+
+    TRACE("Real buffer size: %u\n", PnpBufferSize);
+    TRACE("Resource size: %u\n", Size);
+
+    /* Create component key */
+    FldrCreateComponentKey(SystemKey,
+                           AdapterClass,
+                           MultiFunctionAdapter,
+                           0x0,
+                           0x0,
+                           0xFFFFFFFF,
+                           "PNP BIOS",
+                           PartialResourceList,
+                           Size,
+                           &BusKey);
+
+    (*BusNumber)++;
+}
+
+static
+VOID
+InitializeSerialPort(PUCHAR Port,
+                     UCHAR LineControl)
+{
+    WRITE_PORT_UCHAR(Port + 3, 0x80);  /* set DLAB on   */
+    WRITE_PORT_UCHAR(Port,     0x60);  /* speed LO byte */
+    WRITE_PORT_UCHAR(Port + 1, 0);     /* speed HI byte */
+    WRITE_PORT_UCHAR(Port + 3, LineControl);
+    WRITE_PORT_UCHAR(Port + 1, 0);     /* set comm and DLAB to 0 */
+    WRITE_PORT_UCHAR(Port + 4, 0x09);  /* DR int enable */
+    READ_PORT_UCHAR(Port + 5);  /* clear error bits */
+}
+
+static
+ULONG
+DetectSerialMouse(PUCHAR Port)
+{
+    CHAR Buffer[4];
+    ULONG i;
+    ULONG TimeOut;
+    UCHAR LineControl;
+
+    /* Shutdown mouse or something like that */
+    LineControl = READ_PORT_UCHAR(Port + 4);
+    WRITE_PORT_UCHAR(Port + 4, (LineControl & ~0x02) | 0x01);
+    StallExecutionProcessor(100000);
+
+    /*
+     * Clear buffer
+     * Maybe there is no serial port although BIOS reported one (this
+     * is the case on Apple hardware), or the serial port is misbehaving,
+     * therefore we must give up after some time.
+     */
+    TimeOut = 200;
+    while (READ_PORT_UCHAR(Port + 5) & 0x01)
+    {
+        if (--TimeOut == 0)
+            return MOUSE_TYPE_NONE;
+        READ_PORT_UCHAR(Port);
+    }
+
+    /*
+     * Send modem control with 'Data Terminal Ready', 'Request To Send' and
+     * 'Output Line 2' message. This enables mouse to identify.
+     */
+    WRITE_PORT_UCHAR(Port + 4, 0x0b);
+
+    /* Wait 10 milliseconds for the mouse getting ready */
+    StallExecutionProcessor(10000);
+
+    /* Read first four bytes, which contains Microsoft Mouse signs */
+    TimeOut = 20;
+    for (i = 0; i < 4; i++)
+    {
+        while ((READ_PORT_UCHAR(Port + 5) & 1) == 0)
+        {
+            StallExecutionProcessor(100);
+            --TimeOut;
+            if (TimeOut == 0)
+                return MOUSE_TYPE_NONE;
+        }
+        Buffer[i] = READ_PORT_UCHAR(Port);
+    }
+
+    TRACE("Mouse data: %x %x %x %x\n",
+          Buffer[0], Buffer[1], Buffer[2], Buffer[3]);
+
+    /* Check that four bytes for signs */
+    for (i = 0; i < 4; ++i)
+    {
+        if (Buffer[i] == 'B')
+        {
+            /* Sign for Microsoft Ballpoint */
+//      DbgPrint("Microsoft Ballpoint device detected\n");
+//      DbgPrint("THIS DEVICE IS NOT SUPPORTED, YET\n");
+            return MOUSE_TYPE_NONE;
+        }
+        else if (Buffer[i] == 'M')
+        {
+            /* Sign for Microsoft Mouse protocol followed by button specifier */
+            if (i == 3)
+            {
+                /* Overflow Error */
+                return MOUSE_TYPE_NONE;
+            }
+
+            switch (Buffer[i + 1])
+            {
+            case '3':
+                TRACE("Microsoft Mouse with 3-buttons detected\n");
+                return MOUSE_TYPE_LOGITECH;
+
+            case 'Z':
+                TRACE("Microsoft Wheel Mouse detected\n");
+                return MOUSE_TYPE_WHEELZ;
+
+                /* case '2': */
+            default:
+                TRACE("Microsoft Mouse with 2-buttons detected\n");
+                return MOUSE_TYPE_MICROSOFT;
+            }
+        }
+    }
+
+    return MOUSE_TYPE_NONE;
+}
+
+static ULONG
+GetSerialMousePnpId(PUCHAR Port, char *Buffer)
+{
+    ULONG TimeOut;
+    ULONG i = 0;
+    char c;
+    char x;
+
+    WRITE_PORT_UCHAR(Port + 4, 0x09);
+
+    /* Wait 10 milliseconds for the mouse getting ready */
+    StallExecutionProcessor(10000);
+
+    WRITE_PORT_UCHAR(Port + 4, 0x0b);
+
+    StallExecutionProcessor(10000);
+
+    for (;;)
+    {
+        TimeOut = 200;
+        while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
+        {
+            StallExecutionProcessor(1000);
+            --TimeOut;
+            if (TimeOut == 0)
+            {
+                return 0;
+            }
+        }
+
+        c = READ_PORT_UCHAR(Port);
+        if (c == 0x08 || c == 0x28)
+            break;
+    }
+
+    Buffer[i++] = c;
+    x = c + 1;
+
+    for (;;)
+    {
+        TimeOut = 200;
+        while (((READ_PORT_UCHAR(Port + 5) & 1) == 0) && (TimeOut > 0))
+        {
+            StallExecutionProcessor(1000);
+            --TimeOut;
+            if (TimeOut == 0)
+                return 0;
+        }
+        c = READ_PORT_UCHAR(Port);
+        Buffer[i++] = c;
+        if (c == x)
+            break;
+        if (i >= 256)
+            break;
+    }
+
+    return i;
+}
+
+static
+VOID
+DetectSerialPointerPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey,
+                              PUCHAR Base)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    char Buffer[256];
+    CHAR Identifier[256];
+    PCONFIGURATION_COMPONENT_DATA PeripheralKey;
+    ULONG MouseType;
+    ULONG Size, Length;
+    ULONG i;
+    ULONG j;
+    ULONG k;
+
+    TRACE("DetectSerialPointerPeripheral()\n");
+
+    Identifier[0] = 0;
+
+    InitializeSerialPort(Base, 2);
+    MouseType = DetectSerialMouse(Base);
+
+    if (MouseType != MOUSE_TYPE_NONE)
+    {
+        Length = GetSerialMousePnpId(Base, Buffer);
+        TRACE( "PnP ID length: %u\n", Length);
+
+        if (Length != 0)
+        {
+            /* Convert PnP sting to ASCII */
+            if (Buffer[0] == 0x08)
+            {
+                for (i = 0; i < Length; i++)
+                    Buffer[i] += 0x20;
+            }
+            Buffer[Length] = 0;
+
+            TRACE("PnP ID string: %s\n", Buffer);
+
+            /* Copy PnpId string */
+            for (i = 0; i < 7; i++)
+            {
+                Identifier[i] = Buffer[3 + i];
+            }
+            memcpy(&Identifier[7],
+                   L" - ",
+                   3 * sizeof(WCHAR));
+
+            /* Skip device serial number */
+            i = 10;
+            if (Buffer[i] == '\\')
+            {
+                for (j = ++i; i < Length; ++i)
+                {
+                    if (Buffer[i] == '\\')
+                        break;
+                }
+                if (i >= Length)
+                    i -= 3;
+            }
+
+            /* Skip PnP class */
+            if (Buffer[i] == '\\')
+            {
+                for (j = ++i; i < Length; ++i)
+                {
+                    if (Buffer[i] == '\\')
+                        break;
+                }
+
+                if (i >= Length)
+                    i -= 3;
+            }
+
+            /* Skip compatible PnP Id */
+            if (Buffer[i] == '\\')
+            {
+                for (j = ++i; i < Length; ++i)
+                {
+                    if (Buffer[i] == '\\')
+                        break;
+                }
+                if (Buffer[j] == '*')
+                    ++j;
+                if (i >= Length)
+                    i -= 3;
+            }
+
+            /* Get product description */
+            if (Buffer[i] == '\\')
+            {
+                for (j = ++i; i < Length; ++i)
+                {
+                    if (Buffer[i] == ';')
+                        break;
+                }
+                if (i >= Length)
+                    i -= 3;
+                if (i > j + 1)
+                {
+                    for (k = 0; k < i - j; k++)
+                    {
+                        Identifier[k + 10] = Buffer[k + j];
+                    }
+                    Identifier[10 + (i - j)] = 0;
+                }
+            }
+
+            TRACE("Identifier string: %s\n", Identifier);
+        }
+
+        if (Length == 0 || strlen(Identifier) < 11)
+        {
+            switch (MouseType)
+            {
+            case MOUSE_TYPE_LOGITECH:
+                strcpy(Identifier, "LOGITECH SERIAL MOUSE");
+                break;
+
+            case MOUSE_TYPE_WHEELZ:
+                strcpy(Identifier, "MICROSOFT SERIAL MOUSE WITH WHEEL");
+                break;
+
+            case MOUSE_TYPE_MICROSOFT:
+            default:
+                strcpy(Identifier, "MICROSOFT SERIAL MOUSE");
+                break;
+            }
+        }
+
+        /* Set 'Configuration Data' value */
+        Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
+               sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+        PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+        if (PartialResourceList == NULL)
+        {
+            ERR("Failed to allocate resource descriptor\n");
+            return;
+        }
+        memset(PartialResourceList, 0, Size);
+        PartialResourceList->Version = 1;
+        PartialResourceList->Revision = 1;
+        PartialResourceList->Count = 0;
+
+        /* Create 'PointerPeripheral' key */
+        FldrCreateComponentKey(ControllerKey,
+                               PeripheralClass,
+                               PointerPeripheral,
+                               Input,
+                               0x0,
+                               0xFFFFFFFF,
+                               Identifier,
+                               PartialResourceList,
+                               Size,
+                               &PeripheralKey);
+
+        TRACE("Created key: PointerPeripheral\\0\n");
+    }
+}
+
+static
+VOID
+DetectSerialPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+    PCM_SERIAL_DEVICE_DATA SerialDeviceData;
+    ULONG Irq[MAX_COM_PORTS] = {4, 3, 4, 3};
+    ULONG Base;
+    CHAR Buffer[80];
+    PUSHORT BasePtr;
+    ULONG ControllerNumber = 0;
+    PCONFIGURATION_COMPONENT_DATA ControllerKey;
+    ULONG i;
+    ULONG Size;
+
+    TRACE("DetectSerialPorts()\n");
+
+    /*
+     * The BIOS data area 0x400 holds the address of the first valid COM port.
+     * Each COM port address is stored in a 2-byte field.
+     * Infos at: http://www.bioscentral.com/misc/bda.htm
+     */
+    BasePtr = (PUSHORT)0x400;
+
+    for (i = 0; i < MAX_COM_PORTS; i++, BasePtr++)
+    {
+        Base = (ULONG) * BasePtr;
+        if ((Base == 0) || !CpDoesPortExist(UlongToPtr(Base)))
+            continue;
+
+        TRACE("Found COM%u port at 0x%x\n", i + 1, Base);
+
+        /* Set 'Identifier' value */
+        sprintf(Buffer, "COM%ld", i + 1);
+
+        /* Build full device descriptor */
+        Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
+               2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) +
+               sizeof(CM_SERIAL_DEVICE_DATA);
+        PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+        if (PartialResourceList == NULL)
+        {
+            ERR("Failed to allocate resource descriptor\n");
+            continue;
+        }
+        memset(PartialResourceList, 0, Size);
+
+        /* Initialize resource descriptor */
+        PartialResourceList->Version = 1;
+        PartialResourceList->Revision = 1;
+        PartialResourceList->Count = 3;
+
+        /* Set IO Port */
+        PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
+        PartialDescriptor->Type = CmResourceTypePort;
+        PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
+        PartialDescriptor->u.Port.Start.LowPart = Base;
+        PartialDescriptor->u.Port.Start.HighPart = 0x0;
+        PartialDescriptor->u.Port.Length = 7;
+
+        /* Set Interrupt */
+        PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
+        PartialDescriptor->Type = CmResourceTypeInterrupt;
+        PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
+        PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+        PartialDescriptor->u.Interrupt.Level = Irq[i];
+        PartialDescriptor->u.Interrupt.Vector = Irq[i];
+        PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
+
+        /* Set serial data (device specific) */
+        PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
+        PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
+        PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
+        PartialDescriptor->Flags = 0;
+        PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_SERIAL_DEVICE_DATA);
+
+        SerialDeviceData =
+            (PCM_SERIAL_DEVICE_DATA)&PartialResourceList->PartialDescriptors[3];
+        SerialDeviceData->BaudClock = 1843200; /* UART Clock frequency (Hertz) */
+
+        /* Create controller key */
+        FldrCreateComponentKey(BusKey,
+                               ControllerClass,
+                               SerialController,
+                               Output | Input | ConsoleIn | ConsoleOut,
+                               ControllerNumber,
+                               0xFFFFFFFF,
+                               Buffer,
+                               PartialResourceList,
+                               Size,
+                               &ControllerKey);
+
+        if (!Rs232PortInUse(UlongToPtr(Base)))
+        {
+            /* Detect serial mouse */
+            DetectSerialPointerPeripheral(ControllerKey, UlongToPtr(Base));
+        }
+
+        ControllerNumber++;
+    }
+}
+
+static VOID
+DetectParallelPorts(PCONFIGURATION_COMPONENT_DATA BusKey)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+    ULONG Irq[MAX_LPT_PORTS] = {7, 5, (ULONG) - 1};
+    CHAR Buffer[80];
+    PCONFIGURATION_COMPONENT_DATA ControllerKey;
+    PUSHORT BasePtr;
+    ULONG Base;
+    ULONG ControllerNumber = 0;
+    ULONG i;
+    ULONG Size;
+
+    TRACE("DetectParallelPorts() called\n");
+
+    /*
+     * The BIOS data area 0x408 holds the address of the first valid LPT port.
+     * Each LPT port address is stored in a 2-byte field.
+     * Infos at: http://www.bioscentral.com/misc/bda.htm
+     */
+    BasePtr = (PUSHORT)0x408;
+
+    for (i = 0; i < MAX_LPT_PORTS; i++, BasePtr++)
+    {
+        Base = (ULONG) * BasePtr;
+        if (Base == 0)
+            continue;
+
+        TRACE("Parallel port %u: %x\n", ControllerNumber, Base);
+
+        /* Set 'Identifier' value */
+        sprintf(Buffer, "PARALLEL%ld", i + 1);
+
+        /* Build full device descriptor */
+        Size = sizeof(CM_PARTIAL_RESOURCE_LIST);
+        if (Irq[i] != (ULONG) - 1)
+            Size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+
+        PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+        if (PartialResourceList == NULL)
+        {
+            ERR("Failed to allocate resource descriptor\n");
+            continue;
+        }
+        memset(PartialResourceList, 0, Size);
+
+        /* Initialize resource descriptor */
+        PartialResourceList->Version = 1;
+        PartialResourceList->Revision = 1;
+        PartialResourceList->Count = (Irq[i] != (ULONG) - 1) ? 2 : 1;
+
+        /* Set IO Port */
+        PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
+        PartialDescriptor->Type = CmResourceTypePort;
+        PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+        PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
+        PartialDescriptor->u.Port.Start.LowPart = Base;
+        PartialDescriptor->u.Port.Start.HighPart = 0x0;
+        PartialDescriptor->u.Port.Length = 3;
+
+        /* Set Interrupt */
+        if (Irq[i] != (ULONG) - 1)
+        {
+            PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
+            PartialDescriptor->Type = CmResourceTypeInterrupt;
+            PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
+            PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+            PartialDescriptor->u.Interrupt.Level = Irq[i];
+            PartialDescriptor->u.Interrupt.Vector = Irq[i];
+            PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
+        }
+
+        /* Create controller key */
+        FldrCreateComponentKey(BusKey,
+                               ControllerClass,
+                               ParallelController,
+                               Output,
+                               ControllerNumber,
+                               0xFFFFFFFF,
+                               Buffer,
+                               PartialResourceList,
+                               Size,
+                               &ControllerKey);
+
+        ControllerNumber++;
+    }
+
+    TRACE("DetectParallelPorts() done\n");
+}
+
+// static
+BOOLEAN
+DetectKeyboardDevice(VOID)
+{
+    UCHAR Status;
+    UCHAR Scancode;
+    ULONG Loops;
+    BOOLEAN Result = TRUE;
+
+    /* Identify device */
+    WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
+
+    /* Wait for reply */
+    for (Loops = 0; Loops < 100; Loops++)
+    {
+        StallExecutionProcessor(10000);
+        Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+        if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
+            break;
+    }
+
+    if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
+    {
+        /* PC/XT keyboard or no keyboard */
+        Result = FALSE;
+    }
+
+    Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
+    if (Scancode != 0xFA)
+    {
+        /* No ACK received */
+        Result = FALSE;
+    }
+
+    StallExecutionProcessor(10000);
+
+    Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+    if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
+    {
+        /* Found AT keyboard */
+        return Result;
+    }
+
+    Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
+    if (Scancode != 0xAB)
+    {
+        /* No 0xAB received */
+        Result = FALSE;
+    }
+
+    StallExecutionProcessor(10000);
+
+    Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+    if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) == 0)
+    {
+        /* No byte in buffer */
+        Result = FALSE;
+    }
+
+    Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
+    if (Scancode != 0x41)
+    {
+        /* No 0x41 received */
+        Result = FALSE;
+    }
+
+    /* Found MF-II keyboard */
+    return Result;
+}
+
+static VOID
+DetectKeyboardPeripheral(PCONFIGURATION_COMPONENT_DATA ControllerKey)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+    PCM_KEYBOARD_DEVICE_DATA KeyboardData;
+    PCONFIGURATION_COMPONENT_DATA PeripheralKey;
+    ULONG Size;
+
+    /* HACK: don't call DetectKeyboardDevice() as it fails in Qemu 0.8.2
+    if (DetectKeyboardDevice()) */
+    {
+        /* Set 'Configuration Data' value */
+        Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
+               sizeof(CM_KEYBOARD_DEVICE_DATA);
+        PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+        if (PartialResourceList == NULL)
+        {
+            ERR("Failed to allocate resource descriptor\n");
+            return;
+        }
+
+        /* Initialize resource descriptor */
+        memset(PartialResourceList, 0, Size);
+        PartialResourceList->Version = 1;
+        PartialResourceList->Revision = 1;
+        PartialResourceList->Count = 1;
+
+        PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
+        PartialDescriptor->Type = CmResourceTypeDeviceSpecific;
+        PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
+        PartialDescriptor->u.DeviceSpecificData.DataSize = sizeof(CM_KEYBOARD_DEVICE_DATA);
+
+        KeyboardData = (PCM_KEYBOARD_DEVICE_DATA)(PartialDescriptor + 1);
+        KeyboardData->Version = 1;
+        KeyboardData->Revision = 1;
+        KeyboardData->Type = 4;
+        KeyboardData->Subtype = 0;
+        KeyboardData->KeyboardFlags = 0x20;
+
+        /* Create controller key */
+        FldrCreateComponentKey(ControllerKey,
+                               PeripheralClass,
+                               KeyboardPeripheral,
+                               Input | ConsoleIn,
+                               0x0,
+                               0xFFFFFFFF,
+                               "PCAT_ENHANCED",
+                               PartialResourceList,
+                               Size,
+                               &PeripheralKey);
+        TRACE("Created key: KeyboardPeripheral\\0\n");
+    }
+}
+
+static
+VOID
+DetectKeyboardController(PCONFIGURATION_COMPONENT_DATA BusKey)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
+    PCONFIGURATION_COMPONENT_DATA ControllerKey;
+    ULONG Size;
+
+    /* Set 'Configuration Data' value */
+    Size = sizeof(CM_PARTIAL_RESOURCE_LIST) +
+           2 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+    PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+    if (PartialResourceList == NULL)
+    {
+        ERR("Failed to allocate resource descriptor\n");
+        return;
+    }
+
+    /* Initialize resource descriptor */
+    memset(PartialResourceList, 0, Size);
+    PartialResourceList->Version = 1;
+    PartialResourceList->Revision = 1;
+    PartialResourceList->Count = 3;
+
+    /* Set Interrupt */
+    PartialDescriptor = &PartialResourceList->PartialDescriptors[0];
+    PartialDescriptor->Type = CmResourceTypeInterrupt;
+    PartialDescriptor->ShareDisposition = CmResourceShareUndetermined;
+    PartialDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+    PartialDescriptor->u.Interrupt.Level = 1;
+    PartialDescriptor->u.Interrupt.Vector = 1;
+    PartialDescriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
+
+    /* Set IO Port 0x60 */
+    PartialDescriptor = &PartialResourceList->PartialDescriptors[1];
+    PartialDescriptor->Type = CmResourceTypePort;
+    PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
+    PartialDescriptor->u.Port.Start.LowPart = 0x60;
+    PartialDescriptor->u.Port.Start.HighPart = 0x0;
+    PartialDescriptor->u.Port.Length = 1;
+
+    /* Set IO Port 0x64 */
+    PartialDescriptor = &PartialResourceList->PartialDescriptors[2];
+    PartialDescriptor->Type = CmResourceTypePort;
+    PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
+    PartialDescriptor->Flags = CM_RESOURCE_PORT_IO;
+    PartialDescriptor->u.Port.Start.LowPart = 0x64;
+    PartialDescriptor->u.Port.Start.HighPart = 0x0;
+    PartialDescriptor->u.Port.Length = 1;
+
+    /* Create controller key */
+    FldrCreateComponentKey(BusKey,
+                           ControllerClass,
+                           KeyboardController,
+                           Input | ConsoleIn,
+                           0x0,
+                           0xFFFFFFFF,
+                           NULL,
+                           PartialResourceList,
+                           Size,
+                           &ControllerKey);
+    TRACE("Created key: KeyboardController\\0\n");
+
+    DetectKeyboardPeripheral(ControllerKey);
+}
+
+static
+VOID
+PS2ControllerWait(VOID)
+{
+    ULONG Timeout;
+    UCHAR Status;
+
+    for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++)
+    {
+        Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+        if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0)
+            return;
+
+        /* Sleep for one millisecond */
+        StallExecutionProcessor(1000);
+    }
+}
+
+static
+BOOLEAN
+DetectPS2AuxPort(VOID)
+{
+#if 1
+    /* Current detection is too unreliable. Just do as if
+     * the PS/2 aux port is always present
+     */
+    return TRUE;
+#else
+    ULONG Loops;
+    UCHAR Status;
+
+    /* Put the value 0x5A in the output buffer using the
+     * "WriteAuxiliary Device Output Buffer" command (0xD3).
+     * Poll the Status Register for a while to see if the value really turns up
+     * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set
+     * to 1 in the Status Register, we assume this controller has an
+     *  Auxiliary Port (a.k.a. Mouse Port).
+     */
+    PS2ControllerWait();
+    WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
+                     CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER);
+    PS2ControllerWait();
+
+    /* 0x5A is a random dummy value */
+    WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA,
+                     0x5A);
+
+    for (Loops = 0; Loops < 10; Loops++)
+    {
+        StallExecutionProcessor(10000);
+        Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+        if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
+            break;
+    }
+
+    READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
+
+    return (Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL);
+#endif
+}
+
+static
+BOOLEAN
+DetectPS2AuxDevice(VOID)
+{
+    UCHAR Scancode;
+    UCHAR Status;
+    ULONG Loops;
+    BOOLEAN Result = TRUE;
+
+    PS2ControllerWait();
+    WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL,
+                     CONTROLLER_COMMAND_WRITE_MOUSE);
+    PS2ControllerWait();
+
+    /* Identify device */
+    WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, 0xF2);
+
+    /* Wait for reply */
+    for (Loops = 0; Loops < 100; Loops++)
+    {
+        StallExecutionProcessor(10000);
+        Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+        if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0)
+            break;
+    }
+
+    Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+    if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
+        Result = FALSE;
+
+    Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
+    if (Scancode != 0xFA)
+        Result = FALSE;
+
+    StallExecutionProcessor(10000);
+
+    Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS);
+    if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0)
+        Result = FALSE;
+
+    Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA);
+    if (Scancode != 0x00)
+        Result = FALSE;
+
+    return Result;
+}
+
+// FIXME: Missing: DetectPS2Peripheral!! (for corresponding 'PointerPeripheral')
+
+static
+VOID
+DetectPS2Mouse(PCONFIGURATION_COMPONENT_DATA BusKey)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCONFIGURATION_COMPONENT_DATA ControllerKey;
+    PCONFIGURATION_COMPONENT_DATA PeripheralKey;
+    ULONG Size;
+
+    if (DetectPS2AuxPort())
+    {
+        TRACE("Detected PS2 port\n");
+
+        PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST), TAG_HW_RESOURCE_LIST);
+        if (PartialResourceList == NULL)
+        {
+            ERR("Failed to allocate resource descriptor\n");
+            return;
+        }
+        memset(PartialResourceList, 0, sizeof(CM_PARTIAL_RESOURCE_LIST));
+
+        /* Initialize resource descriptor */
+        PartialResourceList->Version = 1;
+        PartialResourceList->Revision = 1;
+        PartialResourceList->Count = 1;
+
+        /* Set Interrupt */
+        PartialResourceList->PartialDescriptors[0].Type = CmResourceTypeInterrupt;
+        PartialResourceList->PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined;
+        PartialResourceList->PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED;
+        PartialResourceList->PartialDescriptors[0].u.Interrupt.Level = 12;
+        PartialResourceList->PartialDescriptors[0].u.Interrupt.Vector = 12;
+        PartialResourceList->PartialDescriptors[0].u.Interrupt.Affinity = 0xFFFFFFFF;
+
+        /* Create controller key */
+        FldrCreateComponentKey(BusKey,
+                               ControllerClass,
+                               PointerController,
+                               Input,
+                               0x0,
+                               0xFFFFFFFF,
+                               NULL,
+                               PartialResourceList,
+                               sizeof(CM_PARTIAL_RESOURCE_LIST),
+                               &ControllerKey);
+        TRACE("Created key: PointerController\\0\n");
+
+        if (DetectPS2AuxDevice())
+        {
+            TRACE("Detected PS2 mouse\n");
+
+            /* Initialize resource descriptor */
+            Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
+                   sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+            PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+            if (PartialResourceList == NULL)
+            {
+                ERR("Failed to allocate resource descriptor\n");
+                return;
+            }
+            memset(PartialResourceList, 0, Size);
+            PartialResourceList->Version = 1;
+            PartialResourceList->Revision = 1;
+            PartialResourceList->Count = 0;
+
+            /* Create peripheral key */
+            FldrCreateComponentKey(ControllerKey,
+                                   ControllerClass,
+                                   PointerPeripheral,
+                                   Input,
+                                   0x0,
+                                   0xFFFFFFFF,
+                                   "MICROSOFT PS2 MOUSE",
+                                   PartialResourceList,
+                                   Size,
+                                   &PeripheralKey);
+            TRACE("Created key: PointerPeripheral\\0\n");
+        }
+    }
+}
+
+static VOID
+DetectDisplayController(PCONFIGURATION_COMPONENT_DATA BusKey)
+{
+    CHAR Buffer[80];
+    PCONFIGURATION_COMPONENT_DATA ControllerKey;
+    USHORT VesaVersion;
+
+    /* FIXME: Set 'ComponentInformation' value */
+
+    VesaVersion = BiosIsVesaSupported();
+    if (VesaVersion != 0)
+    {
+        TRACE("VESA version %c.%c\n",
+              (VesaVersion >> 8) + '0',
+              (VesaVersion & 0xFF) + '0');
+    }
+    else
+    {
+        TRACE("VESA not supported\n");
+    }
+
+    if (VesaVersion >= 0x0200)
+    {
+        strcpy(Buffer, "VBE Display");
+    }
+    else
+    {
+        strcpy(Buffer, "VGA Display");
+    }
+
+    FldrCreateComponentKey(BusKey,
+                           ControllerClass,
+                           DisplayController,
+                           0x0,
+                           0x0,
+                           0xFFFFFFFF,
+                           Buffer,
+                           NULL,
+                           0,
+                           &ControllerKey);
+    TRACE("Created key: DisplayController\\0\n");
+
+    /* FIXME: Add display peripheral (monitor) data */
+    if (VesaVersion != 0)
+    {
+        if (BiosIsVesaDdcSupported())
+        {
+            TRACE("VESA/DDC supported!\n");
+            if (BiosVesaReadEdid())
+            {
+                TRACE("EDID data read successfully!\n");
+
+            }
+        }
+    }
+}
+
+static
+VOID
+DetectIsaBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber)
+{
+    PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
+    PCONFIGURATION_COMPONENT_DATA BusKey;
+    ULONG Size;
+
+    /* Set 'Configuration Data' value */
+    Size = sizeof(CM_PARTIAL_RESOURCE_LIST) -
+           sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+    PartialResourceList = FrLdrHeapAlloc(Size, TAG_HW_RESOURCE_LIST);
+    if (PartialResourceList == NULL)
+    {
+        ERR("Failed to allocate resource descriptor\n");
+        return;
+    }
+
+    /* Initialize resource descriptor */
+    memset(PartialResourceList, 0, Size);
+    PartialResourceList->Version = 1;
+    PartialResourceList->Revision = 1;
+    PartialResourceList->Count = 0;
+
+    /* Create new bus key */
+    FldrCreateComponentKey(SystemKey,
+                           AdapterClass,
+                           MultiFunctionAdapter,
+                           0x0,
+                           0x0,
+                           0xFFFFFFFF,
+                           "ISA",
+                           PartialResourceList,
+                           Size,
+                           &BusKey);
+
+    /* Increment bus number */
+    (*BusNumber)++;
+
+    /* Detect ISA/BIOS devices */
+    DetectBiosDisks(SystemKey, BusKey);
+    DetectSerialPorts(BusKey);
+    DetectParallelPorts(BusKey);
+    DetectKeyboardController(BusKey);
+    DetectPS2Mouse(BusKey);
+    DetectDisplayController(BusKey);
+
+    /* FIXME: Detect more ISA devices */
+}
+
+PCONFIGURATION_COMPONENT_DATA
+PcHwDetect(VOID)
+{
+    PCONFIGURATION_COMPONENT_DATA SystemKey;
+    ULONG BusNumber = 0;
+
+    TRACE("DetectHardware()\n");
+
+    /* Create the 'System' key */
+    FldrCreateSystemKey(&SystemKey);
+    // TODO: Discover and set the machine type as the Component->Identifier
+
+    GetHarddiskConfigurationData = PcGetHarddiskConfigurationData;
+
+    /* Detect buses */
+    DetectPciBios(SystemKey, &BusNumber);
+    DetectApmBios(SystemKey, &BusNumber);
+    DetectPnpBios(SystemKey, &BusNumber);
+    DetectIsaBios(SystemKey, &BusNumber); // TODO: Detect first EISA or MCA, before ISA
+    DetectAcpiBios(SystemKey, &BusNumber);
+
+    // TODO: Collect the ROM blocks from 0xC0000 to 0xF0000 and append their
+    // CM_ROM_BLOCK data into the 'System' key's configuration data.
+
+    TRACE("DetectHardware() Done\n");
+    return SystemKey;
+}
+
+VOID
+PcHwIdle(VOID)
+{
+    REGS Regs;
+
+    /* Select APM 1.0+ function */
+    Regs.b.ah = 0x53;
+
+    /* Function 05h: CPU idle */
+    Regs.b.al = 0x05;
+
+    /* Call INT 15h */
+    Int386(0x15, &Regs, &Regs);
+
+    /* Check if successfull (CF set on error) */
+    if (INT386_SUCCESS(Regs))
+        return;
+
+    /*
+     * No futher processing here.
+     * Optionally implement HLT instruction handling.
+     */
+}
+
+
+/******************************************************************************/
 
 VOID
 PcMachInit(const char *CmdLine)
@@ -48,15 +1386,16 @@ PcMachInit(const char *CmdLine)
     MachVtbl.InitializeBootDevices = PcInitializeBootDevices;
     MachVtbl.HwDetect = PcHwDetect;
     MachVtbl.HwIdle = PcHwIdle;
+
+    // DiskGetPartitionEntry = DiskGetMbrPartitionEntry; // Default
 }
 
 VOID
 PcPrepareForReactOS(IN BOOLEAN Setup)
 {
-    //
-    // On PC, prepare video and turn off the floppy motor
-    //
+    /* On PC, prepare video and turn off the floppy motor */
     PcVideoPrepareForReactOS(Setup);
     DiskStopFloppyMotor();
 }
+
 /* EOF */