/* Checks if we have a device supported by our driver and initialize
 * our driver/card specific information.
 * In particular we obtain VM monitors configuration and configure related structures.
 */
static VP_STATUS
VBoxDrvFindAdapter(IN PVOID HwDeviceExtension, IN PVOID HwContext, IN PWSTR ArgumentString,
                   IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo, OUT PUCHAR Again)
{
    RT_NOREF(HwContext,  ArgumentString, Again);
    PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT) HwDeviceExtension;
    VP_STATUS rc;
    USHORT DispiId;
    ULONG cbVRAM = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
    PHYSICAL_ADDRESS phVRAM = {0};
    ULONG ulApertureSize = 0;

    PAGED_CODE();
    LOGF_ENTER();

    /* Init video port api */
    VBoxSetupVideoPortAPI(pExt, ConfigInfo);

    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
    DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);

    if (DispiId != VBE_DISPI_ID2)
    {
        WARN(("VBE card not found, returning ERROR_DEV_NOT_EXIST"));
        return ERROR_DEV_NOT_EXIST;
    }
    LOG(("found the VBE card"));

    /*
     * Query the adapter's memory size. It's a bit of a hack, we just read
     * an ULONG from the data port without setting an index before.
     */
    cbVRAM = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);

    /* Write hw information to registry, so that it's visible in windows property dialog */
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.ChipType",
                                        g_wszVBoxChipType, sizeof(g_wszVBoxChipType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.DacType",
                                        g_wszVBoxDACType, sizeof(g_wszVBoxDACType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.MemorySize",
                                        &cbVRAM, sizeof(ULONG));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.AdapterString",
                                        g_wszVBoxAdapterString, sizeof(g_wszVBoxAdapterString));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.BiosString",
                                        g_wszVBoxBiosString, sizeof(g_wszVBoxBiosString));
    VBOXMP_WARN_VPS(rc);

    /* Call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up
     * and to get LFB aperture data.
     */
    {
        VIDEO_ACCESS_RANGE tmpRanges[4];
        ULONG slot = 0;

        VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));

        if (VBoxQueryWinVersion(NULL) == WINVERSION_NT4)
        {
            /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
             * and needs PCI ids for a successful VideoPortGetAccessRanges call.
             */
            ULONG vendorId = 0x80EE;
            ULONG deviceId = 0xBEEF;
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges,
                                          &vendorId, &deviceId, &slot);
        }
        else
        {
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges, NULL, NULL, &slot);
        }
        VBOXMP_WARN_VPS(rc);
        if (rc != NO_ERROR) {
            return rc;
        }

        /* The first non-IO range is the framebuffer. We require that information. */
        for (int iRange = 0; iRange < RT_ELEMENTS(tmpRanges); ++iRange)
        {
            if (!tmpRanges[iRange].RangeInIoSpace)
            {
                phVRAM = tmpRanges[iRange].RangeStart;
                ulApertureSize = tmpRanges[iRange].RangeLength;
                break;
            }
        }
    }

    /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
    rc = VbglR0InitClient();
    VBOXMP_WARN_VPS(rc);

    /* Preinitialize the primary extension. */
    pExt->pNext                   = NULL;
    pExt->pPrimary                = pExt;
    pExt->iDevice                 = 0;
    pExt->ulFrameBufferOffset     = 0;
    pExt->ulFrameBufferSize       = 0;
    pExt->u.primary.ulVbvaEnabled = 0;
    VideoPortZeroMemory(&pExt->areaDisplay, sizeof(HGSMIAREA));

    /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
     * code will be ifdef'ed and later removed.
     * The host will however support both old and new interface to keep compatibility
     * with old guest additions.
     */
    VBoxSetupDisplaysHGSMI(&pExt->u.primary.commonInfo, phVRAM, ulApertureSize, cbVRAM, 0);

    /* Check if the chip restricts horizontal resolution or not.
     * Must be done after VBoxSetupDisplaysHGSMI, because it initializes the common structure.
     */
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
    DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);

    if (DispiId == VBE_DISPI_ID_ANYX)
        VBoxCommonFromDeviceExt(pExt)->fAnyX = TRUE;
    else
        VBoxCommonFromDeviceExt(pExt)->fAnyX = FALSE;

    if (pExt->u.primary.commonInfo.bHGSMI)
    {
        LOGREL(("using HGSMI"));
        VBoxCreateDisplays(pExt, ConfigInfo);
    }

    /** @todo pretend success to make the driver work. */
    rc = NO_ERROR;

    LOGF_LEAVE();
    VBOXMP_WARN_VPS(rc);
    return rc;
}
Ejemplo n.º 2
0
VP_STATUS
DGXFindAdapter(
    PVOID HwDeviceExtension,
    PVOID HwContext,
    PWSTR ArgumentString,
    PVIDEO_PORT_CONFIG_INFO ConfigInfo,
    PUCHAR Again
    )

/*++

Routine Description:

    This routine is called to determine if the adapter for this driver
    is present in the system.
    If it is present, the function fills out some information describing
    the adapter.

Arguments:

    HwDeviceExtension - Supplies the miniport driver's adapter storage. This
        storage is initialized to zero before this call.

    HwContext - Supplies the context value which was passed to
        VideoPortInitialize().

    ArgumentString - Suuplies a NULL terminated ASCII string. This string
        originates from the user.

    ConfigInfo - Returns the configuration information structure which is
        filled by the miniport driver. This structure is initialized with
        any knwon configuration information (such as SystemIoBusNumber) by
        the port driver. Where possible, drivers should have one set of
        defaults which do not require any supplied configuration information.

    Again - Indicates if the miniport driver wants the port driver to call
        its VIDEO_HW_FIND_ADAPTER function again with a new device extension
        and the same config info. This is used by the miniport drivers which
        can search for several adapters on a bus.

Return Value:

    This routine must return:

    NO_ERROR - Indicates a host adapter was found and the
        configuration information was successfully determined.

    ERROR_INVALID_PARAMETER - Indicates an adapter was found but there was an
        error obtaining the configuration information. If possible an error
        should be logged.

    ERROR_DEV_NOT_EXIST - Indicates no host adapter was found for the
        supplied configuration information.

--*/

{

#define NUM_ACCESS_RANGES  5

    PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
    PVOID *pVirtAddr;
    ULONG i;
    USHORT temp;
    PUSHORT port;
    VP_STATUS status;
    PWSTR pwszChip= NULL;    // chip name
    ULONG cbChip= 0;         // length of chip name
    PWSTR pwszDac= NULL;     // DAC name
    ULONG cbDac= 0;          // length of DAC name
    ULONG cbMemSize;         // size of video memory

    VIDEO_ACCESS_RANGE accessRange[NUM_ACCESS_RANGES] = {
        {0X00000061, 0x00000000, 0x00000001, 1, 1, 0},   // DGX I
        {0X00006CA8, 0x00000000, 0x00000001, 1, 1, 0},   // DGX I
        {0X00006C80, 0x00000000, 0x00000009, 1, 1, 0},   // DGX I & II
        {0X00000CAC, 0x00000000, 0x00000004, 1, 1, 0},   // front panel
        {0x20000000, 0x00000000, 0x00400000, 0, 1, 0}    // Frame buf & dac
    };

    //
    // Make sure the size of the structure is at least as large as what we
    // are expecting (check version of the config info structure).
    //

    if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) {

        return ERROR_INVALID_PARAMETER;

    }

    //
    // Check to see if there is a hardware resource conflict.
    //

    status = VideoPortVerifyAccessRanges(HwDeviceExtension,
                                         NUM_ACCESS_RANGES,
                                         accessRange);

    if (status != NO_ERROR) {

        return status;

    }

    //
    // Clear out the Emulator entries and the state size since this driver
    // does not support them.
    //

    ConfigInfo->NumEmulatorAccessEntries = 0;
    ConfigInfo->EmulatorAccessEntries = NULL;
    ConfigInfo->EmulatorAccessEntriesContext = 0;

    ConfigInfo->HardwareStateSize = 0;

    ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x00000000;
    ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000;
    ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00000000;

    //
    // Frame buffer information
    //

    hwDeviceExtension->FrameLength = DELL_DGX_LEN;
    hwDeviceExtension->PhysicalFrameAddress.HighPart = 0;
    hwDeviceExtension->PhysicalFrameAddress.LowPart = DELL_DGX_BASE;


    //
    // Map all of our ranges into system virtual address space.
    // IMPORTANT !!!
    // This is dependant on the order of the virtual addresses in the
    // HwDeviceExtensionto be the same as the order of the entries in the
    // access range structure.
    //

    pVirtAddr = &hwDeviceExtension->DGX1Misc;

    for (i=0 ; i <NUM_ACCESS_RANGES ; i++ ) {

        if ( (*pVirtAddr = VideoPortGetDeviceBase(hwDeviceExtension,
                               accessRange[i].RangeStart,
                               accessRange[i].RangeLength,
                               accessRange[i].RangeInIoSpace)) == NULL) {

            return ERROR_INVALID_PARAMETER;

        }

        pVirtAddr++;
    }

    //
    // Are we really on a Dell DGX machine? If so which one?
    //

    hwDeviceExtension->ModelNumber = 0;

    port = (PUSHORT) hwDeviceExtension->DGXControlPorts;
    temp = VideoPortReadPortUshort(port++);

    if (temp == DELL_DGX_ID_LOW) {

        temp = VideoPortReadPortUshort(port);

        if (temp == DELL_DGX_1_ID_HIGH) {

            hwDeviceExtension->ModelNumber = 1;
            pwszChip= CHIPNAME1;
            cbChip= sizeof(CHIPNAME1);

        }

        if (temp == DELL_DGX_2_ID_HIGH) {

            hwDeviceExtension->ModelNumber = 2;
            pwszChip= CHIPNAME2;
            cbChip= sizeof(CHIPNAME2);

        }
    }

    if (hwDeviceExtension->ModelNumber == 0) {

        //
        // If we did not find the chip, free all the resources we allocated.
        //

        pVirtAddr = &hwDeviceExtension->DGX1Misc;

        for (i=0 ; i <NUM_ACCESS_RANGES ; i++) {

            VideoPortFreeDeviceBase(hwDeviceExtension, *pVirtAddr);
            pVirtAddr++;
        }

        return ERROR_DEV_NOT_EXIST;
    }

    //
    // Initialize the current mode number.
    //

    hwDeviceExtension->CurrentModeNumber = 0;

    //
    // Setup All the valid modes.
    //

    hwDeviceExtension->NumValidModes = 0;

    for (i=0; i < NumDGXModes; i++) {

        DGXModes[i].modeInformation.ModeIndex = i;

        DGXModes[i].bValid = TRUE;
        hwDeviceExtension->NumValidModes++;

    }

    //
    // Indicate we do not wish to be called over
    //

    *Again = 0;

    //
    // Init Front panel Display
    //

    DevSetPanel(HwDeviceExtension, PANEL_MESSAGE);

    //
    // Set hardware information strings in registry
    //

    VideoPortSetRegistryParameters(HwDeviceExtension,
                                   L"HardwareInformation.ChipType",
                                   pwszChip,
                                   cbChip );

    pwszDac= DELL_DGX_DACNAME;
    cbDac= sizeof( DELL_DGX_DACNAME );
    VideoPortSetRegistryParameters(HwDeviceExtension,
                                   L"HardwareInformation.DacType",
                                   pwszDac,
                                   cbDac );

    cbMemSize= DELL_DGX_LEN;
    VideoPortSetRegistryParameters(HwDeviceExtension,
                                   L"HardwareInformation.MemorySize",
                                   &cbMemSize,
                                   sizeof(ULONG) );
    //
    // Indicate a successful completion status.
    //

    return NO_ERROR;

} // end DGXFindAdapter()
Ejemplo n.º 3
0
VP_STATUS
NTAPI
VmxFindAdapter(IN PVOID HwDeviceExtension,
               IN PVOID HwContext,
               IN PWSTR ArgumentString,
               IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
               OUT PUCHAR Again)
{
    VP_STATUS Status;
    PHW_DEVICE_EXTENSION DeviceExtension = HwDeviceExtension;
    DPRINT1("VMX searching for adapter\n");

    /* Zero out the fields */
    VideoPortZeroMemory(DeviceExtension, sizeof(HW_DEVICE_EXTENSION));

    /* Validate the Config Info */
    if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO))
    {
        /* Incorrect OS version? */
        DPRINT1("Invalid configuration info\n");
        return ERROR_INVALID_PARAMETER;
    }

    /* Initialize the device extension and find the adapter */
    Status = VmxInitDevice(DeviceExtension);
    DPRINT1("Init status: %lx\n", Status);
    if (Status != NO_ERROR) return ERROR_DEV_NOT_EXIST;

    /* Save this adapter extension */
    VmxDeviceExtensionArray[0] = DeviceExtension;

    /* Create the sync event */
    VideoPortCreateEvent(DeviceExtension,
                         NOTIFICATION_EVENT,
                         NULL,
                         &DeviceExtension->SyncEvent);

    /* Check for multi-monitor configuration */
    if (VmxIsMultiMon(DeviceExtension))
    {
        /* Let's not go so far */
        UNIMPLEMENTED;
        while (TRUE);
    }

    /* Zero the frame buffer */
    VideoPortZeroMemory((PVOID)DeviceExtension->FrameBuffer.LowPart,
                        DeviceExtension->VramSize.LowPart);

    /* Initialize the video modes */
    VmxInitModes(DeviceExtension);

    /* Setup registry keys */
    VideoPortSetRegistryParameters(DeviceExtension,
                                   L"HardwareInformation.ChipType",
                                   AdapterString,
                                   sizeof(AdapterString));
    VideoPortSetRegistryParameters(DeviceExtension,
                                   L"HardwareInformation.DacType",
                                   AdapterString,
                                   sizeof(AdapterString));
    VideoPortSetRegistryParameters(DeviceExtension,
                                   L"HardwareInformation.MemorySize",
                                   &DeviceExtension->VramSize.LowPart,
                                   sizeof(ULONG));
    VideoPortSetRegistryParameters(DeviceExtension,
                                   L"HardwareInformation.AdapterString",
                                   AdapterString,
                                   sizeof(AdapterString));
    VideoPortSetRegistryParameters(DeviceExtension,
                                   L"HardwareInformation.BiosString",
                                   AdapterString,
                                   sizeof(AdapterString));

    /* No VDM support */
    ConfigInfo->NumEmulatorAccessEntries = 0;
    ConfigInfo->EmulatorAccessEntries = 0;
    ConfigInfo->EmulatorAccessEntriesContext = 0;
    ConfigInfo->HardwareStateSize = 0;
    ConfigInfo->VdmPhysicalVideoMemoryAddress.QuadPart = 0;
    ConfigInfo->VdmPhysicalVideoMemoryLength = 0;

    /* Write that this is Windows XP or higher */
    VmxWriteUlong(DeviceExtension, SVGA_REG_GUEST_ID, 0x5000 | 0x08);
    return NO_ERROR;
}
Ejemplo n.º 4
0
VP_STATUS VBoxMPCmnRegSetDword(IN VBOXMPCMNREGISTRY Reg, PWSTR pName, uint32_t Val)
{
    return VideoPortSetRegistryParameters(Reg, pName, &Val, sizeof(Val));
}
Ejemplo n.º 5
0
/* Checks if we have a device supported by our driver and initialize
 * our driver/card specific information.
 * In particular we obtain VM monitors configuration and configure related structures.
 */
static VP_STATUS
VBoxDrvFindAdapter(IN PVOID HwDeviceExtension, IN PVOID HwContext, IN PWSTR ArgumentString,
                   IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo, OUT PUCHAR Again)
{
    PVBOXMP_DEVEXT pExt = (PVBOXMP_DEVEXT) HwDeviceExtension;
    VP_STATUS rc;
    USHORT DispiId;
    ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;

    PAGED_CODE();
    LOGF_ENTER();

    /* Init video port api */
    VBoxSetupVideoPortAPI(pExt, ConfigInfo);

    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
    VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
    DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);

    if (DispiId != VBE_DISPI_ID2)
    {
        WARN(("VBE card not found, returning ERROR_DEV_NOT_EXIST"));
        return ERROR_DEV_NOT_EXIST;
    }
    LOG(("found the VBE card"));

    /*
     * Query the adapter's memory size. It's a bit of a hack, we just read
     * an ULONG from the data port without setting an index before.
     */
    AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);

    /* Write hw information to registry, so that it's visible in windows property dialog */
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.ChipType",
                                        VBoxChipType, sizeof(VBoxChipType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.DacType",
                                        VBoxDACType, sizeof(VBoxDACType));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.MemorySize",
                                        &AdapterMemorySize, sizeof(ULONG));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.AdapterString",
                                        VBoxAdapterString, sizeof(VBoxAdapterString));
    VBOXMP_WARN_VPS(rc);
    rc = VideoPortSetRegistryParameters(pExt, L"HardwareInformation.BiosString",
                                        VBoxBiosString, sizeof(VBoxBiosString));
    VBOXMP_WARN_VPS(rc);

    /* Call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
    {
        VIDEO_ACCESS_RANGE tmpRanges[4];
        ULONG slot = 0;

        VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));

        if (VBoxQueryWinVersion() == WINNT4)
        {
            /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
             * and needs PCI ids for a successful VideoPortGetAccessRanges call.
             */
            ULONG vendorId = 0x80EE;
            ULONG deviceId = 0xBEEF;
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges,
                                          &vendorId, &deviceId, &slot);
        }
        else
        {
            rc = VideoPortGetAccessRanges(pExt, 0, NULL, RT_ELEMENTS(tmpRanges), tmpRanges, NULL, NULL, &slot);
        }
        VBOXMP_WARN_VPS(rc);
    }

    /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
    rc = VbglInit();
    VBOXMP_WARN_VPS(rc);

    /* Preinitialize the primary extension. */
    pExt->pNext                   = NULL;
    pExt->pPrimary                = pExt;
    pExt->iDevice                 = 0;
    pExt->ulFrameBufferOffset     = 0;
    pExt->ulFrameBufferSize       = 0;
    pExt->u.primary.ulVbvaEnabled = 0;
    VideoPortZeroMemory(&pExt->areaDisplay, sizeof(HGSMIAREA));

    /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
     * code will be ifdef'ed and later removed.
     * The host will however support both old and new interface to keep compatibility
     * with old guest additions.
     */
    VBoxSetupDisplaysHGSMI(&pExt->u.primary.commonInfo, AdapterMemorySize, 0);

    if (pExt->u.primary.commonInfo.bHGSMI)
    {
        LOGREL(("using HGSMI"));
        VBoxCreateDisplays(pExt, ConfigInfo);
    }

    /** @todo pretend success to make the driver work. */
    rc = NO_ERROR;

    LOGF_LEAVE();
    VBOXMP_WARN_VPS(rc);
    return rc;
}
Ejemplo n.º 6
0
/* Determine whether the supported adapter is present. Note that this 
 * function is not allowed to change the state of the adapter!
 */
VP_STATUS HwVidFindAdapter( PVOID HwDevExt, PVOID HwContext, PWSTR ArgumentString,
                            PVIDEO_PORT_CONFIG_INFO ConfigInfo, PUCHAR Again )
{
    PHW_DEV_EXT             pExt = HwDevExt;
    PVOID                   *pVirtAddr;
    ULONG                   i;
    INT                     chip_id;
    VP_STATUS               status;
    ULONG                   cbVramSize;
    PWSTR                   pwszDesc;
    ULONG                   cbDesc;
#ifdef USE_GETACCESSRANGES
    VIDEO_ACCESS_RANGE      pciAccessRanges[NUM_PCI_RANGES];
    USHORT                  usVendorId = BOXV_PCI_VEN;
    USHORT                  usDeviceId = BOXV_PCI_DEV;
    ULONG                   ulSlot = 0;
#endif

    //@todo: The framebuffer address should not be hardcoded for non-PCI access
#define NUM_ACCESS_RANGES   2
    VIDEO_ACCESS_RANGE accessRanges[NUM_ACCESS_RANGES] = {
        /* StartLo     StartHi     Len       IO Vis Shr */
        { 0x000001CE, 0x00000000, 0x00000002, 1, 1, 0 },    /* I/O ports */
        { 0xE0000000, 0x00000000, 0x00400000, 0, 1, 0 }     /* Framebuffer */
    };

    VideoDebugPrint( (1, "videomp: HwVidFindAdapter\n") );

    /* Fail if the passed structure is smaller than the NT 3.1 version. */
    if( ConfigInfo->Length < offsetof( VIDEO_PORT_CONFIG_INFO, DmaChannel ) ) {
        return( ERROR_INVALID_PARAMETER );
    }

    /* Sadly, VideoPortGetAccessRanges was not present in NT 3.1. There is no
     * reasonably simple way to dynamically import port driver routines on 
     * newer versions, so we'll just do without. 
     */
#ifdef USE_GETACCESSRANGES
    /* If PCI is supported, query the bus for resource mappings. */
    if( ConfigInfo->AdapterInterfaceType == PCIBus ) {
        /* Ask for bus specific access ranges. */
        VideoPortZeroMemory( pciAccessRanges, sizeof( pciAccessRanges ) );
        status = VideoPortGetAccessRanges( HwDevExt, 0, NULL,
                                           NUM_PCI_RANGES, pciAccessRanges,
                                           &usVendorId, &usDeviceId, &ulSlot );
        if( status == NO_ERROR ) {
            VideoDebugPrint( (1, "videomp: Found adapter in PCI slot %d\n", ulSlot) );
            pExt->ulSlot = ulSlot;
            /* The framebuffer is in the first slot of the PCI ranges. Copy
             * the data into the access ranges we're going to request.
             */
            accessRanges[1].RangeStart  = pciAccessRanges[0].RangeStart;
            accessRanges[1].RangeLength = pciAccessRanges[0].RangeLength;
        } else {
            /* On NT versions without PCI support, we won't even attempt this.
             * So if we tried to query the PCI device and failed to find it, 
             * it really isn't there and we have to give up. 
             */
            VideoDebugPrint( (1, "videomp: PCI adapter not found\n") );
            return( ERROR_DEV_NOT_EXIST );
        }
    }
#endif

    /* Some versions of vga.sys trap accesses to ports 0x1CE-0x1CF used on
     * old ATI cards. On Windows 2000 and later we can report legacy
     * resources to resolve this conflict. On NT 4 and older, we use a hack
     * and claim other, non-conflicting ports.
     */
    if( PortVersion < VP_VER_W2K )
        accessRanges[0].RangeStart = RtlConvertUlongToLargeInteger( 0x1CC );
 
    /* Check for a conflict in case someone else claimed our resources. */
    status = VideoPortVerifyAccessRanges( HwDevExt, NUM_ACCESS_RANGES, accessRanges );
    if( status != NO_ERROR ) {
        return( status );
    }

    /* Indicate no emulator support. */
    ConfigInfo->NumEmulatorAccessEntries     = 0;
    ConfigInfo->EmulatorAccessEntries        = NULL;
    ConfigInfo->EmulatorAccessEntriesContext = 0;

    ConfigInfo->HardwareStateSize = 0;

    ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart  = 0;
    ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0;
    ConfigInfo->VdmPhysicalVideoMemoryLength           = 0;

    /* Describe the framebuffer. We claimed the range already. */
    pExt->PhysicalFrameAddress = accessRanges[1].RangeStart;


    /*
     * Map all memory and I/O ranges into system virtual address space.
     * NB: The virtual addresses in the HwDevExt must match the number
     * and type of AccessRange entries.
     */
    pVirtAddr = &pExt->IoPorts;

    /* Attempt to claim and map the memory and I/O address ranges. */
    for( i = 0; i < NUM_ACCESS_RANGES; ++i, ++pVirtAddr ) {
        *pVirtAddr = VideoPortGetDeviceBase( pExt, 
                                             accessRanges[i].RangeStart,
                                             accessRanges[i].RangeLength,
                                             accessRanges[i].RangeInIoSpace );
        if( *pVirtAddr == NULL ) {
            return( ERROR_INVALID_PARAMETER );
        }
    }

    /* Verify that supported hardware is present. */
    chip_id = BOXV_detect( pExt, &pExt->FramebufLen );
    if( !chip_id ) {
        /* If supported hardware was not found, free allocated resources. */
        pVirtAddr = &pExt->IoPorts;
        for( i = 0; i < NUM_ACCESS_RANGES; ++i, ++pVirtAddr )
            VideoPortFreeDeviceBase( pExt, *pVirtAddr );

        return( ERROR_DEV_NOT_EXIST );
    }

    /* We need to access VGA and other I/O ports. Fortunately the HAL doesn't 
     * care at all how the I/O ports are or aren't mapped on x86 platforms.
     */
    pExt->IOAddrVGA = NULL;

    /* Only support one attached monitor. */
    pExt->NumMonitors = 1;

    /* Set up mode information. */
    pExt->CurrentModeNumber = 0;
    pExt->NumValidModes     = 0;

    for( i = 0; i < ulAllModes; ++i ) {
        vmpValidateMode( &VideoModes[i], pExt->FramebufLen );
        if( VideoModes[i].bValid )
            ++pExt->NumValidModes;
    }

    /* Only one adapter supported, no need to call us again. */
    *Again = 0;

    /* Report the hardware names via registry. */

#define TEMP_CHIP_NAME  L"bochs Mk II"
    pwszDesc = TEMP_CHIP_NAME;
    cbDesc   = sizeof( TEMP_CHIP_NAME );

    VideoPortSetRegistryParameters( pExt, L"HardwareInformation.ChipType",
                                    pwszDesc, cbDesc );

#define TEMP_DAC_NAME  L"Integrated DAC"
    pwszDesc = TEMP_DAC_NAME;
    cbDesc   = sizeof( TEMP_DAC_NAME );
    VideoPortSetRegistryParameters( pExt, L"HardwareInformation.DacType",
                                    pwszDesc, cbDesc );

#define TEMP_ADAPTER_NAME  L"VirtualBox/bochs"
    pwszDesc = TEMP_ADAPTER_NAME;
    cbDesc   = sizeof( TEMP_ADAPTER_NAME );
    VideoPortSetRegistryParameters( pExt, L"HardwareInformation.AdapterString",
                                    pwszDesc, cbDesc );

    cbVramSize = pExt->FramebufLen;
    VideoPortSetRegistryParameters( pExt, L"HardwareInformation.MemorySize",
                                    &cbVramSize, sizeof( ULONG ) );
    /* All is well. */
    return( NO_ERROR );
}